Skip to content

Commit

Permalink
chore: update webpack-merge (#907)
Browse files Browse the repository at this point in the history
  • Loading branch information
just-jeb authored Dec 13, 2020
1 parent 3ab248e commit 421d867
Show file tree
Hide file tree
Showing 11 changed files with 99 additions and 36 deletions.
20 changes: 19 additions & 1 deletion MIGRATION.MD
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
# Migration from version 10 to version 11

## No action needed
## Custom webpack builder
1. `mergeStrategies` field in `customWebpackConfig` has been deprecated, use `mergeRules` instead as defined [here](https://github.com/survivejs/webpack-merge#mergewithrules).

In order to make this breaking change as backward compatible as possible, the default value of `mergeRules` is the following:
```ts
{
module: {
rules: {
test: "match",
use: {
loader: "match",
options: "merge",
},
},
},
};
```
This is as close as possible to the [`smart` merge strategy](https://github.com/survivejs/webpack-merge/tree/v4.2.2#smart-merging) that was used before, so ideally if you didn't use `mergeStrategies` then your configuration should work just as it worked before.
Otherwise you'll have to adjust the `mergeRules` in accordance with your needs.

# Migration from version 9 to version 10

Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
"ci": "yarn build:packages && ./scripts/run-ci.sh",
"lerna": "lerna",
"postbuild": "yarn test && yarn run e2e",
"build": "tsc && ts-node merge-schemes.ts",
"test": "jest src",
"e2e": "jest e2e",
"format": "prettier --write \"**/*.{js,ts,html,md}\"",
Expand Down
29 changes: 20 additions & 9 deletions packages/custom-webpack/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ Builder options:
"options": {
"customWebpackConfig": {
"path": "./extra-webpack.config.js",
"mergeStrategies": {
"mergeRules": {
"externals": "replace"
}
},
Expand Down Expand Up @@ -164,7 +164,7 @@ Builder options:
"options": {
"customWebpackConfig": {
"path": "./extra-webpack.config.js",
"mergeStrategies": {
"mergeRules": {
"module.rules": "prepend"
},
"replaceDuplicatePlugins": true
Expand Down Expand Up @@ -263,13 +263,24 @@ The following properties are available:
```
The builder will take care of merging the delta with the existing configuration provided by Angular.
In more complicated cases you'd probably want to [use a function](#custom-webpack-config-function) instead of an object.
- `mergeStrategies`: webpack config merge strategies, can be `append | prepend | replace` per webpack config entry. Defaults to `append`.
- `append`: appends the given entry configuration (in custom webpack config) to the existing Angular CLI webpack configuration.
- `prepend`: prepends the given entry configuration (in custom webpack config) to the existing field configuration (in Angular CLI webpack config). The custom loaders config will be added to the _beginning_ of the existing loaders array.
- `replace`: replaces the given entry configuration entirely. The custom webpack config will replace the Angular CLI webpack config (for this particular entry).
See [webpack-merge](https://github.com/survivejs/webpack-merge) for more info.
- `mergeRules`: webpack config merge rules, as described [here](https://github.com/survivejs/webpack-merge#mergewithrules). Defaults to:
```ts
{
module: {
rules: {
test: "match",
use: {
loader: "match",
options: "merge",
},
},
},
};
```
- `replaceDuplicatePlugins`: Defaults to `false`. If `true`, the plugins in custom webpack config will replace the corresponding plugins in default Angular CLI webpack configuration. If `false`, the [default behavior](#merging-plugins-configuration) will be applied.
**Note that if `true`, this option will override `mergeStrategies` for `plugins` field.**
**Note that if `true`, this option will override `mergeRules` for `plugins` field.**
Webpack configuration can be also written in TypeScript. Given the following example:
Expand Down Expand Up @@ -343,7 +354,7 @@ The function is called with the base config the builder options and the target o
`TargetOptions` follows `target` definition from [this](https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/architect/src/input-schema.json) schema
and can be used to manipulate your build based on the build target.
In this case, `mergeStrategies` and `replaceDuplicatePlugins` options have no effect.
In this case, `mergeRules` and `replaceDuplicatePlugins` options have no effect.
`custom-webpack.config.js` example :
Expand Down
6 changes: 5 additions & 1 deletion packages/custom-webpack/e2e/custom-webpack-config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ export const customWebpackConfig = {
description: 'Custom webpack configuration',
properties: {
path: { type: 'string', description: 'Path to the custom webpack configuration file' },
mergeStrategies: { type: 'object', description: 'Merge strategies per webpack config field' },
mergeRules: {
type: 'object',
description:
'Merge rules as described here: https://github.com/survivejs/webpack-merge#mergewithrules',
},
replaceDuplicatePlugins: {
type: 'boolean',
description: 'Flag that indicates whether to replace duplicate webpack plugins or not',
Expand Down
2 changes: 1 addition & 1 deletion packages/custom-webpack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,6 @@
"@angular-devkit/core": "^11.0.0",
"lodash": "^4.17.15",
"ts-node": "^9.0.0",
"webpack-merge": "^4.2.2"
"webpack-merge": "^5.7.0"
}
}
6 changes: 3 additions & 3 deletions packages/custom-webpack/src/custom-webpack-builder-config.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { MergeStrategy } from 'webpack-merge';
import type { mergeWithRules } from 'webpack-merge';

export type MergeStrategies = { [field: string]: MergeStrategy };
export type MergeRules = Parameters<typeof mergeWithRules>[0];

export interface CustomWebpackBuilderConfig {
path?: string;
mergeStrategies?: MergeStrategies;
mergeRules?: MergeRules;
replaceDuplicatePlugins?: boolean;
}
11 changes: 6 additions & 5 deletions packages/custom-webpack/src/custom-webpack-builder.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Path } from '@angular-devkit/core';
import { Configuration } from 'webpack';
import { CustomizeRule } from 'webpack-merge';

import { CustomWebpackBuilder, defaultWebpackConfigPath } from './custom-webpack-builder';
import { MergeStrategies } from './custom-webpack-builder-config';
import { MergeRules } from './custom-webpack-builder-config';
import * as webpackConfigMerger from './webpack-config-merger';

const baseWebpackConfig = {
Expand All @@ -16,7 +17,7 @@ const buildOptions = {
const targetOptions = {
project: 'application',
configuration: 'production',
target: 'serve'
target: 'serve',
};

const customWebpackConfig = {
Expand Down Expand Up @@ -120,11 +121,11 @@ describe('CustomWebpackBuilder', () => {
it('should pass on merge strategies', async () => {
const spy = jest.spyOn(webpackConfigMerger, 'mergeConfigs');
createConfigFile(defaultWebpackConfigPath, customWebpackConfig);
const mergeStrategies: MergeStrategies = { blah: 'prepend' };
const mergeRules: MergeRules = { blah: CustomizeRule.Prepend };

await CustomWebpackBuilder.buildWebpackConfig(
__dirname as Path,
{ mergeStrategies },
{ mergeRules },
baseWebpackConfig,
{},
{}
Expand All @@ -134,7 +135,7 @@ describe('CustomWebpackBuilder', () => {
expect(spy).toHaveBeenCalledWith(
baseWebpackConfig,
customWebpackConfig,
mergeStrategies,
mergeRules,
undefined
);
} finally {
Expand Down
19 changes: 13 additions & 6 deletions packages/custom-webpack/src/custom-webpack-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,24 @@ import { Configuration } from 'webpack';
import { mergeConfigs } from './webpack-config-merger';
import { CustomWebpackBuilderConfig } from './custom-webpack-builder-config';
import { tsNodeRegister } from './utils';
import {TargetOptions} from "./type-definition";
import {CustomWebpackBrowserSchema} from "./browser";
import { TargetOptions } from './type-definition';
import { CustomWebpackBrowserSchema } from './browser';

export const defaultWebpackConfigPath = 'webpack.config.js';

type CustomWebpackConfig =
| Configuration
| Promise<Configuration>
| ((baseWebpackConfig: Configuration, buildOptions: CustomWebpackBrowserSchema, targetOptions: TargetOptions) => Configuration)
| ((baseWebpackConfig: Configuration, buildOptions: CustomWebpackBrowserSchema, targetOptions: TargetOptions) => Promise<Configuration>);
| ((
baseWebpackConfig: Configuration,
buildOptions: CustomWebpackBrowserSchema,
targetOptions: TargetOptions
) => Configuration)
| ((
baseWebpackConfig: Configuration,
buildOptions: CustomWebpackBrowserSchema,
targetOptions: TargetOptions
) => Promise<Configuration>);

export class CustomWebpackBuilder {
static async buildWebpackConfig(
Expand Down Expand Up @@ -49,14 +57,13 @@ export class CustomWebpackBuilder {
return mergeConfigs(
baseWebpackConfig,
resolvedConfig,
config.mergeStrategies,
config.mergeRules,
config.replaceDuplicatePlugins
);
}
}

function resolveCustomWebpackConfig(path: string): CustomWebpackConfig {

tsNodeRegister(path);

const customWebpackConfig = require(path);
Expand Down
2 changes: 1 addition & 1 deletion packages/custom-webpack/src/schema.ext.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"description": "Custom webpack configuration",
"properties": {
"path": {"type": "string", "description": "Path to the custom webpack configuration file"},
"mergeStrategies": {"type": "object", "description": "Merge strategies per webpack config field"},
"mergeRules": {"type": "object", "description": "Merge rules as described here: https://github.com/survivejs/webpack-merge#mergewithrules"},
"replaceDuplicatePlugins": {"type": "boolean", "description": "Flag that indicates whether to replace duplicate webpack plugins or not"}
},
"default": false
Expand Down
18 changes: 14 additions & 4 deletions packages/custom-webpack/src/webpack-config-merger.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { mergeConfigs } from './webpack-config-merger';
import * as webpack from 'webpack';
import { CustomizeRule } from 'webpack-merge';

describe('Webpack config merger test', () => {
it('Should replace plugins', () => {
Expand Down Expand Up @@ -141,7 +142,7 @@ describe('Webpack config merger test', () => {
}
});

it('Should replace plugins while working properly with other strategies', () => {
it('Should replace plugins while working properly with merging rules', () => {
const plugin1 = new webpack.HotModuleReplacementPlugin({
multiStep: true,
fullBuildTimeout: 3000,
Expand All @@ -161,7 +162,7 @@ describe('Webpack config merger test', () => {
externals: ['c', 'd'],
plugins: [plugin2],
},
{ externals: 'prepend' },
{ externals: CustomizeRule.Prepend },
true
);

Expand All @@ -180,7 +181,15 @@ describe('Webpack config merger test', () => {
rules: [
{
test: /\.css$/,
use: [{ loader: 'style-loader' }, { loader: 'sass-loader' }],
use: [
{
loader: 'style-loader',
options: {
someOption: 'blah',
},
},
{ loader: 'sass-loader' },
],
},
],
},
Expand Down Expand Up @@ -214,9 +223,10 @@ describe('Webpack config merger test', () => {
loader: 'style-loader',
options: {
modules: true,
someOption: 'blah',
},
},
'sass-loader',
{ loader: 'sass-loader' },
],
},
],
Expand Down
21 changes: 17 additions & 4 deletions packages/custom-webpack/src/webpack-config-merger.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
import { MergeStrategies } from './custom-webpack-builder-config';
import { smartStrategy } from 'webpack-merge';
import { MergeRules } from './custom-webpack-builder-config';
import { CustomizeRule, mergeWithRules } from 'webpack-merge';
import { Configuration } from 'webpack';
import { differenceWith, keyBy, merge } from 'lodash';

const DEFAULT_MERGE_RULES: MergeRules = {
module: {
rules: {
test: CustomizeRule.Match,
use: {
loader: CustomizeRule.Match,
options: CustomizeRule.Merge,
},
},
},
};

export function mergeConfigs(
webpackConfig1: Configuration,
webpackConfig2: Configuration,
mergeStrategies: MergeStrategies = {},
mergeRules: MergeRules = DEFAULT_MERGE_RULES,
replacePlugins = false
): Configuration {
const mergedConfig = smartStrategy(mergeStrategies)(webpackConfig1, webpackConfig2);
const mergedConfig: Configuration = mergeWithRules(mergeRules)(webpackConfig1, webpackConfig2);

if (webpackConfig1.plugins && webpackConfig2.plugins) {
const conf1ExceptConf2 = differenceWith(
webpackConfig1.plugins,
Expand Down

0 comments on commit 421d867

Please sign in to comment.