const path = require('path'); const webpack = require("webpack"); const ExtractTextPlugin = require("extract-text-webpack-plugin"); const UglifyJSPlugin = require('uglifyjs-webpack-plugin'); const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); function run() { const isProd = process.env.NODE_ENV === 'production'; const runMode = isProd ? 'prod' : 'dev'; const needAnalyze = process.env.ANALYZE; const isServer = process.env.IS_SERVER === '1'; const needOptimize = process.env.OPTIMIZE === '1'; console.log('is production: %s, NODE_ENV: "%s", isServer: %s', isProd, process.env.NODE_ENV, isServer); const lessLoaderImpl = `less-loader?{"sourceMap":true}`; const cssLoaders = ['css-loader', 'sass-loader', lessLoaderImpl]; const extractCss = (isProd || isServer); const cssLoader = extractCss ? ExtractTextPlugin.extract({ fallback: 'style-loader', use: cssLoaders, }) : ['style-loader', 'css-loader']; const sassCommonLoaders = ['css-loader', 'sass-loader']; const sassLoader = extractCss ? ExtractTextPlugin.extract(sassCommonLoaders) : ['style-loader'].concat(sassCommonLoaders); const lessLoader = (isProd || isServer) ? ExtractTextPlugin.extract({ fallback: 'style-loader', use: cssLoaders, }) : ['style-loader', 'css-loader', lessLoaderImpl]; var api_host = process.env.API_HOST || (isProd ? `https://api.golangci.com` : 'https://api.dev.golangci.com'); const host = process.env.HOST || (isProd ? 'https://golangci.com' : 'https://dev.golangci.com'); const runSuffixCommon = `${runMode}.${isServer ? "server" : "client"}.[name]`; const runSuffixForChunk = `${runSuffixCommon}${(isProd && !isServer) ? ".[chunkhash:6]" : ""}`; const runSuffixForCss = `${runSuffixCommon}${(isProd && !isServer) ? ".[md5:contenthash:hex:20]" : ""}`; const runSuffixForServerJs = runSuffixCommon; const runSuffixForFiles = runSuffixForChunk; var plugins = [ new ForkTsCheckerWebpackPlugin(), new webpack.LoaderOptionsPlugin({ minimize: isProd, options: { tslint: { emitErrors: true, failOnHint: true, }, }, }), new webpack.DefinePlugin({ __SERVER__: isServer, __CLIENT__: !isServer, __DEV__: !isProd, API_HOST: `"${api_host}"`, HOST: `"${host}"`, "process.env": { NODE_ENV: JSON.stringify(process.env.NODE_ENV), } }), new webpack.ContextReplacementPlugin( /moment[\/\\]locale$/, /ru/ ), ]; if ((isProd || needAnalyze) && !isServer) { plugins.push(new webpack.optimize.OccurrenceOrderPlugin(true)); } if (isProd || needOptimize) { plugins.push(new UglifyJSPlugin({ uglifyOptions: { ie8: true, safari10: true, ecma: 5, warnings: true, }, sourceMap: true, })); } if (isServer || isProd) { plugins.push( new ExtractTextPlugin({ filename: `${runSuffixForCss}.css`, allChunks: true, }) ); } if (!isServer && isProd) { const HtmlWebpackPlugin = require('html-webpack-plugin'); plugins.push( new HtmlWebpackPlugin({ template: './src/webpack.partial.ejs', filename: './src/webpack.partial.html', inject: false, cache: true, }) ); } if (needAnalyze) { var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; plugins.push(new BundleAnalyzerPlugin()); } const outPath = path.join(__dirname, process.env.DIST_DIR || ('dist/' + runMode)); let loadRules = []; if (isProd) { loadRules.push({ test: /\.tsx?$/, enforce: "pre", loader: 'tslint-loader', exclude: [/node_modules/], }); } loadRules = loadRules.concat([ { test: /\.tsx?$/, exclude: [/node_modules/], use: { loader: "babel-loader", options: { cacheDirectory: true, babelrc: false, presets: [ [ "@babel/preset-env", { targets: { browsers: "> 1%" } } ], "@babel/preset-typescript", "@babel/preset-react", ], plugins: [ "@babel/plugin-transform-regenerator", "transform-class-properties", ["import", {"libraryName": "antd"}], "react-hot-loader/babel" ] } } }, { test: /\.css$/, loader: cssLoader, }, { test: /\.scss$/, loader: sassLoader, }, { test: /\.less$/, loader: lessLoader, }, { test: /\.(png|jpg|jpeg|gif)$/, use: [ { loader: "file-loader", options: { outputPath: "images/", publicPath: isProd ? "/js/dist/images/" : undefined, }, } ] }, { test: /\.svg$/, use: [ { loader: "babel-loader" }, { loader: "react-svg-loader", options: { es5: true, svgo: { plugins: [ {removeAttrs: {attrs: 'xmlns.*'},}, {removeTitle: false}, {cleanupIDs: false}, ] } } } ], }, { enforce: "pre", test: /\.(j|t)sx?$/, exclude: [ /node_modules\/mutationobserver-shim/g, /node_modules\/react-component-octicons/g, ], loader: "source-map-loader" }, { test: /.(ttf|otf|eot|woff(2)?)(\?[a-z0-9]+)?$/, use: [{ loader: 'file-loader', options: { name: `${runSuffixForFiles}.[ext]`, outputPath: 'fonts/', // where the fonts will go publicPath: './' // override the default path } }] }, ]); // controls source map generation mode const devtool = isServer ? undefined : (isProd ? "source-map" : "eval-source-map"); var commonConfig = { devServer: { open: true, // to open the local server in browser contentBase: path.join(__dirname, 'src', 'dev'), historyApiFallback: true, }, plugins: plugins, devtool: devtool, resolve: { // Add '.ts' and '.tsx' as resolvable extensions. extensions: [ ".ts", ".tsx", ".scss", ".less", ".css", ".js", ".jsx", ".json", ".svg", ], modules: [ path.resolve('./src'), path.resolve('./node_modules'), ], }, module: { rules: loadRules, }, } var config; if (isServer) { config = Object.assign({}, commonConfig, { name: 'server-side rendering', entry: { app: ['@babel/polyfill', './src/server'], }, target: 'node', output: { path: outPath, filename: `${runSuffixForServerJs}.js`, libraryTarget: 'commonjs2', }, }); } else { config = Object.assign({}, commonConfig, { entry: { app: ['@babel/polyfill', './src/client'], }, name: 'browser', output: { filename: `${runSuffixForChunk}.js`, path: outPath, publicPath: '/', }, }); if (isProd || needOptimize) { config.optimization = { splitChunks: { cacheGroups: { default: false, vendors: false, // vendor chunk vendor: { // sync + async chunks chunks: 'all', // import file path containing node_modules test: /node_modules/, } } } }; } } console.info(config); module.exports = config; } try { run(); } catch (e) { console.error("exception:", e); }