Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge module rules with custom webpack config #8

Merged
merged 7 commits into from
Dec 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Test

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
test:

runs-on: ubuntu-latest

strategy:
matrix:
node-version: [12.x, 14.x, 16.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
cache: 'yarn'
- run: yarn install
- run: yarn test
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
node_modules/
yarn.lock
package-lock.json
yarn-error.log
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,23 @@ module.exports = function(env, args) {
};
```

If you want to adapt predefined rules and merge them to one, you may do so by matching `test`-expression:

```Javascript
module.exports = function(env, args) {
return {
module: {
rules: [
{
test: /\.(sass|scss)$/, // use same expression used by plugin to merge
...
}
]
},
};
};
```

To remove entry points from webpack, you can set them to null in your own configuration

## Using modernizr
Expand Down
59 changes: 42 additions & 17 deletions helpers/configHelpers.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const fs = require('fs');
const path = require('path');
const { mergeWithCustomize } = require('webpack-merge');
const { mergeWithRules, CustomizeRule } = require('webpack-merge');

const argv = require('minimist')(process.argv.slice(3));

Expand All @@ -14,6 +14,23 @@ function getCustomWebpackConfiguration() {
? require(path.resolve(process.cwd(), 'webpack.js'))
: null;
}
/**
* takes two (partial) configs and compares if a key was set to a non-undefined falsy value in the custom configuration

* @param {object} dc default configuration in current environment
* @param {object} cc custom configuration from project in current environment
*/
function deleteRemovedKeys(dc, cc) {
if (cc) {
Object.keys(dc).forEach((key) => {
const isUnset = cc[key] !== undefined && !cc[key];
if (isUnset) {
delete dc[key];
delete cc[key];
}
});
}
}

function getOutputPath(environment) {
return (
Expand All @@ -24,32 +41,40 @@ function getOutputPath(environment) {
);
}

function buildCustomConfiguration(environment) {
function buildCombinedConfiguration(environment) {
const defaultConfiguration = require(`../config/webpack.${environment}`);
if (!hasOwnConfig()) {
return defaultConfiguration;
}
const customConfig = getCustomWebpackConfiguration();
const customConfiguration = getCustomWebpackConfiguration();

return combineConfigurations(defaultConfiguration, customConfiguration);
}

function combineConfigurations(defaultConfiguration, customConfiguration) {
return function (env, args) {
return mergeWithCustomize({
customizeObject(a, b, key) {
if (key === 'entry') {
Object.keys(a).forEach((key) => {
if (b[key] !== undefined && !b[key]) {
delete a[key];
delete b[key];
}
});
}
const defaultConf = defaultConfiguration(env, args);
const customConf = customConfiguration(env, args);

return undefined;
},
})(defaultConfiguration(env, args), customConfig(env, args));
// Remove the entry points if they are set to non-undefined falsy values in the custom configuration
deleteRemovedKeys(defaultConf.entry, customConf.entry);

return mergeWithRules({
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

module: {
rules: {
test: CustomizeRule.Match,
use: {
loader: "match",
options: "replace"
}
}
}
})(defaultConf, customConf);
};
}

module.exports = {
buildCustomConfiguration,
buildCombinedConfiguration,
combineConfigurations,
getOutputPath,
};
128 changes: 128 additions & 0 deletions helpers/configHelpers.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
const { combineConfigurations } = require('./configHelpers');

const expect = require('chai').expect;

describe('configHelpers', function () {
describe('combineConfigurations', function () {
const mockBabelLoader = function () {};
const mockCssExtractLoader = function () {};
const mockCssLoader = function () {};
const mockPostCssLoader = function () {};
const mockSassLoader = function () {};
const mockAutoprefixerPlugin = function () {};

const defaultConfiguration = function (env, args) {
const mode = args.mode;
return {
entry: {
header: 'header.js',
},
module: {
rules: [
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
loader: mockBabelLoader,
},
{
test: /\.(sass|scss)$/,
use: [
mockCssExtractLoader,
{
loader: mockCssLoader,
options: {
sourceMap: true,
},
},
{
loader: mockPostCssLoader,
options: {
postcssOptions: {
plugins: [mockAutoprefixerPlugin],
},
sourceMap: true,
},
},
{
loader: mockSassLoader,
options: {
sourceMap: true,
sassOptions: {
outputStyle:
mode === 'production' ? 'compressed' : 'nested',
},
},
},
],
},
],
},
};
};

describe('with unset entry in custom config', function () {
const customConfiguration = function (env, args) {
return {
entry: {
header: null,
footer: 'footer.js',
},
};
};

it('is removed from entries', function () {
const config = combineConfigurations(
defaultConfiguration,
customConfiguration
)('dev', { mode: 'development' });
expect(config.entry).to.deep.eq({
footer: 'footer.js',
});
});
});

describe('with existing rule with overwritten loader', function () {
const mockTailwindPlugin = function () {};

const customConfiguration = function (env, args) {
return {
module: {
rules: [
{
test: /\.(sass|scss)$/,
use: [
{
loader: mockPostCssLoader,
options: {
postcssOptions: {
plugins: [mockTailwindPlugin, mockAutoprefixerPlugin],
},
sourceMap: true,
},
},
],
},
],
},
};
};

it('replaces an existing loader', function () {
const config = combineConfigurations(
defaultConfiguration,
customConfiguration
)('dev', { mode: 'development' });
expect(config.module.rules).to.have.length(2);
expect(config.module.rules[1].use).to.have.length(4);
expect(config.module.rules[1].use[2]).to.deep.eq({
loader: mockPostCssLoader,
options: {
postcssOptions: {
plugins: [mockTailwindPlugin, mockAutoprefixerPlugin],
},
sourceMap: true,
},
});
});
});
});
});
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"url": "https://github.com/networkteam/nwt-frontend-scripts"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "mocha 'helpers/*.spec.js'"
},
"dependencies": {
"@babel/core": "^7.14.3",
Expand Down
2 changes: 1 addition & 1 deletion scripts/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ async function processBuild(environment) {
function build(environment, previousFileSizes) {
const webpack = require('webpack');
const combinedConfiguration =
configHelpers.buildCustomConfiguration(environment);
configHelpers.buildCombinedConfiguration(environment);

const compiler = webpack(combinedConfiguration(environment, argv));

Expand Down
2 changes: 1 addition & 1 deletion scripts/watch.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ async function processWatch(environment) {
const webpack = require('webpack');

const combinedConfiguration =
configHelpers.buildCustomConfiguration(environment);
configHelpers.buildCombinedConfiguration(environment);
const compiler = webpack(combinedConfiguration(environment, argv));

compiler.hooks.invalid.tap('invalid', () => {
Expand Down
Loading