const autoprefixer = require('autoprefixer');
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ManifestPlugin = require('webpack-manifest-plugin');
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');
const eslintFormatter = require('react-dev-utils/eslintFormatter');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const paths = require('./paths');
const getClientEnvironment = require('./env');
const theme = require('../antd-theme.js');
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
const publicPath = paths.servedPath;
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';
const publicUrl = publicPath.slice(0, -1);
const env = getClientEnvironment(publicUrl);
if (env.stringified['process.env'].NODE_ENV !== '"production"') {
throw new Error('Production builds must have NODE_ENV=production.');
}
module.exports = {
mode: "production",
bail: true,
devtool: shouldUseSourceMap ? 'source-map' : false,
entry: [require.resolve('./polyfills'), paths.appIndexJs],
output: {
path: paths.appBuild,
filename: 'static/js/[name].[chunkhash:8].js',
chunkFilename: 'static/js/[name].[chunkhash:8].chunk.js',
publicPath: publicPath,
devtoolModuleFilenameTemplate: info =>
path
.relative(paths.appSrc, info.absoluteResourcePath)
.replace(/\\/g, '/'),
},
resolve: {
modules: ['node_modules', paths.appNodeModules].concat(
// It is guaranteed to exist because we tweak it in `env.js`
process.env.NODE_PATH.split(path.delimiter).filter(Boolean)
),
extensions: ['.web.js', '.mjs', '.js', '.json', '.web.jsx', '.jsx','.less'],
alias: {
'@': resolve('src'),
'public': resolve('src/public'),
'components': resolve('src/components'),
'pages': resolve('src/pages'),
'mock': resolve('src/public/mock'),
'api': resolve('src/api'),
'react-native': 'react-native-web',
},
plugins: [
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]),
],
},
module: {
strictExportPresence: true,
rules: [
{
test: /\.(js|jsx|mjs)$/,
enforce: 'pre',
use: [
{
options: {
formatter: eslintFormatter,
eslintPath: require.resolve('eslint'),
},
loader: require.resolve('eslint-loader'),
},
],
include: paths.appSrc,
},
{
oneOf: [
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: require.resolve('url-loader'),
options: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]',
},
},
// Process JS with Babel.
{
test: /\.(js|jsx|mjs)$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
plugins: [
['import', [{ libraryName: 'antd', style: true }]], // import less
],
compact: true,
},
},
{
test: /\.(less|css)$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"less-loader?{modifyVars:" + JSON.stringify(theme) + "}"
],
},
{
test: /\.(scss|sass)$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"sass-loader"
]
},
{
loader: require.resolve('file-loader'),
exclude: [/\.(js|jsx|mjs)$/,/\.(css|less)$/, /\.html$/, /\.json$/],
options: {
name: 'static/media/[name].[hash:8].[ext]',
},
},
],
},
],
},
optimization: {
runtimeChunk: {
name: 'manifest'
},
minimize: true,
noEmitOnErrors: true,
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: false
}),
new OptimizeCSSAssetsPlugin({})
],
splitChunks: {
minSize: 30000,
maxSize: 3000000,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
name: true,
cacheGroups: {
vendor: {
chunks: 'initial',
name: 'vendor',
test: 'vendor'
},
echarts: {
chunks: 'all',
name: 'echarts',
test: /[\\/]echarts[\\/]/,
}
}
}
},
plugins: [
new HtmlWebpackPlugin({
inject: true,
template: paths.appHtml,
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}),
new InterpolateHtmlPlugin(env.raw),
new webpack.DefinePlugin(env.stringified),
new webpack.NamedModulesPlugin(),
new webpack.optimize.OccurrenceOrderPlugin(true),
new MiniCssExtractPlugin({
filename: "css/[name].[hash].css",
chunkFilename: "css/[name].[hash].css"
}),
new ManifestPlugin({
fileName: 'asset-manifest.json',
}),
new SWPrecacheWebpackPlugin({
dontCacheBustUrlsMatching: /\.\w{8}\./,
filename: 'service-worker.js',
logger(message) {
if (message.indexOf('Total precache size is') === 0) {
return;
}
if (message.indexOf('Skipping static resource') === 0) {
return;
}
console.log(message);
},
minify: true,
navigateFallback: publicUrl + '/index.html',
navigateFallbackWhitelist: [/^(?!\/__).*/],
staticFileGlobsIgnorePatterns: [/\.map$/, /asset-manifest\.json$/],
}),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
],
node: {
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty',
},
};