Skip to content

Commit 950d5dd

Browse files
committed
bug #739 Resolve loaders directly from Encore instead of using their names (Lyrkan)
This PR was merged into the master branch. Discussion ---------- Resolve loaders directly from Encore instead of using their names This issue fixes #727 by replacing the use of loader names in rules (for instance `'file-loader'`) by their resolved path (`require.resolve('file-loader')`). The problem with using their name is that we are assuming that the loader's package will be present at the top-level of `node_modules`. If for some reason that's not the case and npm/Yarn decides to put it in, let's say `node_modules/@symfony/webpack-encore/node_modules`, the compilation will fail when Webpack tries to require it. Another reason to do that is to ensure that Webpack uses the right version of a loader. We had some issues before 0.29 because we expected an old version of `file-loader` when some other packages included a newer one that was then used by Webpack because it got hoisted to the top-level `node_modules`. This change should in my opinion be considered a BC break for people that were: * adding a different version of a loader we embed into their `package.json`: that one won't be used anymore * requiring a package that also included one of our embedded loaders: depending on which one was hoisted it could result in a different behavior * manipulating the generated config and filtering loaders based on their names: the comparison won't be the same anymore (see the tests I had to change) I also modified dev dependencies loaders for more consistency but it doesn't really matter for those. Commits ------- a3e1e94 Resolve loaders directly from Encore instead of using their names
2 parents 407d81e + a3e1e94 commit 950d5dd

12 files changed

+32
-32
lines changed

lib/config-generator.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ class ConfigGenerator {
302302

303303
rules.push(applyRuleConfigurationCallback('images', {
304304
test: /\.(png|jpg|jpeg|gif|ico|svg|webp)$/,
305-
loader: loaderName,
305+
loader: require.resolve(loaderName),
306306
options: loaderOptions
307307
}));
308308
}
@@ -330,7 +330,7 @@ class ConfigGenerator {
330330

331331
rules.push(applyRuleConfigurationCallback('fonts', {
332332
test: /\.(woff|woff2|ttf|eot|otf)$/,
333-
loader: loaderName,
333+
loader: require.resolve(loaderName),
334334
options: loaderOptions
335335
}));
336336
}
@@ -394,7 +394,7 @@ class ConfigGenerator {
394394
if (this.webpackConfig.useEslintLoader) {
395395
rules.push(applyRuleConfigurationCallback('eslint', {
396396
test: eslintLoaderUtil.getTest(this.webpackConfig),
397-
loader: 'eslint-loader',
397+
loader: require.resolve('eslint-loader'),
398398
exclude: /node_modules/,
399399
enforce: 'pre',
400400
options: eslintLoaderUtil.getOptions(this.webpackConfig)

lib/loaders/babel.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ module.exports = {
9898

9999
return [
100100
{
101-
loader: 'babel-loader',
101+
loader: require.resolve('babel-loader'),
102102
options: babelConfig
103103
}
104104
];

lib/loaders/css-extract.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ module.exports = {
2929
// If the CSS extraction is disabled, use the
3030
// style-loader instead.
3131
return [{
32-
loader: 'style-loader',
32+
loader: require.resolve('style-loader'),
3333
options: applyOptionsCallback(webpackConfig.styleLoaderConfigurationCallback, options)
3434

3535
}, ...loaders];

lib/loaders/css.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ module.exports = {
4141

4242
const cssLoaders = [
4343
{
44-
loader: 'css-loader',
44+
loader: require.resolve('css-loader'),
4545
options: applyOptionsCallback(webpackConfig.cssLoaderConfigurationCallback, options)
4646
},
4747
];
@@ -54,7 +54,7 @@ module.exports = {
5454
};
5555

5656
cssLoaders.push({
57-
loader: 'postcss-loader',
57+
loader: require.resolve('postcss-loader'),
5858
options: applyOptionsCallback(webpackConfig.postCssLoaderOptionsCallback, postCssLoaderOptions)
5959
});
6060
}

lib/loaders/handlebars.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ module.exports = {
2525

2626
return [
2727
{
28-
loader: 'handlebars-loader',
28+
loader: require.resolve('handlebars-loader'),
2929
options: applyOptionsCallback(webpackConfig.handlebarsConfigurationCallback, options)
3030
}
3131
];

lib/loaders/less.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ module.exports = {
3030
return [
3131
...cssLoader.getLoaders(webpackConfig, useCssModules),
3232
{
33-
loader: 'less-loader',
33+
loader: require.resolve('less-loader'),
3434
options: applyOptionsCallback(webpackConfig.lessLoaderOptionsCallback, config)
3535
},
3636
];

lib/loaders/sass.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ module.exports = {
2929
// without this, all url() paths must be relative to the
3030
// entry file, not the file that contains the url()
3131
sassLoaders.push({
32-
loader: 'resolve-url-loader',
32+
loader: require.resolve('resolve-url-loader'),
3333
options: Object.assign(
3434
{
3535
sourceMap: webpackConfig.useSourceMaps
@@ -47,7 +47,7 @@ module.exports = {
4747
});
4848

4949
sassLoaders.push({
50-
loader: 'sass-loader',
50+
loader: require.resolve('sass-loader'),
5151
options: applyOptionsCallback(webpackConfig.sassLoaderOptionsCallback, config)
5252
});
5353

lib/loaders/stylus.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ module.exports = {
3030
return [
3131
...cssLoader.getLoaders(webpackConfig, useCssModules),
3232
{
33-
loader: 'stylus-loader',
33+
loader: require.resolve('stylus-loader'),
3434
options: applyOptionsCallback(webpackConfig.stylusLoaderOptionsCallback, config)
3535
},
3636
];

lib/loaders/typescript.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ module.exports = {
5151
let loaders = babelLoader.getLoaders(webpackConfig);
5252
return loaders.concat([
5353
{
54-
loader: 'ts-loader',
54+
loader: require.resolve('ts-loader'),
5555
// @see https://github.com/TypeStrong/ts-loader/blob/master/README.md#available-options
5656
options: config
5757
}

lib/loaders/vue.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ module.exports = {
2525

2626
return [
2727
{
28-
loader: 'vue-loader',
28+
loader: require.resolve('vue-loader'),
2929
options: applyOptionsCallback(webpackConfig.vueLoaderOptionsCallback, options)
3030
}
3131
];

test/config-generator.js

+10-10
Original file line numberDiff line numberDiff line change
@@ -861,10 +861,10 @@ describe('The config-generator function', () => {
861861
const actualConfig = configGenerator(config);
862862

863863
const imagesRule = findRule(/\.(png|jpg|jpeg|gif|ico|svg|webp)$/, actualConfig.module.rules);
864-
expect(imagesRule.loader).to.equal('file-loader');
864+
expect(imagesRule.loader).to.contain('file-loader');
865865

866866
const fontsRule = findRule(/\.(woff|woff2|ttf|eot|otf)$/, actualConfig.module.rules);
867-
expect(fontsRule.loader).to.equal('file-loader');
867+
expect(fontsRule.loader).to.contain('file-loader');
868868
});
869869

870870
it('with configureUrlLoader() and missing keys', () => {
@@ -877,10 +877,10 @@ describe('The config-generator function', () => {
877877
const actualConfig = configGenerator(config);
878878

879879
const imagesRule = findRule(/\.(png|jpg|jpeg|gif|ico|svg|webp)$/, actualConfig.module.rules);
880-
expect(imagesRule.loader).to.equal('file-loader');
880+
expect(imagesRule.loader).to.contain('file-loader');
881881

882882
const fontsRule = findRule(/\.(woff|woff2|ttf|eot|otf)$/, actualConfig.module.rules);
883-
expect(fontsRule.loader).to.equal('file-loader');
883+
expect(fontsRule.loader).to.contain('file-loader');
884884
});
885885

886886
it('with configureUrlLoader()', () => {
@@ -900,12 +900,12 @@ describe('The config-generator function', () => {
900900
const actualConfig = configGenerator(config);
901901

902902
const imagesRule = findRule(/\.(png|jpg|jpeg|gif|ico|svg|webp)$/, actualConfig.module.rules);
903-
expect(imagesRule.loader).to.equal('url-loader');
903+
expect(imagesRule.loader).to.contain('url-loader');
904904
expect(imagesRule.options.name).to.equal('[name].foo.[ext]');
905905
expect(imagesRule.options.limit).to.equal(8192);
906906

907907
const fontsRule = findRule(/\.(woff|woff2|ttf|eot|otf)$/, actualConfig.module.rules);
908-
expect(fontsRule.loader).to.equal('url-loader');
908+
expect(fontsRule.loader).to.contain('url-loader');
909909
expect(fontsRule.options.limit).to.equal(4096);
910910
expect(fontsRule.options.name).to.equal('[name].bar.[ext]');
911911
});
@@ -951,7 +951,7 @@ describe('The config-generator function', () => {
951951
const jsRule = findRule(/\.(jsx?)$/, actualConfig.module.rules);
952952
expect(String(jsRule.exclude)).to.equal(String(/(node_modules|bower_components)/));
953953

954-
const babelLoader = jsRule.use.find(loader => loader.loader === 'babel-loader');
954+
const babelLoader = jsRule.use.find(loader => /babel-loader/.test(loader.loader));
955955
const babelEnvPreset = babelLoader.options.presets.find(([name]) => name === '@babel/preset-env');
956956
expect(babelEnvPreset[1].useBuiltIns).to.equal(false);
957957
});
@@ -1001,7 +1001,7 @@ describe('The config-generator function', () => {
10011001
const actualConfig = configGenerator(config);
10021002

10031003
const jsRule = findRule(/\.(jsx?)$/, actualConfig.module.rules);
1004-
const babelLoader = jsRule.use.find(loader => loader.loader === 'babel-loader');
1004+
const babelLoader = jsRule.use.find(loader => /babel-loader/.test(loader.loader));
10051005
const babelEnvPreset = babelLoader.options.presets.find(([name]) => name === '@babel/preset-env');
10061006
expect(babelEnvPreset[1].useBuiltIns).to.equal('usage');
10071007
expect(babelEnvPreset[1].corejs).to.equal(3);
@@ -1018,7 +1018,7 @@ describe('The config-generator function', () => {
10181018
const actualConfig = configGenerator(config);
10191019

10201020
const jsRule = findRule(/\.(jsx?)$/, actualConfig.module.rules);
1021-
const babelLoader = jsRule.use.find(loader => loader.loader === 'babel-loader');
1021+
const babelLoader = jsRule.use.find(loader => /babel-loader/.test(loader.loader));
10221022
const babelEnvPreset = babelLoader.options.presets.find(([name]) => name === '@babel/preset-env');
10231023
expect(babelEnvPreset[1].useBuiltIns).to.equal(false);
10241024
});
@@ -1035,7 +1035,7 @@ describe('The config-generator function', () => {
10351035
const actualConfig = configGenerator(config);
10361036

10371037
const jsRule = findRule(/\.(jsx?)$/, actualConfig.module.rules);
1038-
const babelLoader = jsRule.use.find(loader => loader.loader === 'babel-loader');
1038+
const babelLoader = jsRule.use.find(loader => /babel-loader/.test(loader.loader));
10391039
const babelEnvPreset = babelLoader.options.presets.find(([name]) => name === '@babel/preset-env');
10401040
expect(babelEnvPreset[1].useBuiltIns).to.equal('usage');
10411041
});

test/loaders/sass.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ describe('loaders/sass', () => {
3535

3636
const actualLoaders = sassLoader.getLoaders(config);
3737
expect(actualLoaders).to.have.lengthOf(2);
38-
expect(actualLoaders[0].loader).to.equal('resolve-url-loader');
38+
expect(actualLoaders[0].loader).to.contain('resolve-url-loader');
3939
expect(actualLoaders[0].options.sourceMap).to.be.true;
4040

41-
expect(actualLoaders[1].loader).to.equal('sass-loader');
41+
expect(actualLoaders[1].loader).to.contain('sass-loader');
4242
expect(actualLoaders[1].options.sourceMap).to.be.true;
4343
expect(cssLoaderStub.getCall(0).args[1]).to.be.false;
4444

@@ -55,10 +55,10 @@ describe('loaders/sass', () => {
5555

5656
const actualLoaders = sassLoader.getLoaders(config);
5757
expect(actualLoaders).to.have.lengthOf(2);
58-
expect(actualLoaders[0].loader).to.equal('resolve-url-loader');
58+
expect(actualLoaders[0].loader).to.contain('resolve-url-loader');
5959
expect(actualLoaders[0].options.sourceMap).to.be.false;
6060

61-
expect(actualLoaders[1].loader).to.equal('sass-loader');
61+
expect(actualLoaders[1].loader).to.contain('sass-loader');
6262
// sourcemaps always enabled when resolve-url-loader is enabled
6363
expect(actualLoaders[1].options.sourceMap).to.be.true;
6464

@@ -79,7 +79,7 @@ describe('loaders/sass', () => {
7979

8080
const actualLoaders = sassLoader.getLoaders(config);
8181
expect(actualLoaders).to.have.lengthOf(2);
82-
expect(actualLoaders[0].loader).to.equal('resolve-url-loader');
82+
expect(actualLoaders[0].loader).to.contain('resolve-url-loader');
8383
expect(actualLoaders[0].options.removeCR).to.be.true;
8484

8585
cssLoader.getLoaders.restore();
@@ -98,7 +98,7 @@ describe('loaders/sass', () => {
9898

9999
const actualLoaders = sassLoader.getLoaders(config);
100100
expect(actualLoaders).to.have.lengthOf(1);
101-
expect(actualLoaders[0].loader).to.equal('sass-loader');
101+
expect(actualLoaders[0].loader).to.contain('sass-loader');
102102
expect(actualLoaders[0].options.sourceMap).to.be.false;
103103

104104
cssLoader.getLoaders.restore();
@@ -158,10 +158,10 @@ describe('loaders/sass', () => {
158158

159159
const actualLoaders = sassLoader.getLoaders(config, true);
160160
expect(actualLoaders).to.have.lengthOf(2);
161-
expect(actualLoaders[0].loader).to.equal('resolve-url-loader');
161+
expect(actualLoaders[0].loader).to.contain('resolve-url-loader');
162162
expect(actualLoaders[0].options.sourceMap).to.be.true;
163163

164-
expect(actualLoaders[1].loader).to.equal('sass-loader');
164+
expect(actualLoaders[1].loader).to.contain('sass-loader');
165165
expect(actualLoaders[1].options.sourceMap).to.be.true;
166166
expect(cssLoaderStub.getCall(0).args[1]).to.be.true;
167167

0 commit comments

Comments
 (0)