Skip to content

Commit 65adfdc

Browse files
davidmpazweaverryan
authored andcommitted
Refactor plugin configuration
1 parent 9c5557d commit 65adfdc

13 files changed

+461
-172
lines changed

lib/config-generator.js

+31-172
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,28 @@
99

1010
'use strict';
1111

12-
const webpack = require('webpack');
13-
const ExtractTextPlugin = require('extract-text-webpack-plugin');
1412
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');
2713
const pathUtil = require('./config/path-util');
14+
// loaders utils
2815
const cssLoaderUtil = require('./loaders/css');
2916
const sassLoaderUtil = require('./loaders/sass');
3017
const lessLoaderUtil = require('./loaders/less');
3118
const babelLoaderUtil = require('./loaders/babel');
3219
const tsLoaderUtil = require('./loaders/typescript');
3320
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');
3434

3535
class ConfigGenerator {
3636
/**
@@ -180,173 +180,32 @@ class ConfigGenerator {
180180
buildPluginsConfig() {
181181
let plugins = [];
182182

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);
201184

202185
// 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);
272187

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);
277190

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);
283192

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);
292194

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);
312196

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, ['**/*']);
327198

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);
345200

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);
350209

351210
this.webpackConfig.plugins.forEach(function(plugin) {
352211
plugins.push(plugin);

lib/plugins/asset-output-display.js

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* This file is part of the Symfony package.
3+
*
4+
* (c) Fabien Potencier <[email protected]>
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
'use strict';
11+
12+
const pathUtil = require('../config/path-util');
13+
const AssetOutputDisplayPlugin = require('../friendly-errors/asset-output-display-plugin');
14+
15+
/**
16+
* Updates plugins array passed adding AssetOutputDisplayPlugin instance
17+
*
18+
* @param {Array} plugins
19+
* @param {WebpackConfig} webpackConfig
20+
* @param {FriendlyErrorsWebpackPlugin} friendlyErrorsPlugin
21+
* @return {void}
22+
*/
23+
module.exports = function(plugins, webpackConfig, friendlyErrorsPlugin) {
24+
if (webpackConfig.useDevServer()) {
25+
return;
26+
}
27+
28+
const outputPath = pathUtil.getRelativeOutputPath(webpackConfig);
29+
plugins.push(new AssetOutputDisplayPlugin(outputPath, friendlyErrorsPlugin));
30+
};

lib/plugins/clean.js

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* This file is part of the Symfony package.
3+
*
4+
* (c) Fabien Potencier <[email protected]>
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
'use strict';
11+
12+
const CleanWebpackPlugin = require('clean-webpack-plugin');
13+
14+
/**
15+
* Updates plugins array passed adding CleanWebpackPlugin instance
16+
*
17+
* @param {Array} plugins to push to
18+
* @param {WebpackConfig} webpackConfig read only variable
19+
* @param {Array} paths to clean
20+
* @param {Object} cleanUpOptions
21+
* @return {void}
22+
*/
23+
module.exports = function(plugins, webpackConfig, paths, cleanUpOptions = {}) {
24+
25+
if (!webpackConfig.cleanupOutput) {
26+
return;
27+
}
28+
29+
let config = Object.assign({}, cleanUpOptions, {
30+
root: webpackConfig.outputPath,
31+
verbose: false,
32+
});
33+
34+
plugins.push(new CleanWebpackPlugin(paths, config));
35+
};

lib/plugins/common-chunks.js

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* This file is part of the Symfony package.
3+
*
4+
* (c) Fabien Potencier <[email protected]>
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
'use strict';
11+
12+
const webpack = require('webpack');
13+
14+
/**
15+
* @param {Array} plugins
16+
* @param {WebpackConfig} webpackConfig
17+
* @return {void}
18+
*/
19+
module.exports = function(plugins, webpackConfig) {
20+
21+
if (!webpackConfig.sharedCommonsEntryName) {
22+
return;
23+
}
24+
25+
// if we're extracting a vendor chunk, set it up!
26+
plugins.push(new webpack.optimize.CommonsChunkPlugin({
27+
name: [
28+
webpackConfig.sharedCommonsEntryName,
29+
/*
30+
* Always dump a 2nd file - manifest.json that
31+
* will contain the webpack manifest information.
32+
* This changes frequently, and without this line,
33+
* it would be packaged inside the "shared commons entry"
34+
* file - e.g. vendor.js, which would prevent long-term caching.
35+
*/
36+
'manifest'
37+
],
38+
minChunks: Infinity,
39+
}));
40+
};

lib/plugins/define.js

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* This file is part of the Symfony package.
3+
*
4+
* (c) Fabien Potencier <[email protected]>
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
'use strict';
11+
12+
const webpack = require('webpack');
13+
14+
/**
15+
* @param {Array} plugins
16+
* @param {WebpackConfig} webpackConfig
17+
* @param {Object} defineOptions
18+
* @return {void}
19+
*/
20+
module.exports = function(plugins, webpackConfig, defineOptions = {}) {
21+
22+
if (!webpackConfig.isProduction()) {
23+
return;
24+
}
25+
26+
let defineConfig = Object.assign({}, defineOptions, {
27+
'process.env': {
28+
NODE_ENV: '"production"'
29+
}
30+
});
31+
let define = new webpack.DefinePlugin(defineConfig);
32+
33+
plugins.push(define);
34+
};

0 commit comments

Comments
 (0)