const crypto = require('crypto'); const path = require('path'); const boolean = require('boolean'); const dotenv = require('dotenv'); const ESLintPlugin = require('eslint-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const without = require('lodash/without'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const webpack = require('webpack'); const babelConfig = require('./babel.config'); const buildConfig = require('./build.config'); const pkg = require('./src/package.json'); dotenv.config({ path: path.resolve('webpack.config.production.env'), }); // Use publicPath for production const publicPath = ((payload) => { const algorithm = 'sha1'; const buf = String(payload); const hash = crypto.createHash(algorithm).update(buf).digest('hex'); return '/' + hash.substring(0, 8) + '/'; // 8 digits })(pkg.version); const buildVersion = pkg.version; module.exports = { mode: 'production', cache: true, target: 'web', context: path.resolve(__dirname, 'src/app'), devtool: 'cheap-module-source-map', entry: { main: [ path.resolve(__dirname, 'src/app/index.jsx') ], }, output: { path: path.resolve(__dirname, 'dist/cncjs/app'), filename: '[name].[contenthash].bundle.js', publicPath: publicPath }, module: { rules: [ { test: /\.jsx?$/, loader: 'babel-loader', options: { ...babelConfig(), }, exclude: /node_modules/ }, { test: /\.styl$/, use: [ MiniCssExtractPlugin.loader, { loader: 'css-loader', options: { localsConvention: 'camelCase', modules: { localIdentName: '[path][name]__[local]--[hash:base64:5]', }, importLoaders: 1, } }, { loader: 'stylus-loader', options: { stylusOptions: { use: ['nib'], import: ['nib'], } } } ], exclude: [ path.resolve(__dirname, 'src/app/styles'), ] }, { test: /\.styl$/, use: [ MiniCssExtractPlugin.loader, { loader: 'css-loader', options: { localsConvention: 'camelCase', modules: false, } }, 'stylus-loader', ], include: [ path.resolve(__dirname, 'src/app/styles'), ] }, { test: /\.css$/, use: [ 'style-loader', 'css-loader', ] }, { test: /\.(png|jpg|svg)$/, loader: 'url-loader', options: { limit: 8192, esModule: false } }, { test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'url-loader', options: { limit: 10000, mimetype: 'application/font-woff', esModule: false } }, { test: /\.(ttf|eot)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'file-loader', options: { esModule: false } } ].filter(Boolean) }, optimization: { minimize: true, }, plugins: [ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify('production'), BUILD_VERSION: JSON.stringify(buildVersion), LANGUAGES: JSON.stringify(buildConfig.languages), TRACKING_ID: JSON.stringify(buildConfig.analytics.trackingId), } }), new webpack.ContextReplacementPlugin( /moment[\/\\]locale$/, new RegExp('^\./(' + without(buildConfig.languages, 'en').join('|') + ')$') ), new ESLintPlugin({ extensions: ['js', 'jsx'], exclude: [ '/node_modules/', ], }), new MiniCssExtractPlugin({ filename: '[name].css', chunkFilename: '[id].css', }), new HtmlWebpackPlugin({ filename: 'index.hbs', template: path.resolve(__dirname, 'index.hbs'), }) ], resolve: { alias: { '@app': path.resolve(__dirname, 'src/app'), }, extensions: ['.js', '.jsx'], fallback: { crypto: require.resolve('crypto-browserify'), fs: false, net: false, path: require.resolve('path-browserify'), stream: require.resolve('stream-browserify'), timers: require.resolve('timers-browserify'), tls: false, }, modules: [ path.resolve(__dirname, 'src'), 'node_modules' ], }, };