1 |
|
2 |
|
3 | const path = require('path');
|
4 | const fs = require('fs');
|
5 | const webpack = require('webpack');
|
6 | const HtmlWebpackPlugin = require('html-webpack-plugin');
|
7 | const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
|
8 | const TerserPlugin = require('terser-webpack-plugin');
|
9 | const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
10 | const CopyWebpackPlugin = require('copy-webpack-plugin');
|
11 | const loaders = require('./loaders');
|
12 | const babelPreset = require('./babel-preset');
|
13 | const resolveModule = require('./helpers/resolve-module');
|
14 | const html = require('./html');
|
15 |
|
16 | process.noDeprecation = true;
|
17 |
|
18 | const 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 |
|
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 |
|
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 |
|
92 |
|
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 |
|
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`,
|
149 | from: '**/*',
|
150 | to: 'static'
|
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 |
|
166 |
|
167 |
|
168 |
|
169 |
|
170 | ecma: 8
|
171 | },
|
172 | compress: {
|
173 | ecma: 5,
|
174 | warnings: false,
|
175 |
|
176 |
|
177 |
|
178 |
|
179 | comparisons: false
|
180 | },
|
181 | mangle: {
|
182 | safari10: true
|
183 | },
|
184 | output: {
|
185 | ecma: 5,
|
186 | comments: false,
|
187 |
|
188 |
|
189 | ascii_only: true
|
190 | }
|
191 | },
|
192 |
|
193 |
|
194 | parallel: true,
|
195 |
|
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 |
|
208 | module.exports = plugin;
|