UNPKG

5.76 kBJavaScriptView Raw
1import path from 'path';
2import webpack from 'webpack';
3import atImport from 'postcss-import';
4import postcssPresetEnv from 'postcss-preset-env';
5import HtmlWebpackPlugin from 'html-webpack-plugin';
6import TerserPlugin from 'terser-webpack-plugin';
7import MiniCssExtractPlugin from 'mini-css-extract-plugin';
8import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin';
9
10import palette from './config/palette';
11import media from './config/media';
12import env from './config/env';
13
14const terserDevOptions = {
15 terserOptions: {
16 ecma: 5,
17 compress: {
18 warnings: false,
19 comparisons: false,
20 },
21 output: {
22 comments: false,
23 ascii_only: false,
24 },
25 },
26};
27
28const terserProductionOptions = {
29 terserOptions: {
30 ecma: 5,
31 parse: {},
32 compress: {
33 warnings: false,
34 // Disabled because of an issue with Uglify breaking seemingly valid code:
35 // https://github.com/facebook/create-react-app/issues/2376
36 // Pending further investigation:
37 // https://github.com/mishoo/UglifyJS2/issues/2011
38 comparisons: false,
39 },
40 mangle: true,
41 output: {
42 comments: false,
43 // Turned on because emoji and regex is not minified properly using default
44 // https://github.com/facebook/create-react-app/issues/2488
45 ascii_only: true,
46 },
47 },
48 // Use multi-process parallel running to improve the build speed
49 // Default number of concurrent runs: os.cpus().length - 1
50 parallel: true,
51 // Enable file caching
52 cache: true,
53 sourceMap: false,
54};
55
56const webpackProdConfig = {
57 devtool: 'source-map',
58 mode: process.env.NODE_ENV,
59 entry: {
60 app: './src/index.js',
61 },
62 output: {
63 path: path.join(__dirname, '_public'),
64 filename: '[name].[chunkhash].js',
65 chunkFilename: '[name].[chunkhash].chunk.js',
66 publicPath: '/',
67 },
68 plugins: [
69 new webpack.DefinePlugin({
70 'process.env': env,
71 }),
72
73 new HtmlWebpackPlugin({
74 template: './src/index.html',
75 minify: {
76 removeComments: true,
77 collapseWhitespace: true,
78 removeRedundantAttributes: true,
79 useShortDoctype: true,
80 removeEmptyAttributes: true,
81 removeStyleLinkTypeAttributes: true,
82 removeScriptTypeAttributes: true,
83 keepClosingSlash: true,
84 minifyJS: true,
85 minifyCSS: true,
86 minifyURLs: true,
87 },
88 inject: true,
89 showErrors: false,
90 filename: 'index.html',
91 chunksSortMode: 'dependency',
92 }),
93
94 new MiniCssExtractPlugin({
95 // Options similar to the same options in webpackOptions.output
96 // both options are optional
97 filename: '[name].[hash].css',
98 chunkFilename: '[id].[hash].css',
99 }),
100
101 new webpack.HashedModuleIdsPlugin(),
102 ],
103 optimization: {
104 minimizer: [
105 new TerserPlugin(
106 process.env.NODE_ENV === 'production' ? terserProductionOptions : terserDevOptions,
107 ),
108 ],
109 // Automatically split vendor and commons
110 // https://hackernoon.com/the-100-correct-way-to-split-your-chunks-with-webpack-f8a9df5b7758
111 splitChunks: {
112 chunks: 'all',
113 maxInitialRequests: Infinity,
114 minSize: 0,
115 cacheGroups: {
116 vendor: {
117 test: /[\\/]node_modules[\\/]/,
118 name: 'vendors',
119 chunks: 'all',
120 },
121 },
122 },
123 runtimeChunk: 'single',
124 },
125 module: {
126 rules: [
127 {
128 test: /\.js?$/,
129 include: [path.join(__dirname, 'src')],
130 exclude: path.join(__dirname, 'node_modules'),
131 loader: 'babel-loader',
132 options: {
133 presets: [
134 ['@babel/preset-env', { loose: true, modules: false, useBuiltIns: 'usage', corejs: 2 }],
135 '@babel/preset-react',
136 ],
137 plugins: [
138 '@babel/plugin-syntax-dynamic-import',
139 '@babel/plugin-syntax-import-meta',
140 '@babel/plugin-proposal-class-properties',
141 '@babel/plugin-proposal-json-strings',
142 '@babel/plugin-transform-react-constant-elements',
143 ],
144 babelrc: false,
145 },
146 },
147 {
148 test: /\.css$/,
149 include: path.join(__dirname, 'src'),
150 use: [
151 MiniCssExtractPlugin.loader,
152 {
153 loader: 'css-loader',
154 options: {
155 sourceMap: process.env.NODE_ENV !== 'production',
156 camelCase: true,
157 modules: true,
158 importLoaders: 1,
159 localIdentName: '[name]__[local]___[hash:base64:5]',
160 },
161 },
162 {
163 loader: 'postcss-loader',
164 options: {
165 sourceMap: process.env.NODE_ENV !== 'production' ? 'inline' : false,
166 plugins: () => [
167 atImport(),
168 postcssPresetEnv({
169 stage: 0,
170 importFrom: [
171 {
172 customMedia: media,
173 customProperties: palette,
174 },
175 ],
176 preserve: false,
177 }),
178 ],
179 },
180 },
181 ],
182 },
183 {
184 test: /\.css$/,
185 include: path.join(__dirname, 'node_modules'),
186 use: [
187 MiniCssExtractPlugin.loader,
188 {
189 loader: 'css-loader',
190 options: {
191 sourceMap: process.env.NODE_ENV !== 'production',
192 },
193 },
194 ],
195 },
196 {
197 test: /\.(jpe?g|png|gif)$/,
198 include: path.join(__dirname, 'src'),
199 loader: 'url-loader',
200 options: {
201 limit: 10000,
202 name: './assets/[name]__[hash].[ext]',
203 },
204 },
205 {
206 test: /^(?!.*\.inline\.svg$).*\.svg$/,
207 include: path.join(__dirname, 'src'),
208 use: [
209 '@svgr/webpack',
210 {
211 loader: 'url-loader',
212 options: {
213 limit: 10000,
214 name: './assets/[name]__[hash].[ext]',
215 },
216 },
217 ],
218 },
219 {
220 test: /\.inline.svg$/,
221 include: path.join(__dirname, 'src'),
222 loader: '@svgr/webpack',
223 options: {
224 svgoConfig: {
225 plugins: [{ cleanupIDs: false }, { removeViewBox: false }],
226 },
227 },
228 },
229 ],
230 },
231 node: {
232 fs: 'empty',
233 },
234 resolve: {
235 modules: ['node_modules'],
236 },
237};
238
239// Minify and optimize the CSS
240if (process.env.NODE_ENV === 'production') {
241 webpackProdConfig.plugins.push(new OptimizeCSSAssetsPlugin({}));
242}
243
244export default webpackProdConfig;