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(), ], };