Skip to content

Commit 7e53ee3

Browse files
committed
Refactoring loaders into re-usable modules
1 parent 6e65322 commit 7e53ee3

File tree

6 files changed

+199
-100
lines changed

6 files changed

+199
-100
lines changed

lib/config-generator.js

Lines changed: 13 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ const ExtractTextPlugin = require('extract-text-webpack-plugin');
1414
const ManifestPlugin = require('./webpack/webpack-manifest-plugin');
1515
const DeleteUnusedEntriesJSPlugin = require('./webpack/delete-unused-entries-js-plugin');
1616
const AssetOutputDisplayPlugin = require('./friendly-errors/asset-output-display-plugin');
17-
const loaderFeatures = require('./loader-features');
1817
const CleanWebpackPlugin = require('clean-webpack-plugin');
1918
const WebpackChunkHash = require('webpack-chunk-hash');
2019
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
@@ -23,6 +22,10 @@ const missingLoaderFormatter = require('./friendly-errors/formatters/missing-loa
2322
const missingPostCssConfigTransformer = require('./friendly-errors/transformers/missing-postcss-config');
2423
const missingPostCssConfigFormatter = require('./friendly-errors/formatters/missing-postcss-config');
2524
const pathUtil = require('./config/path-util');
25+
const cssLoaders = require('./loaders/css');
26+
const sassLoaders = require('./loaders/sass');
27+
const lessLoaders = require('./loaders/less');
28+
const babelLoaders = require('./loaders/babel');
2629

2730
class ConfigGenerator {
2831
/**
@@ -99,76 +102,18 @@ class ConfigGenerator {
99102
}
100103

101104
buildRulesConfig() {
102-
const cssLoaders = [
105+
let rules = [
103106
{
104-
loader: 'css-loader' + this.getSourceMapOption() + (this.webpackConfig.isProduction() ? '?minimize=1' : ''),
107+
// match .js and .jsx
108+
test: /\.jsx?$/,
109+
exclude: /(node_modules|bower_components)/,
110+
use: babelLoaders(this.webpackConfig)
105111
},
106-
];
107-
if (this.webpackConfig.usePostCssLoader) {
108-
loaderFeatures.ensureLoaderPackagesExist('postcss');
109-
110-
cssLoaders.push({
111-
loader: 'postcss-loader' + this.getSourceMapOption(),
112-
});
113-
}
114-
115-
let babelConfig = {
116-
// improves performance by caching babel compiles
117-
// we add this option ALWAYS
118-
// https://github.com/babel/babel-loader#options
119-
cacheDirectory: true
120-
};
121-
122-
// configure babel (unless the user is specifying .babelrc)
123-
// todo - add a sanity check for their babelrc contents
124-
if (!this.webpackConfig.doesBabelRcFileExist()) {
125-
Object.assign(babelConfig, {
126-
presets: [
127-
['env', {
128-
// modules don't need to be transformed - webpack will parse
129-
// the modules for us. This is a performance improvement
130-
// https://babeljs.io/docs/plugins/preset-env/#optionsmodules
131-
modules: false,
132-
targets: {
133-
browsers: '> 1%',
134-
uglify: true
135-
},
136-
useBuiltIns: true
137-
}]
138-
],
139-
});
140-
141-
if (this.webpackConfig.useReact) {
142-
loaderFeatures.ensureLoaderPackagesExist('react');
143-
144-
babelConfig.presets.push('react');
145-
}
146-
147-
// allow for babel config to be controlled
148-
this.webpackConfig.babelConfigurationCallback.apply(
149-
// use babelConfig as the this variable
150-
babelConfig,
151-
[babelConfig]
152-
);
153-
}
154-
155-
let rules = [];
156-
rules.push({
157-
// match .js and .jsx
158-
test: /\.jsx?$/,
159-
exclude: /(node_modules|bower_components)/,
160-
use: {
161-
loader: 'babel-loader',
162-
options: babelConfig
163-
}
164-
});
165-
166-
rules = rules.concat([
167112
{
168113
test: /\.css$/,
169114
use: ExtractTextPlugin.extract({
170115
fallback: 'style-loader' + this.getSourceMapOption(),
171-
use: cssLoaders
116+
use: cssLoaders(this.webpackConfig)
172117
})
173118
},
174119
{
@@ -187,51 +132,24 @@ class ConfigGenerator {
187132
publicPath: this.webpackConfig.getRealPublicPath()
188133
}
189134
},
190-
]);
135+
];
191136

192137
if (this.webpackConfig.useSassLoader) {
193-
loaderFeatures.ensureLoaderPackagesExist('sass');
194-
195-
const sassLoaders = [...cssLoaders];
196-
if (true === this.webpackConfig.sassOptions.resolve_url_loader) {
197-
// responsible for resolving SASS url() paths
198-
// without this, all url() paths must be relative to the
199-
// entry file, not the file that contains the url()
200-
sassLoaders.push({
201-
loader: 'resolve-url-loader' + this.getSourceMapOption(),
202-
});
203-
}
204-
205-
sassLoaders.push({
206-
loader: 'sass-loader',
207-
options: {
208-
// needed by the resolve-url-loader
209-
sourceMap: (true === this.webpackConfig.sassOptions.resolve_url_loader) || this.webpackConfig.useSourceMaps
210-
}
211-
});
212-
213138
rules.push({
214139
test: /\.s[ac]ss$/,
215140
use: ExtractTextPlugin.extract({
216141
fallback: 'style-loader' + this.getSourceMapOption(),
217-
use: sassLoaders
142+
use: sassLoaders(this.webpackConfig)
218143
})
219144
});
220145
}
221146

222147
if (this.webpackConfig.useLessLoader) {
223-
loaderFeatures.ensureLoaderPackagesExist('less');
224-
225148
rules.push({
226149
test: /\.less/,
227150
use: ExtractTextPlugin.extract({
228151
fallback: 'style-loader' + this.getSourceMapOption(),
229-
use: [
230-
...cssLoaders,
231-
{
232-
loader: 'less-loader' + this.getSourceMapOption()
233-
},
234-
]
152+
use: lessLoaders(this.webpackConfig)
235153
})
236154
});
237155
}

lib/loaders/babel.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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 loaderFeatures = require('../loader-features');
13+
14+
/**
15+
* @param {WebpackConfig} webpackConfig
16+
* @return {Array} of loaders to use for Babel
17+
*/
18+
module.exports = function(webpackConfig) {
19+
let babelConfig = {
20+
// improves performance by caching babel compiles
21+
// we add this option ALWAYS
22+
// https://github.com/babel/babel-loader#options
23+
cacheDirectory: true
24+
};
25+
26+
// configure babel (unless the user is specifying .babelrc)
27+
// todo - add a sanity check for their babelrc contents
28+
if (!webpackConfig.doesBabelRcFileExist()) {
29+
Object.assign(babelConfig, {
30+
presets: [
31+
['env', {
32+
// modules don't need to be transformed - webpack will parse
33+
// the modules for us. This is a performance improvement
34+
// https://babeljs.io/docs/plugins/preset-env/#optionsmodules
35+
modules: false,
36+
targets: {
37+
browsers: '> 1%',
38+
uglify: true
39+
},
40+
useBuiltIns: true
41+
}]
42+
],
43+
});
44+
45+
if (webpackConfig.useReact) {
46+
loaderFeatures.ensureLoaderPackagesExist('react');
47+
48+
babelConfig.presets.push('react');
49+
}
50+
51+
// allow for babel config to be controlled
52+
webpackConfig.babelConfigurationCallback.apply(
53+
// use babelConfig as the this variable
54+
babelConfig,
55+
[babelConfig]
56+
);
57+
}
58+
59+
return [
60+
{
61+
loader: 'babel-loader',
62+
options: babelConfig
63+
}
64+
];
65+
};

lib/loaders/css.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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 loaderFeatures = require('../loader-features');
13+
14+
/**
15+
* @param {WebpackConfig} webpackConfig
16+
* @return {Array} of loaders to use for CSS files
17+
*/
18+
module.exports = function(webpackConfig) {
19+
const cssLoaders = [
20+
{
21+
loader: 'css-loader',
22+
options: {
23+
minimize: webpackConfig.isProduction(),
24+
sourceMap: webpackConfig.useSourceMaps
25+
}
26+
},
27+
];
28+
29+
if (webpackConfig.usePostCssLoader) {
30+
loaderFeatures.ensureLoaderPackagesExist('postcss');
31+
32+
cssLoaders.push({
33+
loader: 'postcss-loader',
34+
options: {
35+
sourceMap: webpackConfig.useSourceMaps
36+
}
37+
});
38+
}
39+
40+
return cssLoaders;
41+
};

lib/loaders/less.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
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 loaderFeatures = require('../loader-features');
13+
const cssLoaders = require('./css');
14+
15+
/**
16+
* @param {WebpackConfig} webpackConfig
17+
* @return {Array} of loaders to use for Less files
18+
*/
19+
module.exports = function(webpackConfig) {
20+
loaderFeatures.ensureLoaderPackagesExist('less');
21+
22+
return [
23+
...cssLoaders(webpackConfig),
24+
{
25+
loader: 'less-loader',
26+
options: {
27+
sourceMap: webpackConfig.useSourceMaps
28+
}
29+
},
30+
];
31+
};

lib/loaders/sass.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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 loaderFeatures = require('../loader-features');
13+
const cssLoaders = require('./css');
14+
15+
/**
16+
* @param {WebpackConfig} webpackConfig
17+
* @return {Array} of loaders to use for Sass files
18+
*/
19+
module.exports = function(webpackConfig) {
20+
loaderFeatures.ensureLoaderPackagesExist('sass');
21+
22+
const sassLoaders = [...cssLoaders(webpackConfig)];
23+
if (true === webpackConfig.sassOptions.resolve_url_loader) {
24+
// responsible for resolving SASS url() paths
25+
// without this, all url() paths must be relative to the
26+
// entry file, not the file that contains the url()
27+
sassLoaders.push({
28+
loader: 'resolve-url-loader',
29+
options: {
30+
sourceMap: webpackConfig.useSourceMaps
31+
}
32+
});
33+
}
34+
35+
sassLoaders.push({
36+
loader: 'sass-loader',
37+
options: {
38+
// needed by the resolve-url-loader
39+
sourceMap: (true === webpackConfig.sassOptions.resolve_url_loader) || webpackConfig.useSourceMaps
40+
}
41+
});
42+
43+
return sassLoaders;
44+
};

test/config-generator.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ describe('The config-generator function', () => {
373373
const jsRule = findRule(/\.jsx?$/, actualConfig.module.rules);
374374

375375
// check for the default env preset only
376-
expect(JSON.stringify(jsRule.use.options.presets)).contains('env');
376+
expect(JSON.stringify(jsRule.use[0].options.presets)).contains('env');
377377
});
378378

379379
it('If .babelrc is present, we pass *no* config', () => {
@@ -389,7 +389,7 @@ describe('The config-generator function', () => {
389389
const jsRule = findRule(/\.jsx?$/, actualConfig.module.rules);
390390

391391
// the options should only contain the cacheDirectory option
392-
expect(JSON.stringify(jsRule.use.options)).to.equal(JSON.stringify({ 'cacheDirectory': true }));
392+
expect(JSON.stringify(jsRule.use[0].options)).to.equal(JSON.stringify({ 'cacheDirectory': true }));
393393
});
394394

395395
it('configureBabel() passes babel options', () => {
@@ -405,7 +405,7 @@ describe('The config-generator function', () => {
405405

406406
const jsRule = findRule(/\.jsx?$/, actualConfig.module.rules);
407407

408-
expect(jsRule.use.options.presets).to.include('foo');
408+
expect(jsRule.use[0].options.presets).to.include('foo');
409409
});
410410

411411
it('enableReactPreset() passes react preset to babel', () => {
@@ -422,9 +422,9 @@ describe('The config-generator function', () => {
422422

423423
const jsRule = findRule(/\.jsx?$/, actualConfig.module.rules);
424424

425-
expect(jsRule.use.options.presets).to.include('react');
425+
expect(jsRule.use[0].options.presets).to.include('react');
426426
// foo is also still there, not overridden
427-
expect(jsRule.use.options.presets).to.include('foo');
427+
expect(jsRule.use[0].options.presets).to.include('foo');
428428
});
429429
});
430430

0 commit comments

Comments
 (0)