Skip to content

Commit

Permalink
Merge pull request #3765 from alibaba/refactor/react-app-webpack-config
Browse files Browse the repository at this point in the history
refactor: react app webpack config
  • Loading branch information
SoloJiang authored Nov 5, 2020
2 parents 680ca9e + 7e12897 commit 803ca9d
Show file tree
Hide file tree
Showing 17 changed files with 303 additions and 76 deletions.
12 changes: 4 additions & 8 deletions packages/build-app-helpers/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import getMpaEntries from './getMpaEntries';
import getRoutesByAppJson from './getRoutesByAppJson';
import formatPath from './formatPath';
export { default as getMpaEntries } from './getMpaEntries';
export { default as getRoutesByAppJson } from './getRoutesByAppJson';
export { default as formatPath } from './formatPath';
export { default as validation } from './validation';

export {
getMpaEntries,
getRoutesByAppJson,
formatPath,
};
19 changes: 19 additions & 0 deletions packages/build-app-helpers/src/validation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const assert = require('assert');
const { isPlainObject } = require('lodash');

const validation = (key, value, types) => {
const validateResult = types.split('|').some((type) => {
if (type === 'array') {
return Array.isArray(value);
} else if (type === 'object') {
return isPlainObject(value);
} else {
// eslint-disable-next-line valid-typeof
return typeof value === type;
}
});
assert(validateResult, `Config ${key} should be ${types.replace('|', ' | ')}, but got ${value}`);
return validateResult;
};

export default validation;
24 changes: 14 additions & 10 deletions packages/build-webpack-config/src/applyUserConfig.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const defaultConfig = require('./config/default.config');
const unionBy = require('lodash/unionBy');
const defaultConfigKeys = require('./config/default.config');
const validation = require('./config/validation');
const modifyUserConfig = require('./utils/modifyUserConfig');

Expand All @@ -10,21 +11,19 @@ const CONFIG = [{
}, {
name: 'disableRuntime',
validation: 'boolean',
defaultValue: false
defaultValue: false,
configWebpack: () => {}
}];

module.exports = (api, options = {}) => {
const { registerUserConfig, log } = api;
const { customConfig } = options;
const { customConfigs } = options;
CONFIG.forEach((item) => registerUserConfig(item));

const config = Object.assign({}, defaultConfig, customConfig);

// sort config key to make sure entry config is always excute before injectBabel
const configKeys = Object.keys(config).sort();
const configKeys = Object.keys(defaultConfigKeys).sort();

// register user config
registerUserConfig(configKeys.map((configKey) => {
const defaultConfig = configKeys.map((configKey) => {
let configFunc = null;
let configValidation = null;
try {
Expand All @@ -40,11 +39,16 @@ module.exports = (api, options = {}) => {
name: configKey,
validation: configValidation,
configWebpack: configFunc,
defaultValue: config[configKey],
defaultValue: defaultConfigKeys[configKey],
};
}
return false;
}).filter(Boolean));
}).filter(Boolean);

const finalyConfig = unionBy(customConfigs.concat(defaultConfig), 'name');

// register user config
registerUserConfig(finalyConfig);

// modify user config to keep excute order
modifyUserConfig(api);
Expand Down
18 changes: 1 addition & 17 deletions packages/build-webpack-config/src/config/validation.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,4 @@
const assert = require('assert');
const { isPlainObject } = require('lodash');

const validation = (key, value, types) => {
const validateResult = types.split('|').some((type) => {
if (type === 'array') {
return Array.isArray(value);
} else if (type === 'object') {
return isPlainObject(value);
} else {
// eslint-disable-next-line valid-typeof
return typeof value === type;
}
});
assert(validateResult, `Config ${key} should be ${types.replace('|', ' | ')}, but got ${value}`);
return validateResult;
};
const { validation } = require('build-app-helpers');

module.exports = {
alias: 'object',
Expand Down
12 changes: 1 addition & 11 deletions packages/build-webpack-config/src/getEnhanceWebpackConfig.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
const CopyWebpackPlugin = require('copy-webpack-plugin');
const path = require('path');
const fs = require('fs-extra');

module.exports = (api, { target, webpackConfig, babelConfig, libName = 'rax' }) => {
const { context } = api;
const { rootDir, command, webpack, commandArgs } = context;
const { command, webpack, commandArgs } = context;
const appMode = commandArgs.mode || command;

const mode = command === 'start' ? 'development' : 'production';
Expand All @@ -25,12 +21,6 @@ module.exports = (api, { target, webpackConfig, babelConfig, libName = 'rax' })
.plugin('DefinePlugin')
.use(webpack.DefinePlugin, [defineVariables]);

// Copy public dir
if (fs.existsSync(path.resolve(rootDir, 'public'))) {
webpackConfig.plugin('CopyWebpackPlugin').use(CopyWebpackPlugin, [[]]);
}


// Process app.json file
webpackConfig.module
.rule('appJSON')
Expand Down
4 changes: 2 additions & 2 deletions packages/build-webpack-config/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
const applyCliOption = require('./applyCliOption');
const applyUserConfig = require('./applyUserConfig');
const getEnhanceWebpackConfig = require('./getEnhanceWebpackConfig');
const getDefaultConfig = require('./config/default.config');
const defaultConfig = require('./config/default.config');

export {
applyCliOption,
applyUserConfig,
getEnhanceWebpackConfig,
getDefaultConfig
defaultConfig
};
16 changes: 0 additions & 16 deletions packages/build-webpack-config/src/utils/getWebOutputPath.js

This file was deleted.

27 changes: 27 additions & 0 deletions packages/plugin-react-app/src/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const { validation } = require('build-app-helpers');

/* eslint global-require: 0 */
module.exports = [
{
name: 'entry',
defaultValue: 'src/index.jsx',
configWebpack: require('./userConfig/entry'),
validation: (val) => {
// entry: string | array
// entry : { [name]: string | array }
return validation('entry', val, 'string|array|object');
},
},
{
name: 'ignoreHtmlTemplate',
defauleValue: false,
configWebpack: require('./userConfig/ignoreHtmlTemplate'),
validation: 'boolean',
},
{
name: 'outputDir',
defaultValue: 'build',
configWebpack: require('./userConfig/outputDir'),
validation: 'string'
}
];
18 changes: 11 additions & 7 deletions packages/plugin-react-app/src/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
const path = require('path');
const { applyCliOption, applyUserConfig, getWebpackBase } = require('build-webpack-config');
const { applyCliOption, applyUserConfig, getEnhanceWebpackConfig } = require('build-webpack-config');
const { getWebpackConfig, getBabelConfig } = require('build-scripts-config');
const { WEB, MINIAPP, WECHAT_MINIPROGRAM} = require('./constants');
const setTest = require('./setTest');
const customConfigs = require('./config');
const setBase = require('./setBase');
const setDev = require('./setDev');
const setBuild = require('./setBuild');
const setTest = require('./setTest');

module.exports = (api) => {
const { onGetWebpackConfig, context, registerTask } = api;
Expand All @@ -19,10 +21,10 @@ module.exports = (api) => {
applyCliOption(api);

// register user config
applyUserConfig(api);
applyUserConfig(api, { customConfigs });

// set webpack config
onGetWebpackConfig((chainConfig) => {
onGetWebpackConfig(chainConfig => {
// add resolve modules of project node_modules
chainConfig.resolve.modules.add(path.join(rootDir, 'node_modules'));
});
Expand All @@ -33,7 +35,11 @@ module.exports = (api) => {
if (target === WEB && !userConfig.targets) {
target = '';
}
registerTask(target, getWebpackBase(api, { target, webpackConfig, babelConfig }));
registerTask(target, getEnhanceWebpackConfig(api, { target, webpackConfig, babelConfig }));

onGetWebpackConfig((chainConfig) => {
setBase(api, { target, webpackConfig: chainConfig });
});
});

if (command === 'start') {
Expand All @@ -55,5 +61,3 @@ module.exports = (api) => {
setTest(api);
}
};


87 changes: 87 additions & 0 deletions packages/plugin-react-app/src/setBase.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const WebpackPluginImport = require('webpack-plugin-import');
const { getFilePath, getWebOutputPath } = require('./utils');
const { WEB } = require('./constants');

module.exports = (api, { target, webpackConfig }) => {
const { context } = api;
const { rootDir } = context;
const outputPath = getWebOutputPath(context, { target });

webpackConfig
// SimpleProgressPlugin
.plugin('SimpleProgressPlugin')
.tap(([args]) => {
return [{
...args,
progressOptions: {
clear: true,
callback: () => {
console.log();
}
}
}];
})
.end()
// HtmlWebpackPlugin
.plugin('HtmlWebpackPlugin')
.use(HtmlWebpackPlugin, [{
inject: true,
templateParameters: {
NODE_ENV: process.env.NODE_ENV,
},
favicon: getFilePath([
path.join(rootDir, 'public/favicon.ico'),
path.join(rootDir, 'public/favicon.png'),
]),
template: path.resolve(rootDir, 'public/index.html'),
minify: false,
}])
.end()
// CopyWebpackPlugin
.plugin('CopyWebpackPlugin')
.use(CopyWebpackPlugin, [[
{
from: path.resolve(rootDir, 'public'),
to: path.resolve(rootDir, outputPath),
ignore: ['index.html'],
},
]])
.end()
// WebpackPluginImport
.plugin('WebpackPluginImport')
.use(WebpackPluginImport, [[
{
libraryName: /@ali\/ice-.*/,
stylePath: 'style.js',
},
]])
.end();

// Process rpx to vw
if (target === WEB) {
const cssPreprocessor = [ 'scss', 'scss-module', 'css', 'css-module', 'less', 'less-module'];
cssPreprocessor.forEach(rule => {
if (webpackConfig.module.rules.get(rule)) {
webpackConfig.module
.rule(rule)
.use('postcss-loader')
.tap((options) => {
const { plugins = [] } = options;
return {
...options,
plugins: [
...plugins,
// eslint-disable-next-line
require('postcss-plugin-rpx2vw')
],
};
});
}
});
}

return webpackConfig;
};
Loading

0 comments on commit 803ca9d

Please sign in to comment.