update webpack to 4.x (#425)

* update webpack to 4.x
pull/429/head
tangjinzhou 2019-01-20 21:13:55 +08:00 committed by GitHub
parent 0e78eedbfb
commit c351cba0e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 268 additions and 205 deletions

View File

@ -3,6 +3,7 @@
module.exports = function(modules) { module.exports = function(modules) {
const plugins = [ const plugins = [
require.resolve('babel-plugin-transform-vue-jsx'), require.resolve('babel-plugin-transform-vue-jsx'),
require.resolve('babel-plugin-inline-import-data-uri'),
require.resolve('babel-plugin-transform-es3-member-expression-literals'), require.resolve('babel-plugin-transform-es3-member-expression-literals'),
require.resolve('babel-plugin-transform-es3-property-literals'), require.resolve('babel-plugin-transform-es3-property-literals'),
require.resolve('babel-plugin-transform-object-assign'), require.resolve('babel-plugin-transform-object-assign'),

View File

@ -1,28 +1,43 @@
const path = require('path'); const path = require('path');
const webpack = require('webpack'); const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin'); const WebpackBar = require('webpackbar');
const webpackMerge = require('webpack-merge');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const deepAssign = require('deep-assign');
const chalk = require('chalk');
const postcssConfig = require('./postcssConfig'); const postcssConfig = require('./postcssConfig');
const CleanUpStatsPlugin = require('./utils/CleanUpStatsPlugin');
const distFileBaseName = 'antd'; const distFileBaseName = 'antd';
module.exports = function(modules) {
const svgRegex = /\.svg(\?v=\d+\.\d+\.\d+)?$/;
const svgOptions = {
limit: 10000,
minetype: 'image/svg+xml',
};
const imageOptions = {
limit: 10000,
};
function getWebpackConfig(modules) {
const pkg = require(path.join(process.cwd(), 'package.json')); const pkg = require(path.join(process.cwd(), 'package.json'));
const babelConfig = require('./getBabelCommonConfig')(modules || false); const babelConfig = require('./getBabelCommonConfig')(modules || false);
const pluginImportOptions = [ const pluginImportOptions = [
{ {
style: true, style: true,
libraryName: 'antd', libraryName: distFileBaseName,
libraryDirectory: 'components', libraryDirectory: 'components',
}, },
]; ];
// if (distFileBaseName !== 'antd') { pluginImportOptions.push({ style:
// 'css', libraryDirectory: 'components', libraryName: 'antd', }) }
babelConfig.plugins.push([require.resolve('babel-plugin-import'), pluginImportOptions]); babelConfig.plugins.push([require.resolve('babel-plugin-import'), pluginImportOptions]);
if (modules === false) {
babelConfig.plugins.push(require.resolve('./replaceLib'));
}
const config = { const config = {
devtool: 'source-map', devtool: 'source-map',
@ -86,74 +101,75 @@ module.exports = function(modules) {
}, },
{ {
test: /\.css$/, test: /\.css$/,
use: ExtractTextPlugin.extract({ use: [
use: [ MiniCssExtractPlugin.loader,
{ {
loader: 'css-loader', loader: 'css-loader',
options: { options: {
sourceMap: true, sourceMap: true,
},
}, },
{ },
loader: 'postcss-loader', {
options: Object.assign({}, postcssConfig, { sourceMap: true }), loader: 'postcss-loader',
}, options: Object.assign({}, postcssConfig, { sourceMap: true }),
], },
}), ],
}, },
{ {
test: /\.less$/, test: /\.less$/,
use: ExtractTextPlugin.extract({ use: [
use: [ MiniCssExtractPlugin.loader,
{ {
loader: 'css-loader', loader: 'css-loader',
options: { options: {
sourceMap: true, sourceMap: true,
},
}, },
{ },
loader: 'postcss-loader', {
options: Object.assign({}, postcssConfig, { sourceMap: true }), loader: 'postcss-loader',
options: Object.assign({}, postcssConfig, { sourceMap: true }),
},
{
loader: 'less-loader',
options: {
sourceMap: true,
javascriptEnabled: true,
}, },
{ },
loader: 'less-loader', ],
options: { },
sourceMap: true, // Images
}, {
}, test: svgRegex,
], loader: 'url-loader',
}), options: svgOptions,
},
{
test: /\.(png|jpg|jpeg|gif)(\?v=\d+\.\d+\.\d+)?$/i,
loader: 'url-loader',
options: imageOptions,
}, },
], ],
}, },
plugins: [ plugins: [
new ExtractTextPlugin({ filename: '[name].css', disable: false, allChunks: true }),
new CaseSensitivePathsPlugin(), new CaseSensitivePathsPlugin(),
new webpack.BannerPlugin(` new webpack.BannerPlugin(`
${distFileBaseName} v${pkg.version} ${pkg.name} v${pkg.version}
Copyright 2017-present, ant-design-vue. Copyright 2017-present, ant-design-vue.
All rights reserved. All rights reserved.
`), `),
new webpack.ProgressPlugin((percentage, msg, addInfo) => { new WebpackBar({
const stream = process.stderr; name: '🚚 Ant Design Vue Tools',
if (stream.isTTY && percentage < 0.71) { color: '#2f54eb',
stream.cursorTo(0);
stream.write(`📦 ${chalk.magenta(msg)} (${chalk.magenta(addInfo)})`);
stream.clearLine(1);
} else if (percentage === 1) {
console.log(chalk.green('\nwebpack: bundle build is now finished.'));
}
}), }),
new CleanUpStatsPlugin(),
], ],
}; };
if (process.env.RUN_ENV === 'PRODUCTION') { if (process.env.RUN_ENV === 'PRODUCTION') {
const entry = ['./index']; const entry = ['./index'];
config.entry = {
[`${distFileBaseName}.min`]: entry,
};
config.externals = { config.externals = {
vue: { vue: {
root: 'Vue', root: 'Vue',
@ -164,38 +180,61 @@ All rights reserved.
}; };
config.output.library = distFileBaseName; config.output.library = distFileBaseName;
config.output.libraryTarget = 'umd'; config.output.libraryTarget = 'umd';
config.optimization = {
const uncompressedConfig = deepAssign({}, config); minimizer: [
new UglifyJsPlugin({
config.plugins = config.plugins.concat([ cache: true,
new webpack.optimize.UglifyJsPlugin({ parallel: true,
sourceMap: true, sourceMap: true,
output: { uglifyOptions: {
ascii_only: true, warnings: false,
}, },
compress: { }),
warnings: false, ],
},
}),
new webpack.optimize.ModuleConcatenationPlugin(),
new webpack.LoaderOptionsPlugin({ minimize: true }),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production'),
}),
]);
uncompressedConfig.entry = {
[distFileBaseName]: entry,
}; };
uncompressedConfig.plugins.push( // Development
new webpack.DefinePlugin({ const uncompressedConfig = webpackMerge({}, config, {
'process.env.NODE_ENV': JSON.stringify('development'), entry: {
}), [distFileBaseName]: entry,
); },
mode: 'development',
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
}),
],
});
return [config, uncompressedConfig]; // Production
const prodConfig = webpackMerge({}, config, {
entry: {
[`${distFileBaseName}.min`]: entry,
},
mode: 'production',
plugins: [
new webpack.optimize.ModuleConcatenationPlugin(),
new webpack.LoaderOptionsPlugin({
minimize: true,
}),
new MiniCssExtractPlugin({
filename: '[name].css',
}),
],
optimization: {
minimizer: [new OptimizeCSSAssetsPlugin({})],
},
});
return [prodConfig, uncompressedConfig];
} }
return config; return config;
}; }
getWebpackConfig.webpack = webpack;
getWebpackConfig.svgRegex = svgRegex;
getWebpackConfig.svgOptions = svgOptions;
getWebpackConfig.imageOptions = imageOptions;
module.exports = getWebpackConfig;

View File

@ -17,6 +17,7 @@ function transformLess(lessFile, config = {}) {
paths: [path.dirname(resolvedLessFile)], paths: [path.dirname(resolvedLessFile)],
filename: resolvedLessFile, filename: resolvedLessFile,
plugins: [new NpmImportPlugin({ prefix: '~' })], plugins: [new NpmImportPlugin({ prefix: '~' })],
javascriptEnabled: true,
}; };
return less return less
.render(data, lessOpts) .render(data, lessOpts)

View File

@ -0,0 +1,38 @@
// We should use `stats` props of webpack. But it not work in v4.
class CleanUpStatsPlugin {
constructor(option) {
this.option = {
MiniCSSExtractPlugin: true,
tsLoader: true,
...option,
};
}
shouldPickStatChild(child) {
const { MiniCSSExtractPlugin } = this.option;
if (MiniCSSExtractPlugin && child.name.includes('mini-css-extract-plugin')) return false;
return true;
}
shouldPickWarning(message) {
const { tsLoader } = this.option;
if (tsLoader && /export .* was not found in .*/.test(message)) {
return false;
}
return true;
}
apply(compiler) {
compiler.hooks.done.tap('CleanUpStatsPlugin', stats => {
const { children, warnings } = stats.compilation;
if (Array.isArray(children)) {
stats.compilation.children = children.filter(child => this.shouldPickStatChild(child));
}
if (Array.isArray(warnings)) {
stats.compilation.warnings = warnings.filter(message => this.shouldPickWarning(message));
}
});
}
}
module.exports = CleanUpStatsPlugin;

View File

@ -26,6 +26,7 @@
"scripts": { "scripts": {
"dev": "cross-env NODE_ENV=development ENTRY_INDEX=dev ./node_modules/.bin/webpack-dev-server --open --hot --port 3001", "dev": "cross-env NODE_ENV=development ENTRY_INDEX=dev ./node_modules/.bin/webpack-dev-server --open --hot --port 3001",
"start": "cross-env NODE_ENV=development ./node_modules/.bin/webpack-dev-server --open --hot", "start": "cross-env NODE_ENV=development ./node_modules/.bin/webpack-dev-server --open --hot",
"site-test": "cross-env NODE_ENV=production webpack --config ./webpack.site.config.js",
"test": "cross-env NODE_ENV=test jest --config .jest.js", "test": "cross-env NODE_ENV=test jest --config .jest.js",
"site": "node scripts/run.js site-dist", "site": "node scripts/run.js site-dist",
"copy": "node scripts/run.js copy-html", "copy": "node scripts/run.js copy-html",
@ -51,8 +52,8 @@
}, },
"homepage": "https://github.com/vueComponent/ant-design-vue", "homepage": "https://github.com/vueComponent/ant-design-vue",
"pre-commit": [ "pre-commit": [
"lint:style", "lint",
"lint" "prettier"
], ],
"peerDependencies": { "peerDependencies": {
"vue": ">=2.5.0", "vue": ">=2.5.0",
@ -68,12 +69,13 @@
"axios": "^0.18.0", "axios": "^0.18.0",
"babel-cli": "^6.26.0", "babel-cli": "^6.26.0",
"babel-core": "^6.26.0", "babel-core": "^6.26.0",
"babel-eslint": "^8.0.1", "babel-eslint": "^10.0.1",
"babel-helper-vue-jsx-merge-props": "^2.0.3", "babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-jest": "^22.4.3", "babel-jest": "^22.4.3",
"babel-loader": "^7.1.2", "babel-loader": "^7.1.2",
"babel-plugin-add-module-exports": "^1.0.0", "babel-plugin-add-module-exports": "^1.0.0",
"babel-plugin-import": "^1.1.1", "babel-plugin-import": "^1.1.1",
"babel-plugin-inline-import-data-uri": "^1.0.1",
"babel-plugin-istanbul": "^4.1.1", "babel-plugin-istanbul": "^4.1.1",
"babel-plugin-syntax-dynamic-import": "^6.18.0", "babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-plugin-syntax-jsx": "^6.18.0", "babel-plugin-syntax-jsx": "^6.18.0",
@ -112,26 +114,28 @@
"gulp-babel": "^7.0.0", "gulp-babel": "^7.0.0",
"gulp-strip-code": "^0.1.4", "gulp-strip-code": "^0.1.4",
"highlight.js": "^9.12.0", "highlight.js": "^9.12.0",
"html-webpack-plugin": "^2.30.1", "html-webpack-plugin": "^3.2.0",
"husky": "^0.14.3", "husky": "^0.14.3",
"istanbul-instrumenter-loader": "^3.0.0", "istanbul-instrumenter-loader": "^3.0.0",
"jest": "^22.4.3", "jest": "^22.4.3",
"jest-serializer-vue": "^1.0.0", "jest-serializer-vue": "^1.0.0",
"js-base64": "^2.4.8", "js-base64": "^2.4.8",
"jsonp": "^0.2.1", "jsonp": "^0.2.1",
"less": "^2.7.2", "less": "^3.9.0",
"less-loader": "^4.0.5", "less-loader": "^4.1.0",
"less-plugin-npm-import": "^2.1.0", "less-plugin-npm-import": "^2.1.0",
"markdown-it": "^8.4.0", "markdown-it": "^8.4.0",
"markdown-it-anchor": "^4.0.0", "markdown-it-anchor": "^4.0.0",
"marked": "^0.3.7", "marked": "^0.3.7",
"merge2": "^1.2.1", "merge2": "^1.2.1",
"mini-css-extract-plugin": "^0.5.0",
"minimist": "^1.2.0", "minimist": "^1.2.0",
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
"mockdate": "^2.0.2", "mockdate": "^2.0.2",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"postcss": "^6.0.20", "optimize-css-assets-webpack-plugin": "^5.0.1",
"postcss-loader": "^2.1.2", "postcss": "^7.0.6",
"postcss-loader": "^3.0.0",
"pre-commit": "^1.2.2", "pre-commit": "^1.2.2",
"prettier": "^1.15.3", "prettier": "^1.15.3",
"querystring": "^0.2.0", "querystring": "^0.2.0",
@ -146,21 +150,24 @@
"stylelint-config-prettier": "^4.0.0", "stylelint-config-prettier": "^4.0.0",
"stylelint-config-standard": "^18.2.0", "stylelint-config-standard": "^18.2.0",
"through2": "^2.0.3", "through2": "^2.0.3",
"uglifyjs-webpack-plugin": "^2.1.1",
"url-loader": "^1.1.2",
"vue": "^2.5.16", "vue": "^2.5.16",
"vue-antd-md-loader": "^1.0.3", "vue-antd-md-loader": "^1.1.0",
"vue-clipboard2": "0.0.8", "vue-clipboard2": "0.0.8",
"vue-i18n": "^8.3.2", "vue-i18n": "^8.3.2",
"vue-infinite-scroll": "^2.0.2", "vue-infinite-scroll": "^2.0.2",
"vue-jest": "^2.5.0", "vue-jest": "^2.5.0",
"vue-loader": "^13.0.5", "vue-loader": "^15.5.1",
"vue-router": "^3.0.1", "vue-router": "^3.0.1",
"vue-server-renderer": "^2.5.16", "vue-server-renderer": "^2.5.16",
"vue-template-compiler": "^2.5.16", "vue-template-compiler": "^2.5.16",
"vue-virtual-scroller": "^0.12.0", "vue-virtual-scroller": "^0.12.0",
"webpack": "^3.11.0", "webpack": "^4.28.4",
"webpack-chunk-hash": "^0.5.0", "webpack-cli": "^3.2.1",
"webpack-dev-server": "^2.8.2", "webpack-dev-server": "^3.1.14",
"webpack-merge": "^4.1.1" "webpack-merge": "^4.1.1",
"webpackbar": "^3.1.5"
}, },
"dependencies": { "dependencies": {
"@ant-design/icons": "^1.1.15", "@ant-design/icons": "^1.1.15",
@ -190,5 +197,11 @@
"shallowequal": "^1.0.2", "shallowequal": "^1.0.2",
"vue-ref": "^1.0.4", "vue-ref": "^1.0.4",
"warning": "^3.0.0" "warning": "^3.0.0"
} },
"sideEffects": [
"dist/*",
"es/**/style/*",
"lib/**/style/*",
"*.less"
]
} }

14
types/breadcrumb.d.ts vendored
View File

@ -34,7 +34,15 @@ export declare class Breadcrumb extends AntdComponent {
* Custom item renderer, slot="itemRender" and slot-scope="{route, params, routes, paths}" * Custom item renderer, slot="itemRender" and slot-scope="{route, params, routes, paths}"
* @type Function * @type Function
*/ */
itemRender: ( itemRender: ({
{ route, params, routes, paths }: { route: any; params: any; routes: any; paths: any }, route,
) => VNode; params,
routes,
paths,
}: {
route: any;
params: any;
routes: any;
paths: any;
}) => VNode;
} }

10
types/cascader.d.ts vendored
View File

@ -86,9 +86,13 @@ export declare class Cascader extends AntdComponent {
* @default labels => labels.join(' / ') * @default labels => labels.join(' / ')
* @type Function * @type Function
*/ */
displayRender: ( displayRender: ({
{ labels, selectedOptions }: { labels: string[]; selectedOptions: CascaderOptionType[] }, labels,
) => VNode; selectedOptions,
}: {
labels: string[];
selectedOptions: CascaderOptionType[];
}) => VNode;
/** /**
* expand current item when click or hover, one of 'click' 'hover' * expand current item when click or hover, one of 'click' 'hover'

View File

@ -6,7 +6,6 @@
import { AntdComponent } from '../component'; import { AntdComponent } from '../component';
export default class LayoutContent extends AntdComponent { export default class LayoutContent extends AntdComponent {
/** /**
* container className * container className
* @default undefined * @default undefined

View File

@ -6,7 +6,6 @@
import { AntdComponent } from '../component'; import { AntdComponent } from '../component';
export default class LayoutFooter extends AntdComponent { export default class LayoutFooter extends AntdComponent {
/** /**
* container className * container className
* @default undefined * @default undefined

View File

@ -6,7 +6,6 @@
import { AntdComponent } from '../component'; import { AntdComponent } from '../component';
export default class LayoutHeader extends AntdComponent { export default class LayoutHeader extends AntdComponent {
/** /**
* container className * container className
* @default undefined * @default undefined

View File

@ -2,6 +2,8 @@ const path = require('path');
const hljs = require('highlight.js'); const hljs = require('highlight.js');
const Token = require('markdown-it/lib/token'); const Token = require('markdown-it/lib/token');
const cheerio = require('cheerio'); const cheerio = require('cheerio');
const WebpackBar = require('webpackbar');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const getBabelCommonConfig = require('./antd-tools/getBabelCommonConfig'); const getBabelCommonConfig = require('./antd-tools/getBabelCommonConfig');
const babelConfig = getBabelCommonConfig(false); const babelConfig = getBabelCommonConfig(false);
@ -129,52 +131,45 @@ md.core.ruler.push('update_template', function replace({ tokens }) {
</script> </script>
` `
: ''; : '';
newContent += style newContent += style ? `<style>${style || ''}</style>` : '';
? ` newContent += scopedStyle ? `<style scoped>${scopedStyle || ''}</style>` : '';
<style>
${style || ''}
</style>
`
: '';
newContent += scopedStyle
? `
<style scoped>
${scopedStyle || ''}
</style>
`
: '';
const t = new Token('html_block', '', 0); const t = new Token('html_block', '', 0);
t.content = newContent; t.content = newContent;
tokens.push(t); tokens.push(t);
} }
}); });
const vueLoaderOptions = {
loaders: {
js: [
{
loader: 'babel-loader',
options: {
presets: ['env'],
plugins: ['transform-vue-jsx', 'transform-object-rest-spread'],
},
},
],
},
};
module.exports = { module.exports = {
mode: 'production',
entry: { entry: {
index: [`./site/${process.env.ENTRY_INDEX || 'index'}.js`], index: [`./site/${process.env.ENTRY_INDEX || 'index'}.js`],
}, },
module: { module: {
rules: [ rules: [
{ {
test: /\.md/, test: /\.md$/,
use: [ use: [
{
loader: 'vue-loader',
options: vueLoaderOptions,
},
{ {
loader: 'vue-antd-md-loader', loader: 'vue-antd-md-loader',
options: Object.assign(md, { options: Object.assign(md, {
wrapper: 'div', wrapper: 'div',
vueLoaderOptions: { raw: true,
loaders: {
js: [
{
loader: 'babel-loader',
options: {
presets: ['env'],
plugins: ['transform-vue-jsx', 'transform-object-rest-spread'],
},
},
],
},
},
}), }),
}, },
], ],
@ -182,23 +177,7 @@ module.exports = {
{ {
test: /\.vue$/, test: /\.vue$/,
loader: 'vue-loader', loader: 'vue-loader',
options: { options: vueLoaderOptions,
loaders: {
js: [
{
loader: 'babel-loader',
options: {
presets: ['env'],
plugins: [
'transform-vue-jsx',
'transform-object-rest-spread',
'syntax-dynamic-import',
],
},
},
],
},
},
}, },
{ {
test: /\.(js|jsx)$/, test: /\.(js|jsx)$/,
@ -225,4 +204,5 @@ module.exports = {
'@': path.join(__dirname, ''), '@': path.join(__dirname, ''),
}, },
}, },
plugins: [new VueLoaderPlugin(), new WebpackBar()],
}; };

View File

@ -5,6 +5,7 @@ const merge = require('webpack-merge');
const baseWebpackConfig = require('./webpack.base.config'); const baseWebpackConfig = require('./webpack.base.config');
module.exports = merge(baseWebpackConfig, { module.exports = merge(baseWebpackConfig, {
mode: 'development',
output: { output: {
path: path.resolve(__dirname, './dist'), path: path.resolve(__dirname, './dist'),
publicPath: '/ant-design-vue/', publicPath: '/ant-design-vue/',
@ -20,7 +21,7 @@ module.exports = merge(baseWebpackConfig, {
loader: 'css-loader', loader: 'css-loader',
options: { sourceMap: true }, options: { sourceMap: true },
}, },
{ loader: 'less-loader', options: { sourceMap: true } }, { loader: 'less-loader', options: { sourceMap: true, javascriptEnabled: true } },
], ],
}, },
{ {

View File

@ -1,86 +1,67 @@
const path = require('path'); const path = require('path');
const webpack = require('webpack'); const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const WebpackChunkHash = require('webpack-chunk-hash');
const HtmlWebpackPlugin = require('html-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin');
const merge = require('webpack-merge'); const merge = require('webpack-merge');
const baseWebpackConfig = require('./webpack.base.config'); const baseWebpackConfig = require('./webpack.base.config');
const modulePlugin = new ExtractTextPlugin({
filename: '[name].[chunkhash].css',
allChunks: true,
});
module.exports = merge(baseWebpackConfig, { module.exports = merge(baseWebpackConfig, {
output: { output: {
path: path.resolve(__dirname, './site-dist'), path: path.resolve(__dirname, './site-dist'),
publicPath: '/ant-design-vue/', publicPath: '/ant-design-vue/',
filename: '[name].[chunkhash].js', filename: '[name].[contenthash:8].js',
chunkFilename: '[chunkhash].async.js', chunkFilename: '[contenthash:8].async.js',
}, },
module: { module: {
rules: [ rules: [
{ {
test: /\.less$/, test: /\.less$/,
use: modulePlugin.extract({ use: [
fallback: 'style-loader', MiniCssExtractPlugin.loader,
use: [ 'css-loader',
{ 'postcss-loader',
loader: 'css-loader', { loader: 'less-loader', options: { javascriptEnabled: true } },
}, ],
{
loader: 'postcss-loader',
},
{ loader: 'less-loader' },
],
}),
}, },
{ {
test: /\.css$/, test: /\.css$/,
use: modulePlugin.extract({ use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'],
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
},
{
loader: 'postcss-loader',
},
],
}),
}, },
], ],
}, },
optimization: {
splitChunks: {
cacheGroups: {
vendors: {
name: `chunk-vendors`,
test: /[\\/]node_modules[\\/]/,
priority: -10,
chunks: 'initial',
},
common: {
name: `chunk-common`,
minChunks: 2,
priority: -20,
chunks: 'initial',
reuseExistingChunk: true,
},
},
},
},
plugins: [ plugins: [
new webpack.DefinePlugin({ new webpack.DefinePlugin({
'process.env': { 'process.env': {
NODE_ENV: '"production"', NODE_ENV: '"production"',
}, },
}), }),
new webpack.optimize.CommonsChunkPlugin({
name: 'vender',
minChunks: function(module) {
return /node_modules/.test(module.context);
},
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
minChunks: Infinity,
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
},
}),
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
template: './site/index.html', template: './site/index.html',
inject: true, inject: true,
production: true, production: true,
}), }),
new webpack.LoaderOptionsPlugin({ new MiniCssExtractPlugin({
minimize: true, filename: '[name].[contenthash:8].css',
chunkFilename: '[id].[contenthash:8].css',
}), }),
modulePlugin,
new WebpackChunkHash({ algorithm: 'md5' }),
], ],
}); });