UNPKG

6.1 kBJavaScriptView Raw
1/* eslint-disable import/no-dynamic-require */
2/* eslint-disable global-require */
3const path = require('path');
4const fs = require('fs');
5const webpack = require('webpack');
6const HtmlWebpackPlugin = require('html-webpack-plugin');
7const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
8const TerserPlugin = require('terser-webpack-plugin');
9const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
10const CopyWebpackPlugin = require('copy-webpack-plugin');
11const loaders = require('./loaders');
12const babelPreset = require('./babel-preset');
13const resolveModule = require('./helpers/resolve-module');
14const html = require('./html');
15
16process.noDeprecation = true;
17
18const plugin = settings => {
19 const babelrcPath = path.join(settings.project(), '.babelrc');
20 const babelrcExists = fs.existsSync(babelrcPath);
21 const resolveApp = relativePath => path.resolve(settings.app(), relativePath);
22
23 function getVersion() {
24 return settings.pkg().version || 'N/A';
25 }
26
27 const config = {
28 mode: 'production',
29
30 context: settings.app(),
31
32 entry: {
33 index: [
34 require.resolve('react-app-polyfill/ie11'),
35 require.resolve('navigator.sendbeacon'),
36 resolveModule(resolveApp, 'index')
37 ]
38 },
39
40 optimization: {
41 splitChunks: {
42 cacheGroups: {
43 styles: {
44 name: 'styles',
45 test: /\.css$/,
46 chunks: 'all',
47 enforce: true
48 },
49 commons: {
50 chunks: 'initial',
51 minChunks: 2
52 },
53 vendor: {
54 test: /node_modules/,
55 chunks: 'initial',
56 name: 'vendor',
57 priority: 10,
58 enforce: true
59 }
60 }
61 },
62 minimizer: []
63 },
64
65 output: {
66 path: settings.output(),
67 filename: settings.fileName(),
68 chunkFilename: settings.chunkFileName(),
69 // TODO: remove this when upgrading to webpack 5
70 futureEmitAssets: true,
71 devtoolModuleFilenameTemplate: info =>
72 `webpack:///${path.relative(settings.project(), info.absoluteResourcePath)}${
73 info.loaders ? `?${info.loaders}` : ''
74 }`
75 },
76
77 devtool: settings.sourceMap(),
78
79 resolve: {
80 // Tell webpack what directories should be searched when resolving modules
81 modules: [
82 settings.app(),
83 'node_modules',
84 path.join(settings.project(), 'node_modules'),
85 path.join(__dirname, 'node_modules')
86 ],
87 symlinks: true,
88 extensions: ['.js', '.jsx', '.ts', '.tsx', '.json', '.css', 'scss']
89 },
90
91 // This set of options is identical to the resolve property set above,
92 // but is used only to resolve webpack's loader packages.
93 resolveLoader: {
94 modules: [path.join(settings.project(), 'node_modules'), path.join(__dirname, 'node_modules')],
95 symlinks: true
96 },
97
98 module: {
99 rules: [
100 {
101 test: /\.(js|mjs|jsx|ts|tsx)$/,
102 include: settings.include(),
103 use: [
104 {
105 loader: 'babel-loader',
106 options: {
107 presets: [babelPreset],
108 cacheDirectory: settings.isDevelopment(),
109 babelrc: babelrcExists
110 }
111 }
112 ]
113 },
114 loaders.css.production,
115 loaders.scss.production,
116 loaders.fonts,
117 loaders.images
118 ]
119 },
120 plugins: [
121 new webpack.DefinePlugin(settings.globals()),
122
123 new webpack.BannerPlugin({
124 banner: `APP_VERSION=${JSON.stringify(getVersion())};`,
125 test: /\.jsx?/,
126 raw: true,
127 entryOnly: true
128 }),
129
130 new webpack.BannerPlugin({
131 banner: `v${getVersion()} - ${new Date().toJSON()}`
132 }),
133
134 new HtmlWebpackPlugin(html(settings)),
135
136 // Ignore all the moment local files
137 new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
138
139 new CaseSensitivePathsPlugin(),
140
141 new loaders.MiniCssExtractPlugin({
142 filename: 'css/[name]-[contenthash].css'
143 }),
144
145 new CopyWebpackPlugin(
146 [
147 {
148 context: `${settings.app()}/static`, // copy from this directory
149 from: '**/*', // copy all files
150 to: 'static' // copy into {output}/static folder
151 }
152 ],
153 {
154 logLevel: 'warn'
155 }
156 )
157 ]
158 };
159
160 if (settings.isProduction()) {
161 config.optimization.minimizer.push(
162 new TerserPlugin({
163 terserOptions: {
164 parse: {
165 // we want terser to parse ecma 8 code. However, we don't want it
166 // to apply any minfication steps that turns valid ecma 5 code
167 // into invalid ecma 5 code. This is why the 'compress' and 'output'
168 // sections only apply transformations that are ecma 5 safe
169 // https://github.com/facebook/create-react-app/pull/4234
170 ecma: 8
171 },
172 compress: {
173 ecma: 5,
174 warnings: false,
175 // Disabled because of an issue with Uglify breaking seemingly valid code:
176 // https://github.com/facebook/create-react-app/issues/2376
177 // Pending further investigation:
178 // https://github.com/mishoo/UglifyJS2/issues/2011
179 comparisons: false
180 },
181 mangle: {
182 safari10: true
183 },
184 output: {
185 ecma: 5,
186 comments: false,
187 // Turned on because emoji and regex is not minified properly using default
188 // https://github.com/facebook/create-react-app/issues/2488
189 ascii_only: true
190 }
191 },
192 // Use multi-process parallel running to improve the build speed
193 // Default number of concurrent runs: os.cpus().length - 1
194 parallel: true,
195 // Enable file caching
196 cache: true,
197 sourceMap: true
198 }),
199 new OptimizeCSSAssetsPlugin({
200 cssProcessorOptions: { zindex: false, reduceIdents: false }
201 })
202 );
203 }
204
205 return config;
206};
207
208module.exports = plugin;