feat(angular): allow custom webpack config support for webpack-browse… (#5609)

* feat(angular): allow custom webpack config support for webpack-browser builds

Allow building with a custom webpack config when using webpack-browser builds

* cleanup(angular): have buildApp function determine what builder to use

have buildApp function determine what builder to use keeping run function cleaner

* chore(misc): add IGNORE_MATCHES to CI dep discrepancy check

Add option to ignore packages in the discrepancy check for CI

* cleanup(angular): throw schematic error when webpack config path incorrect

Throw a helpful error when the user supplies an incorrect custom webpack config file path
This commit is contained in:
Colum Ferry 2021-05-18 16:05:17 +01:00 committed by GitHub
parent ff3cc38b0c
commit 0872f01738
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 82 additions and 10 deletions

View File

@ -15,6 +15,7 @@
"@angular-devkit",
"@angular-eslint/",
"@schematics",
"jasmine-marbles"
"jasmine-marbles",
"webpack-merge"
]
}

View File

@ -39,6 +39,7 @@
"@nrwl/jest": "*",
"@nrwl/linter": "*",
"@schematics/angular": "~12.0.0",
"jasmine-marbles": "~0.6.0"
"jasmine-marbles": "~0.6.0",
"webpack-merge": "5.7.3"
}
}

View File

@ -363,6 +363,17 @@
"type": "string"
},
"default": []
},
"customWebpackConfig": {
"description": "Options for additional webpack configurations",
"type": "object",
"properties": {
"path": {
"description": "Path to additional webpack configuration. Paths will be resolved to workspace root.",
"type": "string"
}
},
"additionalProperties": true
}
},
"additionalProperties": false,

View File

@ -5,6 +5,7 @@ import {
createBuilder,
targetFromTargetString,
} from '@angular-devkit/architect';
import { executeBrowserBuilder } from '@angular-devkit/build-angular';
import { JsonObject } from '@angular-devkit/core';
import { from, Observable, of } from 'rxjs';
import {
@ -12,30 +13,61 @@ import {
checkDependentProjectsHaveBeenBuilt,
createTmpTsConfig,
} from '@nrwl/workspace/src/utils/buildable-libs-utils';
import { joinPathFragments } from '@nrwl/devkit';
import { join } from 'path';
import { createProjectGraph } from '@nrwl/workspace/src/core/project-graph';
import { Schema } from '@angular-devkit/build-angular/src/browser/schema';
import { switchMap } from 'rxjs/operators';
import { existsSync } from 'fs';
import { merge } from 'webpack-merge';
import { SchematicsException } from '@angular-devkit/schematics';
type BrowserBuilderSchema = Schema &
JsonObject & {
buildTarget: string;
buildTarget?: string;
customWebpackConfig?: {
path: string;
};
};
function buildApp(
options: BrowserBuilderSchema,
context: BuilderContext
): Promise<BuilderRun> {
): Observable<BuilderOutput> {
const { buildTarget, ...delegateOptions } = options;
// If there is a path to custom webpack config
// Invoke our own support for custom webpack config
if (options.customWebpackConfig && options.customWebpackConfig.path) {
const pathToWebpackConfig = joinPathFragments(
context.workspaceRoot,
options.customWebpackConfig.path
);
if (existsSync(pathToWebpackConfig)) {
return buildAppWithCustomWebpackConfiguration(
options,
context,
pathToWebpackConfig
);
} else {
throw new SchematicsException(
`Custom Webpack Config File Not Found!\nTo use a custom webpack config, please ensure the path to the custom webpack file is correct: \n${pathToWebpackConfig}`
);
}
}
let scheduledBuilder: Promise<BuilderRun>;
if (buildTarget) {
const target = targetFromTargetString(buildTarget);
return context.scheduleTarget(target, delegateOptions, {
scheduledBuilder = context.scheduleTarget(target, delegateOptions, {
target: context.target,
logger: context.logger as any,
});
} else {
return context.scheduleBuilder(
delegateOptions.customWebpackConfig = undefined;
scheduledBuilder = context.scheduleBuilder(
'@angular-devkit/build-angular:browser',
delegateOptions,
{
@ -44,6 +76,23 @@ function buildApp(
}
);
}
return from(scheduledBuilder).pipe(switchMap((x) => x.result));
}
function buildAppWithCustomWebpackConfiguration(
options: BrowserBuilderSchema,
context: BuilderContext,
pathToWebpackConfig: string
) {
const { buildTarget, customWebpackConfig, ...delegateOptions } = options;
return executeBrowserBuilder(delegateOptions, context, {
webpackConfiguration: (baseWebpackConfig) => {
const customWebpackConfiguration = require(pathToWebpackConfig);
return merge(baseWebpackConfig, customWebpackConfiguration);
},
});
}
function run(
@ -67,9 +116,7 @@ function run(
return of(checkDependentProjectsHaveBeenBuilt(context, dependencies)).pipe(
switchMap((result) => {
if (result) {
return from(buildApp(options, context)).pipe(
switchMap((x) => x.result)
);
return buildApp(options, context);
} else {
// just pass on the result
return of({ success: false });

View File

@ -1,12 +1,24 @@
import * as chalk from 'chalk';
import { satisfies } from 'semver';
// Ignore packages that are defined here per package
const IGNORE_MATCHES = {
'*': [],
angular: ['webpack-merge'],
};
export default function getDiscrepancies(
name: string,
projectDependencies: JSON,
devDependencies: JSON
) {
return Object.keys(projectDependencies)
.filter((p) => !p.startsWith('@nrwl/'))
.filter((p) =>
!IGNORE_MATCHES['*'].includes(p) && IGNORE_MATCHES[name]
? !IGNORE_MATCHES[name].includes(p)
: true
)
.filter(
(p) =>
devDependencies[p] &&

View File

@ -62,7 +62,7 @@ const argv = require('yargs')
: [];
const discrepancies = argv.discrepancies
? getDiscrepancies(dependencies, devDependencies)
? getDiscrepancies(project.name, dependencies, devDependencies)
: [];
return { ...project, missing, discrepancies };