feat: allow user to modify generated webpack config

This commit is contained in:
endiliey 2018-08-30 03:30:44 +08:00
parent 2b5ee3e869
commit 10b1a38762
9 changed files with 172 additions and 3 deletions

View file

@ -6,6 +6,7 @@ const globby = require('globby');
const load = require('../load');
const createServerConfig = require('../webpack/server');
const createClientConfig = require('../webpack/client');
const {applyConfigureWebpack} = require('../webpack/utils');
function compile(config) {
return new Promise((resolve, reject) => {
@ -36,8 +37,15 @@ module.exports = async function build(siteDir, cliOptions = {}) {
const props = await load(siteDir);
const serverConfig = createServerConfig(props).toConfig();
const clientConfig = createClientConfig(props).toConfig();
let serverConfig = createServerConfig(props).toConfig();
let clientConfig = createClientConfig(props).toConfig();
// apply user webpack config
const {
siteConfig: {configureWebpack}
} = props;
clientConfig = applyConfigureWebpack(configureWebpack, clientConfig, false);
serverConfig = applyConfigureWebpack(configureWebpack, serverConfig, true);
// Build the client bundles first.
// We cannot run them in parallel because the server need to pickup the correct client bundle name

View file

@ -13,6 +13,7 @@ const serve = require('webpack-serve');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const load = require('../load');
const createClientConfig = require('../webpack/client');
const {applyConfigureWebpack} = require('../webpack/utils');
function getHost(reqHost) {
return reqHost || 'localhost';
@ -72,6 +73,13 @@ module.exports = async function start(siteDir, cliOptions = {}) {
}
]);
config = config.toConfig();
// apply user webpack config
const {
siteConfig: {configureWebpack}
} = props;
config = applyConfigureWebpack(configureWebpack, config, false);
const compiler = webpack(config);
// webpack-serve

View file

@ -21,7 +21,9 @@ module.exports = function loadConfig(siteDir, deleteCache = true) {
const optionalFields = [
'customDocsPath',
'highlight',
'markdownPlugins'
'markdownPlugins',
'configureWebpack',
'chainWebpack'
];
const missingFields = requiredFields.filter(field => !config[field]);
if (missingFields && missingFields.length > 0) {

View file

@ -3,6 +3,7 @@ const webpackNiceLog = require('webpack-nicelog');
const {StatsWriterPlugin} = require('webpack-stats-plugin');
const cleanWebpackPlugin = require('clean-webpack-plugin');
const createBaseConfig = require('./base');
const {applyChainWebpack} = require('./utils');
module.exports = function createClientConfig(props) {
const config = createBaseConfig(props);
@ -21,5 +22,9 @@ module.exports = function createClientConfig(props) {
// show compilation progress bar and build time
config.plugin('niceLog').use(webpackNiceLog, [{name: 'Client'}]);
// user extended webpack-chain config
applyChainWebpack(props.siteConfig.chainWebpack, config, false);
return config;
};

View file

@ -2,6 +2,7 @@ const path = require('path');
const staticSiteGenerator = require('static-site-generator-webpack-plugin');
const webpackNiceLog = require('webpack-nicelog');
const createBaseConfig = require('./base');
const {applyChainWebpack} = require('./utils');
module.exports = function createServerConfig(props) {
const config = createBaseConfig(props, true);
@ -32,5 +33,8 @@ module.exports = function createServerConfig(props) {
.plugin('niceLog')
.use(webpackNiceLog, [{name: 'Server', color: 'yellow'}]);
// user extended webpack-chain config
applyChainWebpack(props.siteConfig.chainWebpack, config, true);
return config;
};

28
lib/webpack/utils.js Normal file
View file

@ -0,0 +1,28 @@
const merge = require('webpack-merge');
// Modify the generated webpack config with normal webpack config
function applyConfigureWebpack(userConfig, config, isServer) {
if (typeof userConfig === 'object') {
return merge(config, userConfig);
}
if (typeof userConfig === 'function') {
const res = userConfig(config, isServer);
if (res && typeof res === 'object') {
return merge(config, res);
}
}
return config;
}
// Modify the generated webpack config with webpack-chain API
function applyChainWebpack(userChainWebpack, config, isServer) {
if (userChainWebpack) {
userChainWebpack(config, isServer);
}
}
module.exports = {
applyConfigureWebpack,
applyChainWebpack
};

View file

@ -81,6 +81,7 @@
"style-loader": "^0.22.1",
"webpack": "^4.16.3",
"webpack-chain": "^4.8.0",
"webpack-merge": "^4.1.4",
"webpack-nicelog": "^2.2.1",
"webpack-serve": "^2.0.2",
"webpack-stats-plugin": "^0.2.1"

107
test/webpack/utils.test.js Normal file
View file

@ -0,0 +1,107 @@
import {validate} from 'webpack';
import path from 'path';
import Config from 'webpack-chain';
import {applyConfigureWebpack, applyChainWebpack} from '@lib/webpack/utils';
describe('extending generated webpack config', () => {
test('direct mutation on generated webpack config object', async () => {
// fake generated webpack config
let config = {
output: {
path: __dirname,
filename: 'bundle.js'
}
};
/* eslint-disable */
const configureWebpack = (generatedConfig, isServer) => {
if (!isServer) {
generatedConfig.entry = 'entry.js';
generatedConfig.output = {
path: path.join(__dirname, 'dist'),
filename: 'new.bundle.js'
};
}
};
/* eslint-enable */
config = applyConfigureWebpack(configureWebpack, config, false);
expect(config).toEqual({
entry: 'entry.js',
output: {
path: path.join(__dirname, 'dist'),
filename: 'new.bundle.js'
}
});
const errors = validate(config);
console.log(errors);
expect(errors.length).toBe(0);
});
test('webpack-merge with user webpack config object', async () => {
// fake generated webpack config
let config = {
output: {
path: __dirname,
filename: 'bundle.js'
}
};
/* eslint-disable */
const configureWebpack = {
entry: 'entry.js',
output: {
path: path.join(__dirname, 'dist'),
filename: 'new.bundle.js'
}
};
/* eslint-enable */
config = applyConfigureWebpack(configureWebpack, config, false);
expect(config).toEqual({
entry: 'entry.js',
output: {
path: path.join(__dirname, 'dist'),
filename: 'new.bundle.js'
}
});
const errors = validate(config);
expect(errors.length).toBe(0);
});
test('use webpack-chain API', async () => {
// fake generated webpack config in webpack-chain format
let config = new Config();
config.output.path(__dirname).filename('bundle.js');
// user chainWebpack
/* eslint-disable */
const chainWebpack = (oldConfig, isServer) => {
if (!isServer) {
oldConfig.entry('main').add('./entry.js');
oldConfig.output
.path(path.join(__dirname, 'dist'))
.filename('new.bundle.js');
}
};
/* eslint-enable */
applyChainWebpack(chainWebpack, config, false);
// transform to webpack configuration object format
config = config.toConfig();
expect(config).toEqual({
output: {
path: path.join(__dirname, 'dist'),
filename: 'new.bundle.js'
},
entry: {
main: ['./entry.js']
}
});
const errors = validate(config);
expect(errors.length).toBe(0);
});
});

View file

@ -6975,6 +6975,12 @@ webpack-log@^1.0.1, webpack-log@^1.1.1, webpack-log@^1.1.2, webpack-log@^1.2.0:
loglevelnext "^1.0.1"
uuid "^3.1.0"
webpack-merge@^4.1.4:
version "4.1.4"
resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.1.4.tgz#0fde38eabf2d5fd85251c24a5a8c48f8a3f4eb7b"
dependencies:
lodash "^4.17.5"
webpack-nicelog@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/webpack-nicelog/-/webpack-nicelog-2.2.1.tgz#e3458003ce0d98966e930657176fb4eb6f536b85"