From 7ac69ffe512e606a57430481fc785ccb4b6d5f3c Mon Sep 17 00:00:00 2001 From: ClarkXia Date: Fri, 18 Dec 2020 12:03:50 +0800 Subject: [PATCH 1/7] feat: support webpackLoaders and webpackPlugins --- .../src/config/user.config.js | 12 ++- .../src/userConfig/webpackLoaders.js | 82 +++++++++++++++++++ .../src/userConfig/webpackPlugins.js | 24 ++++++ 3 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 packages/build-user-config/src/userConfig/webpackLoaders.js create mode 100644 packages/build-user-config/src/userConfig/webpackPlugins.js diff --git a/packages/build-user-config/src/config/user.config.js b/packages/build-user-config/src/config/user.config.js index 69906e6441..b2b366895b 100644 --- a/packages/build-user-config/src/config/user.config.js +++ b/packages/build-user-config/src/config/user.config.js @@ -207,6 +207,14 @@ module.exports = [ }, { name: 'targets', - validation: 'array' - } + validation: 'array', + }, + { + name: 'webpackLoaders', + validation: 'object', + }, + { + name: 'webpackPlugins', + validation: 'object', + }, ]; diff --git a/packages/build-user-config/src/userConfig/webpackLoaders.js b/packages/build-user-config/src/userConfig/webpackLoaders.js new file mode 100644 index 0000000000..91c389ab0b --- /dev/null +++ b/packages/build-user-config/src/userConfig/webpackLoaders.js @@ -0,0 +1,82 @@ +const genRegExpRule = (value) => new RegExp(Array.isArray(value) ? value.join('|') : value); +const ensureArray = (value) => Array.isArray(value) ? value : [value]; +const optionAPIs = { + test: (rule, value) => { + rule.test(genRegExpRule(value)); + }, + oneOf: (rule, value) => { + rule.oneOf(value); + }, + resourceQuery: (rule, value) => { + rule.resourceQuery(genRegExpRule(value)); + }, + // clear include rules + includeClear: (rule) => { + rule.include.clear(); + }, + include: (rule, value) => { + ensureArray(value).forEach((includeValue) => { + rule.include.add(includeValue); + }); + }, + // clear exclude rules + excludeClear: (rule) => { + rule.exclude.clear(); + }, + exclude: (rule, value) => { + ensureArray(value).forEach((excludeValue) => { + rule.exclude.add(excludeValue); + }); + }, + pre: (rule) => { + rule.pre(); + }, + post: (rule) => { + rule.post(); + }, + enforce: (rule) => { + rule.enforce(); + }, + before: (rule, value) => { + rule.before(value); + }, + after: (rule, value) => { + rule.after(value); + }, +}; +const validRuleOption = Object.keys(optionAPIs); +const configModuleRule = (rule, options) => { + // loop validRuleOption to make sure optionAPIs excute in order + validRuleOption.forEach((optionsKey) => { + const optionValue = options[optionsKey]; + if (optionValue) { + optionAPIs[optionsKey](rule, optionValue); + } + }); +}; + +const configRuleLoaders = (rule, loaders) => { + const loaderNames = Object.keys(loaders); + loaderNames.forEach((loaderName) => { + const loaderOptions = loaders[loaderName]; + // check if loader is exsits + if (rule.uses.has(loaderName)) { + rule.use(loaderName).tap(opts => ({ ...opts, ...loaderOptions})); + } else { + rule.use(loaderName).loader(loaderName).options(loaderOptions); + } + }); +}; + +module.exports = (config, webpackLoaders) => { + if (webpackLoaders) { + const ruleNames = Object.keys(webpackLoaders); + ruleNames.forEach((ruleName) => { + // create new rule if module rule is not exists + const rule = config.module.rule(ruleName); + const ruleOptions = webpackLoaders[ruleName]; + configModuleRule(rule, ruleOptions); + configRuleLoaders(rule, ruleOptions.loaders || {}); + }); + } +}; \ No newline at end of file diff --git a/packages/build-user-config/src/userConfig/webpackPlugins.js b/packages/build-user-config/src/userConfig/webpackPlugins.js new file mode 100644 index 0000000000..249b665256 --- /dev/null +++ b/packages/build-user-config/src/userConfig/webpackPlugins.js @@ -0,0 +1,24 @@ +module.exports = (config, webpackPlugins, context) => { + if (webpackPlugins) { + const pluginNames = Object.keys(webpackPlugins); + pluginNames.forEach((pluginName) => { + // check if plugin has been already registed + if (config.plugins.has(pluginName)) { + // modify plugin options + config.plugin(pluginName).tap(([args]) => [{...args, ...webpackPlugins[pluginName]}]); + } else { + // add new plugin + let plugin = null; + if (pluginName.match(/^webpack\./)) { + // webpack builtin plugins + const { webpack } = context; + plugin = webpack[pluginName]; + } else { + // eslint-disable-next-line + plugin = require(pluginName); + } + config.plugin(pluginName).use(plugin, [webpackPlugins[pluginName]]); + } + }); + } +}; \ No newline at end of file From c674989e3d0f4da538bf91a244f3a507e82fbdf5 Mon Sep 17 00:00:00 2001 From: ClarkXia Date: Fri, 18 Dec 2020 12:43:22 +0800 Subject: [PATCH 2/7] feat: support before and after --- .../build-user-config/src/userConfig/webpackLoaders.js | 9 ++++++--- .../build-user-config/src/userConfig/webpackPlugins.js | 8 ++++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/build-user-config/src/userConfig/webpackLoaders.js b/packages/build-user-config/src/userConfig/webpackLoaders.js index 91c389ab0b..65f45696b9 100644 --- a/packages/build-user-config/src/userConfig/webpackLoaders.js +++ b/packages/build-user-config/src/userConfig/webpackLoaders.js @@ -58,13 +58,16 @@ const configModuleRule = (rule, options) => { const configRuleLoaders = (rule, loaders) => { const loaderNames = Object.keys(loaders); loaderNames.forEach((loaderName) => { - const loaderOptions = loaders[loaderName]; + const { options, before, after } = loaders[loaderName]; // check if loader is exsits + let loaderRule = null; if (rule.uses.has(loaderName)) { - rule.use(loaderName).tap(opts => ({ ...opts, ...loaderOptions})); + loaderRule = rule.use(loaderName).tap(opts => ({ ...opts, ...options})); } else { - rule.use(loaderName).loader(loaderName).options(loaderOptions); + loaderRule = rule.use(loaderName).loader(loaderName).options(options); } + if (before) loaderRule.before(before); + if (after) loaderRule.after(after); }); }; diff --git a/packages/build-user-config/src/userConfig/webpackPlugins.js b/packages/build-user-config/src/userConfig/webpackPlugins.js index 249b665256..f2e4003325 100644 --- a/packages/build-user-config/src/userConfig/webpackPlugins.js +++ b/packages/build-user-config/src/userConfig/webpackPlugins.js @@ -2,10 +2,12 @@ module.exports = (config, webpackPlugins, context) => { if (webpackPlugins) { const pluginNames = Object.keys(webpackPlugins); pluginNames.forEach((pluginName) => { + const { options, after, before } = webpackPlugins[pluginName]; + let plguinRule = null; // check if plugin has been already registed if (config.plugins.has(pluginName)) { // modify plugin options - config.plugin(pluginName).tap(([args]) => [{...args, ...webpackPlugins[pluginName]}]); + plguinRule = config.plugin(pluginName).tap(([args]) => [{...args, ...options}]); } else { // add new plugin let plugin = null; @@ -17,8 +19,10 @@ module.exports = (config, webpackPlugins, context) => { // eslint-disable-next-line plugin = require(pluginName); } - config.plugin(pluginName).use(plugin, [webpackPlugins[pluginName]]); + plguinRule = config.plugin(pluginName).use(plugin, [options]); } + if (before) plguinRule.before(before); + if (after) plguinRule.after(after); }); } }; \ No newline at end of file From 8ebfbc2537a521877cd6ec1f32969ab6067611c5 Mon Sep 17 00:00:00 2001 From: ClarkXia Date: Fri, 18 Dec 2020 14:36:05 +0800 Subject: [PATCH 3/7] docs: build config of webpackPlugin and webpackLoaders --- docs/guide/basic/build.md | 72 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/docs/guide/basic/build.md b/docs/guide/basic/build.md index 7e4fd76110..68e5cf3e94 100644 --- a/docs/guide/basic/build.md +++ b/docs/guide/basic/build.md @@ -548,6 +548,78 @@ dll // dll 构建产物文件夹 └── dll-pkg.json // build.json 中所配置的 dllEntry 信息 ```` +### webpackPlugins + +- 类型:`object` +- 默认值:无 + +通过 `webpackPlugins` 可以方便地新增或者修改工程上的 webpack 插件配置。 + +配置方式: + +```json +{ + "webpackPlugins": { + "webpack.ProvidePlugin": { + "options": { + "identifier": "module1" + } + }, + "HtmlWebpackPlugin": { + "before": "webpack.ProvidePlugin" + } + } +} +``` + +配置规则如下: +- 对于 webpack 内置的 plugins,可以通过 webpack.PluginName 的形式作为 key 值进行配置 +- 对于其他 webpack 插件,需要将插件的 npm 包名作为 key 值进行配置,package.json 中需要添加并安装该插件依赖 +- 每一项插件配置支持 before/after 用来调整 webpack 插件执行顺序 +- 如果配置设置的插件已被添加,则修改插件配置 + +### webpackLoaders + +- 类型:`object` +- 默认值:无 + +通过 `webpackLoaders` 可以方便地新增或者修改工程上的 webpack loader 配置。 + +配置方式 + +```json +{ + "webpackLoaders": { + "css": { + "test": ".css$", + "loaders": { + "style-loader": { + "options": { + "loaderoption": true + }, + "before": "less-loader" + } + } + } + } +} +``` + +配置规则如下: +- webpackLoaders 配置下每一项为具体的 webpack loader 规则,支持参数 + - test:配置类型 `string|string[]`,同 [Rule.test](https://webpack.js.org/configuration/module/#ruletest) + - oneOf:配置类型 `[oneOfKey: string]: { resourceQuery: string; loaders: Loaders }`,同[Rule.oneOf](https://webpack.js.org/configuration/module/#ruleoneof) + - includeClear:清除默认 include 配置 + - include:配置类型 `string|string[]`,同 [Rule.include](https://webpack.js.org/configuration/module/#ruleinclude) + - excludeClear:清除默认 exclude 配置 + - exclude:配置类型 `string|string[]`,同 [Rule.exclude](https://webpack.js.org/configuration/module/#ruleexclude) + - pre:配置类型 `boolean`,配置 rule 的 enforce 值为 pre + - post:配置类型 `boolean`,配置 rule 的 enforce 值为 post + - before:配置类型 `string`,用于配置定义顺序,前置指定 + - after:配置类型 `string`,用于配置定义顺序,后置指定 + - loaders:配置具体的 webpack loader +- loaders 参数用来指定具体 webpack loader 的参数;每一项 loader 参数支持 before/after 用来调整 webpack loader 的执行顺序;如果 loader 名已被添加,则修改插件配置 + ## 根据环境区分工程配置 参考 [区分不同环境](/docs/guide/basic/config.md)。 From fbd400f6da1457d15074a633b7dc8935c69baded Mon Sep 17 00:00:00 2001 From: ClarkXia Date: Fri, 18 Dec 2020 14:36:33 +0800 Subject: [PATCH 4/7] fix: oneOf rules --- .../src/userConfig/webpackLoaders.js | 22 +++++++++++-------- .../src/userConfig/webpackPlugins.js | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/build-user-config/src/userConfig/webpackLoaders.js b/packages/build-user-config/src/userConfig/webpackLoaders.js index 65f45696b9..b4a765d484 100644 --- a/packages/build-user-config/src/userConfig/webpackLoaders.js +++ b/packages/build-user-config/src/userConfig/webpackLoaders.js @@ -1,14 +1,17 @@ const genRegExpRule = (value) => new RegExp(Array.isArray(value) ? value.join('|') : value); const ensureArray = (value) => Array.isArray(value) ? value : [value]; + const optionAPIs = { test: (rule, value) => { rule.test(genRegExpRule(value)); }, oneOf: (rule, value) => { - rule.oneOf(value); - }, - resourceQuery: (rule, value) => { - rule.resourceQuery(genRegExpRule(value)); + Object.keys(value).forEach((oneOfName) => { + const { resourceQuery, loaders } = value[oneOfName]; + const loaderRule = rule.oneOf(oneOfName) + .resourceQuery(genRegExpRule(resourceQuery)); + configRuleLoaders(loaderRule, loaders || {}); + }); }, // clear include rules includeClear: (rule) => { @@ -45,7 +48,8 @@ const optionAPIs = { }, }; const validRuleOption = Object.keys(optionAPIs); -const configModuleRule = (rule, options) => { + +function configModuleRule(rule, options) { // loop validRuleOption to make sure optionAPIs excute in order validRuleOption.forEach((optionsKey) => { const optionValue = options[optionsKey]; @@ -53,9 +57,9 @@ const configModuleRule = (rule, options) => { optionAPIs[optionsKey](rule, optionValue); } }); -}; +} -const configRuleLoaders = (rule, loaders) => { +function configRuleLoaders(rule, loaders) { const loaderNames = Object.keys(loaders); loaderNames.forEach((loaderName) => { const { options, before, after } = loaders[loaderName]; @@ -69,7 +73,7 @@ const configRuleLoaders = (rule, loaders) => { if (before) loaderRule.before(before); if (after) loaderRule.after(after); }); -}; +} module.exports = (config, webpackLoaders) => { if (webpackLoaders) { @@ -82,4 +86,4 @@ module.exports = (config, webpackLoaders) => { configRuleLoaders(rule, ruleOptions.loaders || {}); }); } -}; \ No newline at end of file +}; diff --git a/packages/build-user-config/src/userConfig/webpackPlugins.js b/packages/build-user-config/src/userConfig/webpackPlugins.js index f2e4003325..eeff9e0fb0 100644 --- a/packages/build-user-config/src/userConfig/webpackPlugins.js +++ b/packages/build-user-config/src/userConfig/webpackPlugins.js @@ -25,4 +25,4 @@ module.exports = (config, webpackPlugins, context) => { if (after) plguinRule.after(after); }); } -}; \ No newline at end of file +}; From 5dccf9aee2cef867026f46332d7b7057b293aaed Mon Sep 17 00:00:00 2001 From: ClarkXia Date: Fri, 18 Dec 2020 14:39:19 +0800 Subject: [PATCH 5/7] fix: resourceQuery --- .../src/userConfig/webpackLoaders.js | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/build-user-config/src/userConfig/webpackLoaders.js b/packages/build-user-config/src/userConfig/webpackLoaders.js index b4a765d484..e1c14fe6e4 100644 --- a/packages/build-user-config/src/userConfig/webpackLoaders.js +++ b/packages/build-user-config/src/userConfig/webpackLoaders.js @@ -6,10 +6,26 @@ const optionAPIs = { rule.test(genRegExpRule(value)); }, oneOf: (rule, value) => { + /** + * config.module + * .rule('css') + * .oneOf('inline') + * .resourceQuery(/inline/) + * .use('url') + * .loader('url-loader') + * .end() + * .end() + * .oneOf('external') + * .resourceQuery(/external/) + * .use('file') + * .loader('file-loader') + */ Object.keys(value).forEach((oneOfName) => { const { resourceQuery, loaders } = value[oneOfName]; - const loaderRule = rule.oneOf(oneOfName) - .resourceQuery(genRegExpRule(resourceQuery)); + const loaderRule = rule.oneOf(oneOfName); + if (resourceQuery) { + loaderRule.resourceQuery(genRegExpRule(resourceQuery)); + } configRuleLoaders(loaderRule, loaders || {}); }); }, From a2d376a67dcd1d61cd3bdfd3eb6b8e42d9e6b26a Mon Sep 17 00:00:00 2001 From: ClarkXia Date: Fri, 18 Dec 2020 14:41:50 +0800 Subject: [PATCH 6/7] chore: doc --- docs/guide/basic/build.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guide/basic/build.md b/docs/guide/basic/build.md index 68e5cf3e94..a4e9a3b671 100644 --- a/docs/guide/basic/build.md +++ b/docs/guide/basic/build.md @@ -585,7 +585,7 @@ dll // dll 构建产物文件夹 通过 `webpackLoaders` 可以方便地新增或者修改工程上的 webpack loader 配置。 -配置方式 +配置方式: ```json { @@ -608,7 +608,7 @@ dll // dll 构建产物文件夹 配置规则如下: - webpackLoaders 配置下每一项为具体的 webpack loader 规则,支持参数 - test:配置类型 `string|string[]`,同 [Rule.test](https://webpack.js.org/configuration/module/#ruletest) - - oneOf:配置类型 `[oneOfKey: string]: { resourceQuery: string; loaders: Loaders }`,同[Rule.oneOf](https://webpack.js.org/configuration/module/#ruleoneof) + - oneOf:配置类型 `[oneOfName: string]: { resourceQuery: string; loaders: Loaders }`,同[Rule.oneOf](https://webpack.js.org/configuration/module/#ruleoneof) - includeClear:清除默认 include 配置 - include:配置类型 `string|string[]`,同 [Rule.include](https://webpack.js.org/configuration/module/#ruleinclude) - excludeClear:清除默认 exclude 配置 From 7d095af4374217447203dae93d0158c81c3d7e4d Mon Sep 17 00:00:00 2001 From: ClarkXia Date: Tue, 22 Dec 2020 10:39:30 +0800 Subject: [PATCH 7/7] chore: typo --- .../build-user-config/src/userConfig/webpackPlugins.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/build-user-config/src/userConfig/webpackPlugins.js b/packages/build-user-config/src/userConfig/webpackPlugins.js index eeff9e0fb0..0ba2ad576e 100644 --- a/packages/build-user-config/src/userConfig/webpackPlugins.js +++ b/packages/build-user-config/src/userConfig/webpackPlugins.js @@ -3,11 +3,11 @@ module.exports = (config, webpackPlugins, context) => { const pluginNames = Object.keys(webpackPlugins); pluginNames.forEach((pluginName) => { const { options, after, before } = webpackPlugins[pluginName]; - let plguinRule = null; + let pluginRule = null; // check if plugin has been already registed if (config.plugins.has(pluginName)) { // modify plugin options - plguinRule = config.plugin(pluginName).tap(([args]) => [{...args, ...options}]); + pluginRule = config.plugin(pluginName).tap(([args]) => [{...args, ...options}]); } else { // add new plugin let plugin = null; @@ -19,10 +19,10 @@ module.exports = (config, webpackPlugins, context) => { // eslint-disable-next-line plugin = require(pluginName); } - plguinRule = config.plugin(pluginName).use(plugin, [options]); + pluginRule = config.plugin(pluginName).use(plugin, [options]); } - if (before) plguinRule.before(before); - if (after) plguinRule.after(after); + if (before) pluginRule.before(before); + if (after) pluginRule.after(after); }); } };