const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
const OfflinePlugin = require('offline-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const WebpackPwaManifest = require('webpack-pwa-manifest');
const CompressionPlugin = require('compression-webpack-plugin');
const WebpackPluginFrTheme = require('webpack-plugin-fr-theme');
const { HashedModuleIdsPlugin } = require('webpack');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
const paths = require('./paths');
const getClientEnvironment = require('./env');
const loaders = require('./loader.prod');
const publicPath = paths.servedPath;
const publicUrl = publicPath.slice(0, -1);
const env = getClientEnvironment(publicUrl);
if (env.stringified['process.env'].NODE_ENV !== '"production"') {
throw new Error('生产环境编译,必须设定环境变量为 NODE_ENV=production.');
}
module.exports = {
mode: 'production',
// build遇到错误,中止build
bail: true,
target: 'web',
entry: [require.resolve('react-app-polyfill/ie11'), paths.appIndexJs],
output: {
path: paths.appBuild,
pathinfo: true,
publicPath: '',
filename: 'assets/js/[name].[hash].js',
sourceMapFilename: 'assets/js/[name].[hash].map',
chunkFilename: 'assets/js/[name].[chunkhash].chunk.js',
},
resolve: {
modules: [paths.appSrc, paths.appNodeModules],
extensions: ['.jsx', '.js', '.scss', '.css', '.json'],
alias: {
'@': paths.appSrc,
},
plugins: [
// 阻止从src和node_modules目录之外导入模块
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]),
],
},
optimization: {
nodeEnv: 'production',
sideEffects: true,
noEmitOnErrors: true,
runtimeChunk: true,
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
warnings: false,
parse: {},
compress: {
ecma: 5,
warnings: false,
comparisons: false,
inline: 2,
},
mangle: true,
output: {
ecma: 5,
comments: false,
ascii_only: true,
},
},
parallel: true,
cache: true,
sourceMap: true,
}),
new OptimizeCSSAssetsPlugin(),
],
splitChunks: {
chunks: 'async', // 必须三选一: "initial直接引入" | "all"(默认就是all)全部 | "async动态引入"
minSize: 30000, // 最小尺寸,默认0
minChunks: 1, // 最小 chunk ,默认1
maxAsyncRequests: 5, // 最大异步请求数, 默认1
maxInitialRequests: 3, // 最大初始化请求书,默认1
name: false,
cacheGroups: {
vendor: {
name: 'vendor',
test: /[\\/]node_modules[\\/]/,
chunks: 'all',
},
otherBase: {
test: module =>
/@ant-design|swagger-ui-react|react|prop-types|antd|recharts|lodash|react-quill/.test(module.context), // 直接使用 test 来做路径匹配,抽离react相关代码
chunks: 'all',
name: 'otherBase',
priority: 10,
},
// styles: {
// name: 'styles',
// test: /\.(scss|css|less)$/,
// chunks: 'all',
// enforce: true,
// },
},
},
},
module: {
// 缺少exports,报错而不是警告
strictExportPresence: true,
rules: [
loaders.jsLoader,
{
oneOf: [
loaders.cssLoaderRule,
loaders.scssLoaderRule,
loaders.lessLoaderRule,
loaders.svgSpriteLoader,
loaders.fontWoffLoader,
loaders.fontTtfLoader,
loaders.imageLoader,
loaders.mediaLoader,
loaders.otherLoader,
],
},
],
},
performance: {
hints: false,
},
plugins: [
// new ProgressBarPlugin(),
new WebpackPluginFrTheme(),
new webpack.DefinePlugin(env.stringified),
new webpack.NamedModulesPlugin(),
new webpack.optimize.ModuleConcatenationPlugin(),
new webpack.optimize.OccurrenceOrderPlugin(true),
new MiniCssExtractPlugin({
filename: 'assets/css/app.[name].css',
chunkFilename: 'assets/css/app.[contenthash:12].css',
}),
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /en-gb|zh-cn/),
new CopyWebpackPlugin([
{
from: paths.appPublic,
to: paths.appBuild,
},
]),
new HtmlWebpackPlugin({
inject: true,
template: paths.appHtml,
sourceMap: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}),
new CleanWebpackPlugin(),
new CompressionPlugin({
algorithm: 'gzip',
test: /\.js$|\.css$|\.html$/,
threshold: 10240,
minRatio: 0.8,
}),
new WebpackPwaManifest({
name: 'AISware AI²',
short_name: 'AISquare',
description: '通用人工智能平台',
background_color: '#fafafa',
theme_color: '#b1624d',
inject: true,
ios: false,
}),
new HashedModuleIdsPlugin({
hashFunction: 'sha256',
hashDigest: 'hex',
hashDigestLength: 20,
}),
new OfflinePlugin({
relativePaths: true,
appShell: '/',
caches: 'all',
AppCache: false,
updateStrategy: 'changed',
safeToUseOptionalCaches: true,
ServiceWorker: {
output: 'assets/js/sw.js',
publicPath: 'assets/js',
minify: true,
events: true,
},
}),
//new BundleAnalyzerPlugin(),
],
};