mirror of
https://github.com/facebook/docusaurus.git
synced 2025-06-07 05:12:31 +02:00
refactor(v2): simplify webpack stuff (#1342)
* refactor(v2): webpack stuff * nits * nits test
This commit is contained in:
parent
2248b4b927
commit
84c3e0a045
12 changed files with 254 additions and 334 deletions
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
|
const merge = require('webpack-merge');
|
||||||
const CleanWebpackPlugin = require('clean-webpack-plugin');
|
const CleanWebpackPlugin = require('clean-webpack-plugin');
|
||||||
const {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer');
|
const {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
@ -48,16 +49,16 @@ module.exports = async function build(siteDir, cliOptions = {}) {
|
||||||
// Apply user webpack config.
|
// Apply user webpack config.
|
||||||
const {outDir, plugins} = props;
|
const {outDir, plugins} = props;
|
||||||
|
|
||||||
const clientConfigObj = createClientConfig(props);
|
let clientConfig = merge(createClientConfig(props), {
|
||||||
// Remove/clean build folders before building bundles.
|
plugins: [
|
||||||
clientConfigObj.plugin('clean').use(CleanWebpackPlugin, [{verbose: false}]);
|
// Remove/clean build folders before building bundles.
|
||||||
// Visualize size of webpack output files with an interactive zoomable treemap.
|
new CleanWebpackPlugin({verbose: false}),
|
||||||
if (cliOptions.bundleAnalyzer) {
|
// Visualize size of webpack output files with an interactive zoomable treemap.
|
||||||
clientConfigObj.plugin('bundleAnalyzer').use(BundleAnalyzerPlugin);
|
cliOptions.bundleAnalyzer && new BundleAnalyzerPlugin(),
|
||||||
}
|
].filter(Boolean),
|
||||||
|
});
|
||||||
|
|
||||||
let clientConfig = clientConfigObj.toConfig();
|
let serverConfig = createServerConfig(props);
|
||||||
let serverConfig = createServerConfig(props).toConfig();
|
|
||||||
|
|
||||||
// Plugin lifecycle - configureWebpack
|
// Plugin lifecycle - configureWebpack
|
||||||
plugins.forEach(plugin => {
|
plugins.forEach(plugin => {
|
||||||
|
|
|
@ -17,6 +17,7 @@ const {prepareUrls} = require('react-dev-utils/WebpackDevServerUtils');
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
const HotModuleReplacementPlugin = require('webpack/lib/HotModuleReplacementPlugin');
|
const HotModuleReplacementPlugin = require('webpack/lib/HotModuleReplacementPlugin');
|
||||||
const WebpackDevServer = require('webpack-dev-server');
|
const WebpackDevServer = require('webpack-dev-server');
|
||||||
|
const merge = require('webpack-merge');
|
||||||
const {normalizeUrl} = require('@docusaurus/utils');
|
const {normalizeUrl} = require('@docusaurus/utils');
|
||||||
const load = require('../load');
|
const load = require('../load');
|
||||||
const loadConfig = require('../load/config');
|
const loadConfig = require('../load/config');
|
||||||
|
@ -83,24 +84,24 @@ module.exports = async function start(siteDir, cliOptions = {}) {
|
||||||
const openUrl = normalizeUrl([urls.localUrlForBrowser, baseUrl]);
|
const openUrl = normalizeUrl([urls.localUrlForBrowser, baseUrl]);
|
||||||
|
|
||||||
// Create compiler from generated webpack config.
|
// Create compiler from generated webpack config.
|
||||||
let config = createClientConfig(props);
|
|
||||||
|
|
||||||
const {siteConfig, plugins = []} = props;
|
const {siteConfig, plugins = []} = props;
|
||||||
config.plugin('html-webpack-plugin').use(HtmlWebpackPlugin, [
|
let config = merge(createClientConfig(props), {
|
||||||
{
|
plugins: [
|
||||||
inject: false,
|
// Generates an `index.html` file with the <script> injected.
|
||||||
hash: true,
|
new HtmlWebpackPlugin({
|
||||||
template: path.resolve(
|
inject: false,
|
||||||
__dirname,
|
hash: true,
|
||||||
'../core/templates/index.html.template.ejs',
|
template: path.resolve(
|
||||||
),
|
__dirname,
|
||||||
filename: 'index.html',
|
'../core/templates/index.html.template.ejs',
|
||||||
title: siteConfig.title,
|
),
|
||||||
},
|
filename: 'index.html',
|
||||||
]);
|
title: siteConfig.title,
|
||||||
// Needed for hot reload.
|
}),
|
||||||
config.plugin('hmr').use(HotModuleReplacementPlugin);
|
// This is necessary to emit hot updates for webpack-dev-server
|
||||||
config = config.toConfig();
|
new HotModuleReplacementPlugin(),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
// Plugin lifecycle - configureWebpack
|
// Plugin lifecycle - configureWebpack
|
||||||
plugins.forEach(plugin => {
|
plugins.forEach(plugin => {
|
||||||
|
|
|
@ -5,13 +5,11 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const CSSExtractPlugin = require('mini-css-extract-plugin');
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
const Config = require('webpack-chain');
|
|
||||||
const cacheLoaderVersion = require('cache-loader/package.json').version;
|
|
||||||
const TerserPlugin = require('terser-webpack-plugin');
|
const TerserPlugin = require('terser-webpack-plugin');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const isWsl = require('is-wsl');
|
const isWsl = require('is-wsl');
|
||||||
const {applyBabel, applyCacheLoader, applyStyle} = require('./utils');
|
const {getBabelLoader, getCacheLoader, getStyleLoaders} = require('./utils');
|
||||||
|
|
||||||
const CSS_REGEX = /\.css$/;
|
const CSS_REGEX = /\.css$/;
|
||||||
const CSS_MODULE_REGEX = /\.module\.css$/;
|
const CSS_MODULE_REGEX = /\.module\.css$/;
|
||||||
|
@ -26,133 +24,114 @@ module.exports = function createBaseConfig(props, isServer) {
|
||||||
cliOptions: {cacheLoader},
|
cliOptions: {cacheLoader},
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const config = new Config();
|
|
||||||
const isProd = process.env.NODE_ENV === 'production';
|
const isProd = process.env.NODE_ENV === 'production';
|
||||||
|
return {
|
||||||
config
|
mode: isProd ? 'production' : 'development',
|
||||||
.mode(isProd ? 'production' : 'development')
|
output: {
|
||||||
.output.path(outDir)
|
path: outDir,
|
||||||
.filename(isProd ? '[name].[chunkhash].js' : '[name].js')
|
filename: isProd ? '[name].[chunkhash].js' : '[name].js',
|
||||||
.chunkFilename(isProd ? '[name].[chunkhash].js' : '[name].js')
|
chunkFilename: isProd ? '[name].[chunkhash].js' : '[name].js',
|
||||||
.publicPath(baseUrl);
|
publicPath: baseUrl,
|
||||||
|
|
||||||
if (!isProd) {
|
|
||||||
config.devtool('cheap-module-eval-source-map');
|
|
||||||
}
|
|
||||||
|
|
||||||
config.resolve
|
|
||||||
.set('symlinks', true)
|
|
||||||
.alias.set('@theme', themePath)
|
|
||||||
.set('@site', siteDir)
|
|
||||||
.set('@build', outDir)
|
|
||||||
.set('@generated', generatedFilesDir)
|
|
||||||
.set('@core', path.resolve(__dirname, '../core'))
|
|
||||||
.set('@docusaurus', path.resolve(__dirname, '../docusaurus'))
|
|
||||||
.end()
|
|
||||||
.modules.add(path.resolve(__dirname, '../../node_modules')) // Prioritize our own node modules.
|
|
||||||
.add(path.resolve(siteDir, 'node_modules')) // load user node_modules
|
|
||||||
.add(path.resolve(process.cwd(), 'node_modules'))
|
|
||||||
.add('node_modules');
|
|
||||||
|
|
||||||
const jsRule = config.module
|
|
||||||
.rule('js')
|
|
||||||
.test(/\.jsx?$/)
|
|
||||||
.exclude.add(filepath => {
|
|
||||||
// Always transpile lib directory
|
|
||||||
if (filepath.startsWith(path.join(__dirname, '..'))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Don't transpile node_modules
|
|
||||||
return /node_modules/.test(filepath);
|
|
||||||
})
|
|
||||||
.end();
|
|
||||||
applyCacheLoader(jsRule, {
|
|
||||||
cacheLoader,
|
|
||||||
siteDir,
|
|
||||||
cacheLoaderVersion,
|
|
||||||
isServer,
|
|
||||||
});
|
|
||||||
applyBabel(jsRule, {isServer});
|
|
||||||
|
|
||||||
applyStyle(config.module.rule('css'), {
|
|
||||||
cssOptions: {
|
|
||||||
importLoaders: 1,
|
|
||||||
sourceMap: !isProd,
|
|
||||||
minimize: true,
|
|
||||||
},
|
},
|
||||||
isProd,
|
devtool: !isProd && 'cheap-module-eval-source-map',
|
||||||
isServer,
|
resolve: {
|
||||||
})
|
symlinks: true,
|
||||||
.test(CSS_REGEX)
|
alias: {
|
||||||
.exclude.add(CSS_MODULE_REGEX)
|
'@theme': themePath,
|
||||||
.end();
|
'@site': siteDir,
|
||||||
|
'@build': outDir,
|
||||||
// Adds support for CSS Modules (https://github.com/css-modules/css-modules)
|
'@generated': generatedFilesDir,
|
||||||
// using the extension .module.css
|
'@core': path.resolve(__dirname, '../core'),
|
||||||
applyStyle(config.module.rule('css-module'), {
|
'@docusaurus': path.resolve(__dirname, '../docusaurus'),
|
||||||
cssOptions: {
|
|
||||||
modules: true,
|
|
||||||
importLoaders: 1,
|
|
||||||
localIdentName: `[local]_[hash:base64:8]`,
|
|
||||||
sourceMap: !isProd,
|
|
||||||
minimize: true,
|
|
||||||
},
|
|
||||||
isProd,
|
|
||||||
isServer,
|
|
||||||
}).test(CSS_MODULE_REGEX);
|
|
||||||
|
|
||||||
// mini-css-extract plugin
|
|
||||||
config.plugin('extractCSS').use(CSSExtractPlugin, [
|
|
||||||
{
|
|
||||||
filename: isProd ? '[name].[chunkhash].css' : '[name].css',
|
|
||||||
chunkFilename: isProd ? '[name].[chunkhash].css' : '[name].css',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
// https://webpack.js.org/plugins/split-chunks-plugin/
|
|
||||||
config.optimization.splitChunks({
|
|
||||||
// We set max requests to Infinity because of HTTP/2
|
|
||||||
maxInitialRequests: Infinity,
|
|
||||||
maxAsyncRequests: Infinity,
|
|
||||||
cacheGroups: {
|
|
||||||
// disable the built-in cacheGroups
|
|
||||||
default: false,
|
|
||||||
vendors: {
|
|
||||||
test: /[\\/]node_modules[\\/]/,
|
|
||||||
name: 'vendors',
|
|
||||||
priority: 20,
|
|
||||||
// create chunk regardless of the size of the chunk
|
|
||||||
enforce: true,
|
|
||||||
},
|
|
||||||
common: {
|
|
||||||
name: 'common',
|
|
||||||
chunks: 'all',
|
|
||||||
minChunks: 2,
|
|
||||||
priority: 10,
|
|
||||||
reuseExistingChunk: true,
|
|
||||||
enforce: true,
|
|
||||||
},
|
},
|
||||||
|
modules: [
|
||||||
|
'node_modules',
|
||||||
|
path.resolve(__dirname, '../../node_modules'),
|
||||||
|
path.resolve(siteDir, 'node_modules'),
|
||||||
|
path.resolve(process.cwd(), 'node_modules'),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
});
|
optimization: {
|
||||||
|
// Only minimize client bundle in production because server bundle is only used for static site generation
|
||||||
if (isProd) {
|
minimize: isProd && !isServer,
|
||||||
config.optimization.minimizer([
|
minimizer: [
|
||||||
new TerserPlugin({
|
new TerserPlugin({
|
||||||
cache: true,
|
cache: true,
|
||||||
// We can't run in parallel for WSL due to upstream bug
|
// Disabled on WSL (Windows Subsystem for Linux) due to an issue with Terser
|
||||||
// https://github.com/webpack-contrib/terser-webpack-plugin/issues/21
|
// https://github.com/webpack-contrib/terser-webpack-plugin/issues/21
|
||||||
parallel: !isWsl,
|
parallel: !isWsl,
|
||||||
sourceMap: true,
|
sourceMap: true,
|
||||||
terserOptions: {
|
terserOptions: {
|
||||||
ecma: 6,
|
ecma: 6,
|
||||||
mangle: true,
|
mangle: true,
|
||||||
output: {
|
output: {
|
||||||
comments: false,
|
comments: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
splitChunks: {
|
||||||
|
maxInitialRequests: Infinity,
|
||||||
|
maxAsyncRequests: Infinity,
|
||||||
|
cacheGroups: {
|
||||||
|
// disable the built-in cacheGroups
|
||||||
|
default: false,
|
||||||
|
vendors: {
|
||||||
|
test: /[\\/]node_modules[\\/]/,
|
||||||
|
name: 'vendors',
|
||||||
|
priority: 20,
|
||||||
|
// create chunk regardless of the size of the chunk
|
||||||
|
enforce: true,
|
||||||
|
},
|
||||||
|
common: {
|
||||||
|
name: 'common',
|
||||||
|
chunks: 'all',
|
||||||
|
minChunks: 2,
|
||||||
|
priority: 10,
|
||||||
|
reuseExistingChunk: true,
|
||||||
|
enforce: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.jsx?$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
use: [
|
||||||
|
cacheLoader && getCacheLoader(isServer),
|
||||||
|
getBabelLoader(isServer),
|
||||||
|
].filter(Boolean),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: CSS_REGEX,
|
||||||
|
exclude: CSS_MODULE_REGEX,
|
||||||
|
use: getStyleLoaders(isServer, {
|
||||||
|
importLoaders: 1,
|
||||||
|
sourceMap: !isProd,
|
||||||
|
minimize: true,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
// Adds support for CSS Modules (https://github.com/css-modules/css-modules)
|
||||||
|
// using the extension .module.css
|
||||||
|
{
|
||||||
|
test: CSS_MODULE_REGEX,
|
||||||
|
use: getStyleLoaders(isServer, {
|
||||||
|
modules: true,
|
||||||
|
importLoaders: 1,
|
||||||
|
localIdentName: `[local]_[hash:base64:8]`,
|
||||||
|
sourceMap: !isProd,
|
||||||
|
minimize: true,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new MiniCssExtractPlugin({
|
||||||
|
filename: isProd ? '[name].[chunkhash].css' : '[name].css',
|
||||||
|
chunkFilename: isProd ? '[name].[chunkhash].css' : '[name].css',
|
||||||
}),
|
}),
|
||||||
]);
|
],
|
||||||
}
|
};
|
||||||
|
|
||||||
return config;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,43 +6,44 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const webpackNiceLog = require('webpack-nicelog');
|
const WebpackNiceLog = require('webpack-nicelog');
|
||||||
const {StatsWriterPlugin} = require('webpack-stats-plugin');
|
const {StatsWriterPlugin} = require('webpack-stats-plugin');
|
||||||
const {ReactLoadablePlugin} = require('react-loadable/webpack');
|
const {ReactLoadablePlugin} = require('react-loadable/webpack');
|
||||||
|
const merge = require('webpack-merge');
|
||||||
|
|
||||||
const createBaseConfig = require('./base');
|
const createBaseConfig = require('./base');
|
||||||
const {applyChainWebpack} = require('./utils');
|
|
||||||
|
|
||||||
module.exports = function createClientConfig(props) {
|
module.exports = function createClientConfig(props) {
|
||||||
const isProd = process.env.NODE_ENV === 'production';
|
const isProd = process.env.NODE_ENV === 'production';
|
||||||
|
|
||||||
const config = createBaseConfig(props);
|
const config = createBaseConfig(props);
|
||||||
config.entry('main').add(path.resolve(__dirname, '../core/clientEntry.js'));
|
|
||||||
|
|
||||||
// https://github.com/gaearon/react-hot-loader#react--dom
|
|
||||||
// To enable react-hot-loader in development
|
|
||||||
if (!isProd) {
|
|
||||||
config.resolve.alias.set('react-dom', '@hot-loader/react-dom').end();
|
|
||||||
}
|
|
||||||
|
|
||||||
const {generatedFilesDir} = props;
|
const {generatedFilesDir} = props;
|
||||||
// Write webpack stats object so we can pickup correct client bundle path in server.
|
|
||||||
config
|
|
||||||
.plugin('clientStats')
|
|
||||||
.use(StatsWriterPlugin, [{filename: 'client.stats.json'}]);
|
|
||||||
config
|
|
||||||
.plugin('reactLoadableStats')
|
|
||||||
.use(ReactLoadablePlugin, [
|
|
||||||
{filename: path.join(generatedFilesDir, 'react-loadable.json')},
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Show compilation progress bar and build time.
|
const clientConfig = merge(config, {
|
||||||
config
|
entry: {
|
||||||
.plugin('niceLog')
|
main: path.resolve(__dirname, '../core/clientEntry.js'),
|
||||||
.use(webpackNiceLog, [{name: 'Client', skipBuildTime: isProd}]);
|
},
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
// https://github.com/gaearon/react-hot-loader#react--dom
|
||||||
|
'react-dom': '@hot-loader/react-dom',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
// Write webpack stats object so we can pickup correct client bundle path in server.
|
||||||
|
new StatsWriterPlugin({
|
||||||
|
filename: 'client.stats.json',
|
||||||
|
}),
|
||||||
|
// React-loadable manifests
|
||||||
|
new ReactLoadablePlugin({
|
||||||
|
filename: path.join(generatedFilesDir, 'react-loadable.json'),
|
||||||
|
}),
|
||||||
|
// Show compilation progress bar and build time.
|
||||||
|
new WebpackNiceLog({
|
||||||
|
name: 'Client',
|
||||||
|
skipBuildTime: isProd,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
// User-extended webpack-chain config.
|
return clientConfig;
|
||||||
applyChainWebpack(props.siteConfig.chainWebpack, config, false);
|
|
||||||
|
|
||||||
return config;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,47 +7,48 @@
|
||||||
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const StaticSiteGeneratorPlugin = require('static-site-generator-webpack-plugin');
|
const StaticSiteGeneratorPlugin = require('static-site-generator-webpack-plugin');
|
||||||
const webpackNiceLog = require('webpack-nicelog');
|
const WebpackNiceLog = require('webpack-nicelog');
|
||||||
|
const merge = require('webpack-merge');
|
||||||
const createBaseConfig = require('./base');
|
const createBaseConfig = require('./base');
|
||||||
const {applyChainWebpack} = require('./utils');
|
|
||||||
|
|
||||||
module.exports = function createServerConfig(props) {
|
module.exports = function createServerConfig(props) {
|
||||||
|
const {baseUrl, routesPaths} = props;
|
||||||
const config = createBaseConfig(props, true);
|
const config = createBaseConfig(props, true);
|
||||||
|
|
||||||
config.entry('main').add(path.resolve(__dirname, '../core/serverEntry.js'));
|
|
||||||
config.target('node');
|
|
||||||
config.resolve.alias.set('ejs', 'ejs/ejs.min.js').end();
|
|
||||||
config.output.filename('server.bundle.js').libraryTarget('commonjs2');
|
|
||||||
|
|
||||||
// no need to minimize server bundle since we only run server compilation to generate static html files
|
|
||||||
config.optimization.minimize(false);
|
|
||||||
|
|
||||||
// Workaround for Webpack 4 Bug (https://github.com/webpack/webpack/issues/6522)
|
|
||||||
config.output.globalObject('this');
|
|
||||||
|
|
||||||
const {siteConfig, routesPaths} = props;
|
|
||||||
|
|
||||||
// Static site generator webpack plugin.
|
|
||||||
config.plugin('siteGenerator').use(StaticSiteGeneratorPlugin, [
|
|
||||||
{
|
|
||||||
entry: 'main',
|
|
||||||
locals: {
|
|
||||||
baseUrl: siteConfig.baseUrl,
|
|
||||||
},
|
|
||||||
paths: routesPaths,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Show compilation progress bar.
|
|
||||||
const isProd = process.env.NODE_ENV === 'production';
|
const isProd = process.env.NODE_ENV === 'production';
|
||||||
config
|
|
||||||
.plugin('niceLog')
|
|
||||||
.use(webpackNiceLog, [
|
|
||||||
{name: 'Server', color: 'yellow', skipBuildTime: isProd},
|
|
||||||
]);
|
|
||||||
|
|
||||||
// User-extended webpack-chain config.
|
const serverConfig = merge(config, {
|
||||||
applyChainWebpack(props.siteConfig.chainWebpack, config, true);
|
entry: {
|
||||||
|
main: path.resolve(__dirname, '../core/serverEntry.js'),
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
filename: 'server.bundle.js',
|
||||||
|
libraryTarget: 'commonjs2',
|
||||||
|
// Workaround for Webpack 4 Bug (https://github.com/webpack/webpack/issues/6522)
|
||||||
|
globalObject: 'this',
|
||||||
|
},
|
||||||
|
target: 'node',
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
ejs: 'ejs/ejs.min.js',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
// Static site generator webpack plugin.
|
||||||
|
new StaticSiteGeneratorPlugin({
|
||||||
|
entry: 'main',
|
||||||
|
locals: {
|
||||||
|
baseUrl,
|
||||||
|
},
|
||||||
|
paths: routesPaths,
|
||||||
|
}),
|
||||||
|
|
||||||
return config;
|
// Show compilation progress bar.
|
||||||
|
new WebpackNiceLog({
|
||||||
|
name: 'Server',
|
||||||
|
color: 'yellow',
|
||||||
|
skipBuildTime: isProd,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
return serverConfig;
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const CSSExtractPlugin = require('mini-css-extract-plugin');
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
const path = require('path');
|
const cacheLoaderVersion = require('cache-loader/package.json').version;
|
||||||
const merge = require('webpack-merge');
|
const merge = require('webpack-merge');
|
||||||
|
|
||||||
// Modify the generated webpack config with normal webpack config.
|
// Modify the generated webpack config with normal webpack config.
|
||||||
|
@ -23,68 +23,59 @@ function applyConfigureWebpack(userConfig, config, isServer) {
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modify the generated webpack config with webpack-chain API.
|
// Utility method to get style loaders
|
||||||
function applyChainWebpack(userChainWebpack, config, isServer) {
|
function getStyleLoaders(isServer, cssOptions) {
|
||||||
if (userChainWebpack) {
|
const isProd = process.env.NODE_ENV === 'production';
|
||||||
userChainWebpack(config, isServer);
|
const loaders = [
|
||||||
}
|
!isServer &&
|
||||||
|
isProd && {
|
||||||
|
loader: MiniCssExtractPlugin.loader,
|
||||||
|
},
|
||||||
|
!isServer && !isProd && require.resolve('style-loader'),
|
||||||
|
{
|
||||||
|
loader: isServer
|
||||||
|
? require.resolve('css-loader/locals')
|
||||||
|
: require.resolve('css-loader'),
|
||||||
|
options: cssOptions,
|
||||||
|
},
|
||||||
|
].filter(Boolean);
|
||||||
|
return loaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utility method to add styling-related rule to Webpack config.
|
function getCacheLoader(isServer, cacheOptions) {
|
||||||
function applyStyle(styleRule, {cssOptions, isServer, isProd}) {
|
return {
|
||||||
if (!isServer) {
|
loader: require.resolve('cache-loader'),
|
||||||
if (isProd) {
|
options: Object.assign(
|
||||||
styleRule.use('extract-css-loader').loader(CSSExtractPlugin.loader);
|
{
|
||||||
} else {
|
|
||||||
styleRule.use('style-loader').loader('style-loader');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
styleRule
|
|
||||||
.use('css-loader')
|
|
||||||
.loader(isServer ? 'css-loader/locals' : 'css-loader')
|
|
||||||
.options(cssOptions);
|
|
||||||
|
|
||||||
return styleRule;
|
|
||||||
}
|
|
||||||
|
|
||||||
function applyCacheLoader(
|
|
||||||
rule,
|
|
||||||
{cacheLoader, siteDir, cacheLoaderVersion, isServer},
|
|
||||||
) {
|
|
||||||
if (cacheLoader) {
|
|
||||||
rule
|
|
||||||
.use('cache-loader')
|
|
||||||
.loader('cache-loader')
|
|
||||||
.options({
|
|
||||||
cacheDirectory: path.resolve(siteDir, '.cache-loader'),
|
|
||||||
cacheIdentifier: `cache-loader:${cacheLoaderVersion}${isServer}`,
|
cacheIdentifier: `cache-loader:${cacheLoaderVersion}${isServer}`,
|
||||||
});
|
},
|
||||||
}
|
cacheOptions,
|
||||||
|
),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyBabel(rule, {isServer}) {
|
function getBabelLoader(isServer, babelOptions) {
|
||||||
rule
|
return {
|
||||||
.use('babel')
|
loader: require.resolve('babel-loader'),
|
||||||
.loader('babel-loader')
|
options: Object.assign(
|
||||||
.options({
|
{
|
||||||
// ignore local project babel config (.babelrc)
|
babelrc: false,
|
||||||
babelrc: false,
|
configFile: false,
|
||||||
// ignore local project babel config (babel.config.js)
|
presets: ['@babel/env', '@babel/react'],
|
||||||
configFile: false,
|
plugins: [
|
||||||
presets: ['@babel/env', '@babel/react'],
|
'react-hot-loader/babel',
|
||||||
plugins: [
|
isServer ? 'dynamic-import-node' : '@babel/syntax-dynamic-import',
|
||||||
'react-hot-loader/babel', // To enable react-hot-loader
|
'react-loadable/babel',
|
||||||
isServer ? 'dynamic-import-node' : '@babel/syntax-dynamic-import',
|
],
|
||||||
'react-loadable/babel',
|
},
|
||||||
],
|
babelOptions,
|
||||||
});
|
),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
applyBabel,
|
getBabelLoader,
|
||||||
applyCacheLoader,
|
getCacheLoader,
|
||||||
|
getStyleLoaders,
|
||||||
applyConfigureWebpack,
|
applyConfigureWebpack,
|
||||||
applyChainWebpack,
|
|
||||||
applyStyle,
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -70,7 +70,6 @@
|
||||||
"terser-webpack-plugin": "^1.2.3",
|
"terser-webpack-plugin": "^1.2.3",
|
||||||
"webpack": "^4.26.0",
|
"webpack": "^4.26.0",
|
||||||
"webpack-bundle-analyzer": "^3.1.0",
|
"webpack-bundle-analyzer": "^3.1.0",
|
||||||
"webpack-chain": "^4.9.0",
|
|
||||||
"webpack-dev-server": "^3.2.1",
|
"webpack-dev-server": "^3.2.1",
|
||||||
"webpack-merge": "^4.1.4",
|
"webpack-merge": "^4.1.4",
|
||||||
"webpack-nicelog": "^2.3.1",
|
"webpack-nicelog": "^2.3.1",
|
||||||
|
|
|
@ -13,7 +13,7 @@ describe('webpack base config', () => {
|
||||||
test('simple', async () => {
|
test('simple', async () => {
|
||||||
console.log = jest.fn();
|
console.log = jest.fn();
|
||||||
const props = await loadSetup('simple');
|
const props = await loadSetup('simple');
|
||||||
const config = createBaseConfig(props).toConfig();
|
const config = createBaseConfig(props);
|
||||||
const errors = validate(config);
|
const errors = validate(config);
|
||||||
expect(errors.length).toBe(0);
|
expect(errors.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
@ -21,7 +21,7 @@ describe('webpack base config', () => {
|
||||||
test('custom', async () => {
|
test('custom', async () => {
|
||||||
console.log = jest.fn();
|
console.log = jest.fn();
|
||||||
const props = await loadSetup('custom');
|
const props = await loadSetup('custom');
|
||||||
const config = createBaseConfig(props).toConfig();
|
const config = createBaseConfig(props);
|
||||||
const errors = validate(config);
|
const errors = validate(config);
|
||||||
expect(errors.length).toBe(0);
|
expect(errors.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,7 +13,7 @@ describe('webpack dev config', () => {
|
||||||
test('simple', async () => {
|
test('simple', async () => {
|
||||||
console.log = jest.fn();
|
console.log = jest.fn();
|
||||||
const props = await loadSetup('simple');
|
const props = await loadSetup('simple');
|
||||||
const config = createClientConfig(props).toConfig();
|
const config = createClientConfig(props);
|
||||||
const errors = validate(config);
|
const errors = validate(config);
|
||||||
expect(errors.length).toBe(0);
|
expect(errors.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
@ -21,7 +21,7 @@ describe('webpack dev config', () => {
|
||||||
test('custom', async () => {
|
test('custom', async () => {
|
||||||
console.log = jest.fn();
|
console.log = jest.fn();
|
||||||
const props = await loadSetup('custom');
|
const props = await loadSetup('custom');
|
||||||
const config = createClientConfig(props).toConfig();
|
const config = createClientConfig(props);
|
||||||
const errors = validate(config);
|
const errors = validate(config);
|
||||||
expect(errors.length).toBe(0);
|
expect(errors.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,7 +13,7 @@ describe('webpack production config', () => {
|
||||||
test('simple', async () => {
|
test('simple', async () => {
|
||||||
console.log = jest.fn();
|
console.log = jest.fn();
|
||||||
const props = await loadSetup('simple');
|
const props = await loadSetup('simple');
|
||||||
const config = createServerConfig(props).toConfig();
|
const config = createServerConfig(props);
|
||||||
const errors = validate(config);
|
const errors = validate(config);
|
||||||
expect(errors.length).toBe(0);
|
expect(errors.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
@ -21,7 +21,7 @@ describe('webpack production config', () => {
|
||||||
test('custom', async () => {
|
test('custom', async () => {
|
||||||
console.log = jest.fn();
|
console.log = jest.fn();
|
||||||
const props = await loadSetup('custom');
|
const props = await loadSetup('custom');
|
||||||
const config = createServerConfig(props).toConfig();
|
const config = createServerConfig(props);
|
||||||
const errors = validate(config);
|
const errors = validate(config);
|
||||||
expect(errors.length).toBe(0);
|
expect(errors.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,9 +8,8 @@
|
||||||
import '@babel/polyfill';
|
import '@babel/polyfill';
|
||||||
import {validate} from 'webpack';
|
import {validate} from 'webpack';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import Config from 'webpack-chain';
|
|
||||||
|
|
||||||
import {applyConfigureWebpack, applyChainWebpack} from '@lib/webpack/utils';
|
import {applyConfigureWebpack} from '@lib/webpack/utils';
|
||||||
|
|
||||||
describe('extending generated webpack config', () => {
|
describe('extending generated webpack config', () => {
|
||||||
test('direct mutation on generated webpack config object', async () => {
|
test('direct mutation on generated webpack config object', async () => {
|
||||||
|
@ -76,38 +75,4 @@ describe('extending generated webpack config', () => {
|
||||||
const errors = validate(config);
|
const errors = validate(config);
|
||||||
expect(errors.length).toBe(0);
|
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);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
18
yarn.lock
18
yarn.lock
|
@ -4347,11 +4347,6 @@ deepmerge@3.2.0:
|
||||||
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-3.2.0.tgz#58ef463a57c08d376547f8869fdc5bcee957f44e"
|
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-3.2.0.tgz#58ef463a57c08d376547f8869fdc5bcee957f44e"
|
||||||
integrity sha512-6+LuZGU7QCNUnAJyX8cIrlzoEgggTM6B7mm+znKOX4t5ltluT9KLjN6g61ECMS0LTsLW7yDpNoxhix5FZcrIow==
|
integrity sha512-6+LuZGU7QCNUnAJyX8cIrlzoEgggTM6B7mm+znKOX4t5ltluT9KLjN6g61ECMS0LTsLW7yDpNoxhix5FZcrIow==
|
||||||
|
|
||||||
deepmerge@^1.5.2:
|
|
||||||
version "1.5.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-1.5.2.tgz#10499d868844cdad4fee0842df8c7f6f0c95a753"
|
|
||||||
integrity sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==
|
|
||||||
|
|
||||||
deepmerge@^2.1.1:
|
deepmerge@^2.1.1:
|
||||||
version "2.2.1"
|
version "2.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170"
|
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170"
|
||||||
|
@ -7536,11 +7531,6 @@ isurl@^1.0.0-alpha5:
|
||||||
has-to-string-tag-x "^1.2.0"
|
has-to-string-tag-x "^1.2.0"
|
||||||
is-object "^1.0.1"
|
is-object "^1.0.1"
|
||||||
|
|
||||||
javascript-stringify@^1.6.0:
|
|
||||||
version "1.6.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/javascript-stringify/-/javascript-stringify-1.6.0.tgz#142d111f3a6e3dae8f4a9afd77d45855b5a9cce3"
|
|
||||||
integrity sha1-FC0RHzpuPa6PSpr9d9RYVbWpzOM=
|
|
||||||
|
|
||||||
jest-changed-files@^24.5.0:
|
jest-changed-files@^24.5.0:
|
||||||
version "24.5.0"
|
version "24.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-24.5.0.tgz#4075269ee115d87194fd5822e642af22133cf705"
|
resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-24.5.0.tgz#4075269ee115d87194fd5822e642af22133cf705"
|
||||||
|
@ -13473,14 +13463,6 @@ webpack-bundle-analyzer@^3.1.0:
|
||||||
opener "^1.5.1"
|
opener "^1.5.1"
|
||||||
ws "^6.0.0"
|
ws "^6.0.0"
|
||||||
|
|
||||||
webpack-chain@^4.9.0:
|
|
||||||
version "4.12.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/webpack-chain/-/webpack-chain-4.12.1.tgz#6c8439bbb2ab550952d60e1ea9319141906c02a6"
|
|
||||||
integrity sha512-BCfKo2YkDe2ByqkEWe1Rw+zko4LsyS75LVr29C6xIrxAg9JHJ4pl8kaIZ396SUSNp6b4815dRZPSTAS8LlURRQ==
|
|
||||||
dependencies:
|
|
||||||
deepmerge "^1.5.2"
|
|
||||||
javascript-stringify "^1.6.0"
|
|
||||||
|
|
||||||
webpack-dev-middleware@^3.5.1:
|
webpack-dev-middleware@^3.5.1:
|
||||||
version "3.6.1"
|
version "3.6.1"
|
||||||
resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.6.1.tgz#91f2531218a633a99189f7de36045a331a4b9cd4"
|
resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.6.1.tgz#91f2531218a633a99189f7de36045a331a4b9cd4"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue