|
9 | 9 |
|
10 | 10 | 'use strict'; |
11 | 11 |
|
12 | | -const webpack = require('webpack'); |
13 | | -const ExtractTextPlugin = require('extract-text-webpack-plugin'); |
14 | 12 | const extractText = require('./loaders/extract-text'); |
15 | | -const ManifestPlugin = require('./webpack/webpack-manifest-plugin'); |
16 | | -const DeleteUnusedEntriesJSPlugin = require('./webpack/delete-unused-entries-js-plugin'); |
17 | | -const AssetOutputDisplayPlugin = require('./friendly-errors/asset-output-display-plugin'); |
18 | | -const CleanWebpackPlugin = require('clean-webpack-plugin'); |
19 | | -const WebpackChunkHash = require('webpack-chunk-hash'); |
20 | | -const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin'); |
21 | | -const missingLoaderTransformer = require('./friendly-errors/transformers/missing-loader'); |
22 | | -const missingLoaderFormatter = require('./friendly-errors/formatters/missing-loader'); |
23 | | -const missingPostCssConfigTransformer = require('./friendly-errors/transformers/missing-postcss-config'); |
24 | | -const missingPostCssConfigFormatter = require('./friendly-errors/formatters/missing-postcss-config'); |
25 | | -const vueUnactivatedLoaderTransformer = require('./friendly-errors/transformers/vue-unactivated-loader-error'); |
26 | | -const vueUnactivatedLoaderFormatter = require('./friendly-errors/formatters/vue-unactivated-loader-error'); |
27 | 13 | const pathUtil = require('./config/path-util'); |
| 14 | +// loaders utils |
28 | 15 | const cssLoaderUtil = require('./loaders/css'); |
29 | 16 | const sassLoaderUtil = require('./loaders/sass'); |
30 | 17 | const lessLoaderUtil = require('./loaders/less'); |
31 | 18 | const babelLoaderUtil = require('./loaders/babel'); |
32 | 19 | const tsLoaderUtil = require('./loaders/typescript'); |
33 | 20 | const vueLoaderUtil = require('./loaders/vue'); |
| 21 | +// plugins utils |
| 22 | +const extractTextPluginUtil = require('./plugins/extract-text'); |
| 23 | +const deleteUnusedEntriesPluginUtil = require('./plugins/delete-unused-entries'); |
| 24 | +const manifestPluginUtil = require('./plugins/manifest'); |
| 25 | +const loaderOptionsPluginUtil = require('./plugins/loader-options'); |
| 26 | +const versioningPluginUtil = require('./plugins/versioning'); |
| 27 | +const variableProviderPluginUtil = require('./plugins/variable-provider'); |
| 28 | +const cleanPluginUtil = require('./plugins/clean'); |
| 29 | +const commonChunksPluginUtil = require('./plugins/common-chunks'); |
| 30 | +const definePluginUtil = require('./plugins/define'); |
| 31 | +const uglifyPluginUtil = require('./plugins/uglify'); |
| 32 | +const friendlyErrorPluginUtil = require('./plugins/friendly-errors'); |
| 33 | +const assetOutputDisplay = require('./plugins/asset-output-display'); |
34 | 34 |
|
35 | 35 | class ConfigGenerator { |
36 | 36 | /** |
@@ -180,173 +180,32 @@ class ConfigGenerator { |
180 | 180 | buildPluginsConfig() { |
181 | 181 | let plugins = []; |
182 | 182 |
|
183 | | - /* |
184 | | - * All CSS/SCSS content (due to the loaders above) will be |
185 | | - * extracted into an [entrypointname].css files. The result |
186 | | - * is that NO css will be inlined, *except* CSS that is required |
187 | | - * in an async way (e.g. via require.ensure()). |
188 | | - * |
189 | | - * This may not be ideal in some cases, but it's at least |
190 | | - * predictable. It means that you must manually add a |
191 | | - * link tag for an entry point's CSS (unless no CSS file |
192 | | - * was imported - in which case no CSS file will be dumped). |
193 | | - */ |
194 | | - plugins.push(new ExtractTextPlugin({ |
195 | | - filename: this.webpackConfig.useVersioning ? '[name].[contenthash].css' : '[name].css', |
196 | | - // if true, async CSS (e.g. loaded via require.ensure()) |
197 | | - // is extracted to the entry point CSS. If false, it's |
198 | | - // inlined in the AJAX-loaded .js file. |
199 | | - allChunks: false |
200 | | - })); |
| 183 | + extractTextPluginUtil(plugins, this.webpackConfig); |
201 | 184 |
|
202 | 185 | // register the pure-style entries that should be deleted |
203 | | - plugins.push(new DeleteUnusedEntriesJSPlugin( |
204 | | - // transform into an Array |
205 | | - [... this.webpackConfig.styleEntries.keys()] |
206 | | - )); |
207 | | - |
208 | | - /* |
209 | | - * Dump the manifest.json file |
210 | | - */ |
211 | | - let manifestPrefix = this.webpackConfig.manifestKeyPrefix; |
212 | | - if (null === manifestPrefix) { |
213 | | - // by convention, we remove the opening slash on the manifest keys |
214 | | - manifestPrefix = this.webpackConfig.publicPath.replace(/^\//,''); |
215 | | - } |
216 | | - plugins.push(new ManifestPlugin({ |
217 | | - basePath: manifestPrefix, |
218 | | - // guarantee the value uses the public path (or CDN public path) |
219 | | - publicPath: this.webpackConfig.getRealPublicPath(), |
220 | | - // always write a manifest.json file, even with webpack-dev-server |
221 | | - writeToFileEmit: true, |
222 | | - })); |
223 | | - |
224 | | - /* |
225 | | - * This section is a bit mysterious. The "minimize" |
226 | | - * true is read and used to minify the CSS. |
227 | | - * But as soon as this plugin is included |
228 | | - * at all, SASS begins to have errors, until the context |
229 | | - * and output options are specified. At this time, I'm |
230 | | - * not totally sure what's going on here |
231 | | - * https://github.com/jtangelder/sass-loader/issues/285 |
232 | | - */ |
233 | | - plugins.push(new webpack.LoaderOptionsPlugin({ |
234 | | - debug: !this.webpackConfig.isProduction(), |
235 | | - options: { |
236 | | - context: this.webpackConfig.getContext(), |
237 | | - output: { path: this.webpackConfig.outputPath } |
238 | | - } |
239 | | - })); |
240 | | - |
241 | | - /* |
242 | | - * With versioning, the "chunkhash" used in the filenames and |
243 | | - * the module ids (i.e. the internal names of modules that |
244 | | - * are required) become important. Specifically: |
245 | | - * |
246 | | - * 1) If the contents of a module don't change, then you don't want its |
247 | | - * internal module id to change. Otherwise, whatever file holds the |
248 | | - * webpack "manifest" will change because the module id will change. |
249 | | - * Solved by HashedModuleIdsPlugin or NamedModulesPlugin |
250 | | - * |
251 | | - * 2) Similarly, if the final contents of a file don't change, |
252 | | - * then we also don't want that file to have a new filename. |
253 | | - * The WebpackChunkHash() handles this, by making sure that |
254 | | - * the chunkhash is based off of the file contents. |
255 | | - * |
256 | | - * Even in the webpack community, the ideal setup seems to be |
257 | | - * a bit of a mystery: |
258 | | - * * https://github.com/webpack/webpack/issues/1315 |
259 | | - * * https://github.com/webpack/webpack.js.org/issues/652#issuecomment-273324529 |
260 | | - * * https://webpack.js.org/guides/caching/#deterministic-hashes |
261 | | - */ |
262 | | - if (this.webpackConfig.isProduction()) { |
263 | | - // shorter, and obfuscated module ids (versus NamedModulesPlugin) |
264 | | - // makes the final assets *slightly* larger, but prevents contents |
265 | | - // from sometimes changing when nothing really changed |
266 | | - plugins.push(new webpack.HashedModuleIdsPlugin()); |
267 | | - } else { |
268 | | - // human-readable module names, helps debug in HMR |
269 | | - // enable always when not in production for consistency |
270 | | - plugins.push(new webpack.NamedModulesPlugin()); |
271 | | - } |
| 186 | + deleteUnusedEntriesPluginUtil(plugins, this.webpackConfig); |
272 | 187 |
|
273 | | - if (this.webpackConfig.useVersioning) { |
274 | | - // enables the [chunkhash] ability |
275 | | - plugins.push(new WebpackChunkHash()); |
276 | | - } |
| 188 | + // Dump the manifest.json file |
| 189 | + manifestPluginUtil(plugins, this.webpackConfig); |
277 | 190 |
|
278 | | - if (Object.keys(this.webpackConfig.providedVariables).length > 0) { |
279 | | - plugins = plugins.concat([ |
280 | | - new webpack.ProvidePlugin(this.webpackConfig.providedVariables) |
281 | | - ]); |
282 | | - } |
| 191 | + loaderOptionsPluginUtil(plugins, this.webpackConfig); |
283 | 192 |
|
284 | | - if (this.webpackConfig.cleanupOutput) { |
285 | | - plugins.push( |
286 | | - new CleanWebpackPlugin(['**/*'], { |
287 | | - root: this.webpackConfig.outputPath, |
288 | | - verbose: false, |
289 | | - }) |
290 | | - ); |
291 | | - } |
| 193 | + versioningPluginUtil(plugins, this.webpackConfig); |
292 | 194 |
|
293 | | - // if we're extracting a vendor chunk, set it up! |
294 | | - if (this.webpackConfig.sharedCommonsEntryName) { |
295 | | - plugins = plugins.concat([ |
296 | | - new webpack.optimize.CommonsChunkPlugin({ |
297 | | - name: [ |
298 | | - this.webpackConfig.sharedCommonsEntryName, |
299 | | - /* |
300 | | - * Always dump a 2nd file - manifest.json that |
301 | | - * will contain the webpack manifest information. |
302 | | - * This changes frequently, and without this line, |
303 | | - * it would be packaged inside the "shared commons entry" |
304 | | - * file - e.g. vendor.js, which would prevent long-term caching. |
305 | | - */ |
306 | | - 'manifest' |
307 | | - ], |
308 | | - minChunks: Infinity, |
309 | | - }), |
310 | | - ]); |
311 | | - } |
| 195 | + variableProviderPluginUtil(plugins, this.webpackConfig); |
312 | 196 |
|
313 | | - if (this.webpackConfig.isProduction()) { |
314 | | - plugins = plugins.concat([ |
315 | | - new webpack.DefinePlugin({ |
316 | | - 'process.env': { |
317 | | - NODE_ENV: '"production"' |
318 | | - } |
319 | | - }), |
320 | | - |
321 | | - // todo - options here should be configurable |
322 | | - new webpack.optimize.UglifyJsPlugin({ |
323 | | - sourceMap: this.webpackConfig.useSourceMaps |
324 | | - }) |
325 | | - ]); |
326 | | - } |
| 197 | + cleanPluginUtil(plugins, this.webpackConfig, ['**/*']); |
327 | 198 |
|
328 | | - const friendlyErrorsPlugin = new FriendlyErrorsWebpackPlugin({ |
329 | | - clearConsole: false, |
330 | | - additionalTransformers: [ |
331 | | - missingLoaderTransformer, |
332 | | - missingPostCssConfigTransformer, |
333 | | - vueUnactivatedLoaderTransformer |
334 | | - ], |
335 | | - additionalFormatters: [ |
336 | | - missingLoaderFormatter, |
337 | | - missingPostCssConfigFormatter, |
338 | | - vueUnactivatedLoaderFormatter |
339 | | - ], |
340 | | - compilationSuccessInfo: { |
341 | | - messages: [] |
342 | | - } |
343 | | - }); |
344 | | - plugins.push(friendlyErrorsPlugin); |
| 199 | + commonChunksPluginUtil(plugins, this.webpackConfig); |
345 | 200 |
|
346 | | - if (!this.webpackConfig.useDevServer()) { |
347 | | - const outputPath = pathUtil.getRelativeOutputPath(this.webpackConfig); |
348 | | - plugins.push(new AssetOutputDisplayPlugin(outputPath, friendlyErrorsPlugin)); |
349 | | - } |
| 201 | + // todo - options here should be configurable |
| 202 | + definePluginUtil(plugins, this.webpackConfig); |
| 203 | + uglifyPluginUtil(plugins, this.webpackConfig); |
| 204 | + |
| 205 | + let friendlyErrorPlugin = friendlyErrorPluginUtil(); |
| 206 | + plugins.push(friendlyErrorPlugin); |
| 207 | + |
| 208 | + assetOutputDisplay(plugins, this.webpackConfig, friendlyErrorPlugin); |
350 | 209 |
|
351 | 210 | this.webpackConfig.plugins.forEach(function(plugin) { |
352 | 211 | plugins.push(plugin); |
|
0 commit comments