Skip to content

Commit 677c434

Browse files
committed
minor #521 Allow to set @babel/preset-env's useBuiltIns option (Lyrkan)
This PR was merged into the master branch. Discussion ---------- Allow to set @babel/preset-env's useBuiltIns option This PR adds an `useBuiltIns` option to the second parameter of `Encore.configureBabel()` that sets the same option on the`@babel/preset-env` preset. That option allows to change how the preset handles polyfills (fixes #444), for instance: ```js Encore.configureBabel(() => {}, { // automatically import individual polyfills // where they are needed useBuiltIns: 'usage'; }); ``` The PR also depreciates the `include_node_modules` option and replaces it by `includeNodeModules` since other methods (for instance `Encore.enableSassLoader()`) use camelCased names. Commits ------- 6298a52 Allow to set @babel/preset-env useBuiltIns option and replace include_node_modules by includeNodeModules
2 parents b671783 + 6298a52 commit 677c434

File tree

5 files changed

+79
-14
lines changed

5 files changed

+79
-14
lines changed

index.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -793,7 +793,11 @@ class Encore {
793793
*
794794
* // ...or keep the default rule but only allow
795795
* // *some* Node modules to be processed by Babel
796-
* include_node_modules: ['foundation-sites']
796+
* includeNodeModules: ['foundation-sites']
797+
*
798+
* // automatically import polyfills where they
799+
* // are needed
800+
* useBuiltIns: 'usage'
797801
* });
798802
*
799803
* Supported options:
@@ -803,10 +807,18 @@ class Encore {
803807
* processed by Babel (https://webpack.js.org/configuration/module/#condition).
804808
* Cannot be used if the "include_node_modules" option is
805809
* also set.
806-
* * {string[]} include_node_modules
810+
* * {string[]} includeNodeModules
807811
* If set that option will include the given Node modules to
808812
* the files that are processed by Babel. Cannot be used if
809813
* the "exclude" option is also set.
814+
* * {'usage'|'entry'|false} useBuiltIns (default='entry')
815+
* Set the "useBuiltIns" option of @babel/preset-env that changes
816+
* how it handles polyfills (https://babeljs.io/docs/en/babel-preset-env#usebuiltins)
817+
* Using it with 'entry' will require you to import @babel/polyfill
818+
* once in your whole app and will result in that import being replaced
819+
* by individual polyfills. Using it with 'usage' will try to
820+
* automatically detect which polyfills are needed for each file and
821+
* add them accordingly.
810822
*
811823
* @param {function} callback
812824
* @param {object} encoreOptions

lib/WebpackConfig.js

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ class WebpackConfig {
8181
fonts: false
8282
};
8383
this.babelOptions = {
84-
exclude: /(node_modules|bower_components)/
84+
exclude: /(node_modules|bower_components)/,
85+
useBuiltIns: 'entry',
8586
};
8687

8788
// Features/Loaders options callbacks
@@ -327,13 +328,19 @@ class WebpackConfig {
327328
this.babelConfigurationCallback = callback;
328329

329330
for (const optionKey of Object.keys(options)) {
331+
let normalizedOptionKey = optionKey;
330332
if (optionKey === 'include_node_modules') {
333+
logger.deprecation('configureBabel: "include_node_modules" is deprecated. Please use "includeNodeModules" instead.');
334+
normalizedOptionKey = 'includeNodeModules';
335+
}
336+
337+
if (normalizedOptionKey === 'includeNodeModules') {
331338
if (Object.keys(options).includes('exclude')) {
332-
throw new Error('"include_node_modules" and "exclude" options can\'t be used together when calling configureBabel().');
339+
throw new Error('"includeNodeModules" and "exclude" options can\'t be used together when calling configureBabel().');
333340
}
334341

335342
if (!Array.isArray(options[optionKey])) {
336-
throw new Error('Option "include_node_modules" passed to configureBabel() must be an Array.');
343+
throw new Error('Option "includeNodeModules" passed to configureBabel() must be an Array.');
337344
}
338345

339346
this.babelOptions['exclude'] = (filePath) => {
@@ -356,10 +363,10 @@ class WebpackConfig {
356363
// Exclude other modules
357364
return true;
358365
};
359-
} else if (!(optionKey in this.babelOptions)) {
360-
throw new Error(`Invalid option "${optionKey}" passed to configureBabel(). Valid keys are ${Object.keys(this.babelOptions).join(', ')}`);
366+
} else if (!(normalizedOptionKey in this.babelOptions)) {
367+
throw new Error(`Invalid option "${normalizedOptionKey}" passed to configureBabel(). Valid keys are ${[...Object.keys(this.babelOptions), 'includeNodeModules'].join(', ')}`);
361368
} else {
362-
this.babelOptions[optionKey] = options[optionKey];
369+
this.babelOptions[normalizedOptionKey] = options[optionKey];
363370
}
364371
}
365372
}

lib/loaders/babel.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ module.exports = {
3737
modules: false,
3838
targets: {},
3939
forceAllTransforms: webpackConfig.isProduction(),
40-
useBuiltIns: 'entry'
40+
useBuiltIns: webpackConfig.babelOptions.useBuiltIns,
4141
}]
4242
],
4343
plugins: ['@babel/plugin-syntax-dynamic-import']

test/WebpackConfig.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ describe('WebpackConfig object', () => {
502502
expect(config.babelOptions.exclude).to.equal('foo');
503503
});
504504

505-
it('Calling with "include_node_modules" option', () => {
505+
it('Calling with "includeNodeModules" option', () => {
506506
const config = createConfig();
507507
config.configureBabel(() => {}, { include_node_modules: ['foo', 'bar'] });
508508

@@ -533,6 +533,13 @@ describe('WebpackConfig object', () => {
533533
}
534534
});
535535

536+
it('Calling with "useBuiltIns" option', () => {
537+
const config = createConfig();
538+
config.configureBabel(() => { }, { useBuiltIns: 'foo' });
539+
540+
expect(config.babelOptions.useBuiltIns).to.equal('foo');
541+
});
542+
536543
it('Calling with non-callback throws an error', () => {
537544
const config = createConfig();
538545

@@ -558,19 +565,19 @@ describe('WebpackConfig object', () => {
558565
}).to.throw('Invalid option "fake_option" passed to configureBabel()');
559566
});
560567

561-
it('Calling with both "include_node_modules" and "exclude" options', () => {
568+
it('Calling with both "includeNodeModules" and "exclude" options', () => {
562569
const config = createConfig();
563570

564571
expect(() => {
565-
config.configureBabel(() => {}, { exclude: 'foo', include_node_modules: ['bar', 'baz'] });
572+
config.configureBabel(() => {}, { exclude: 'foo', includeNodeModules: ['bar', 'baz'] });
566573
}).to.throw('can\'t be used together');
567574
});
568575

569-
it('Calling with an invalid "include_node_modules" option value', () => {
576+
it('Calling with an invalid "includeNodeModules" option value', () => {
570577
const config = createConfig();
571578

572579
expect(() => {
573-
config.configureBabel(() => {}, { include_node_modules: 'foo' });
580+
config.configureBabel(() => {}, { includeNodeModules: 'foo' });
574581
}).to.throw('must be an Array');
575582
});
576583
});

test/config-generator.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin');
1717
const ManifestPlugin = require('webpack-manifest-plugin');
1818
const CleanWebpackPlugin = require('clean-webpack-plugin');
1919
const webpack = require('webpack');
20+
const path = require('path');
2021
const logger = require('../lib/logger');
2122

2223
const isWindows = (process.platform === 'win32');
@@ -861,6 +862,10 @@ describe('The config-generator function', () => {
861862

862863
const jsRule = findRule(/\.jsx?$/, actualConfig.module.rules);
863864
expect(String(jsRule.exclude)).to.equal(String(/(node_modules|bower_components)/));
865+
866+
const babelLoader = jsRule.use.find(loader => loader.loader === 'babel-loader');
867+
const babelEnvPreset = babelLoader.options.presets.find(([name]) => name === '@babel/preset-env');
868+
expect(babelEnvPreset[1].useBuiltIns).to.equal('entry');
864869
});
865870

866871
it('with configureBabel() and a different exclude rule', () => {
@@ -877,6 +882,40 @@ describe('The config-generator function', () => {
877882
const jsRule = findRule(/\.jsx?$/, actualConfig.module.rules);
878883
expect(String(jsRule.exclude)).to.equal(String(/foo/));
879884
});
885+
886+
it('with configureBabel() and some whitelisted modules', () => {
887+
const config = createConfig();
888+
config.outputPath = '/tmp/output/public-path';
889+
config.publicPath = '/public-path';
890+
config.addEntry('main', './main');
891+
config.configureBabel(() => {}, {
892+
includeNodeModules: ['foo']
893+
});
894+
895+
const actualConfig = configGenerator(config);
896+
897+
const jsRule = findRule(/\.jsx?$/, actualConfig.module.rules);
898+
expect(jsRule.exclude).to.be.a('Function');
899+
expect(jsRule.exclude(path.join('test', 'node_modules', 'foo', 'index.js'))).to.be.false;
900+
expect(jsRule.exclude(path.join('test', 'node_modules', 'bar', 'index.js'))).to.be.true;
901+
});
902+
903+
it('with configureBabel() and a different useBuiltIns value', () => {
904+
const config = createConfig();
905+
config.outputPath = '/tmp/output/public-path';
906+
config.publicPath = '/public-path';
907+
config.addEntry('main', './main');
908+
config.configureBabel(() => { }, {
909+
useBuiltIns: 'usage'
910+
});
911+
912+
const actualConfig = configGenerator(config);
913+
914+
const jsRule = findRule(/\.jsx?$/, actualConfig.module.rules);
915+
const babelLoader = jsRule.use.find(loader => loader.loader === 'babel-loader');
916+
const babelEnvPreset = babelLoader.options.presets.find(([name]) => name === '@babel/preset-env');
917+
expect(babelEnvPreset[1].useBuiltIns).to.equal('usage');
918+
});
880919
});
881920

882921
describe('Test shouldSplitEntryChunks', () => {

0 commit comments

Comments
 (0)