Skip to content

Commit 6298a52

Browse files
committed
Allow to set @babel/preset-env useBuiltIns option and replace include_node_modules by includeNodeModules
1 parent f35841a commit 6298a52

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
@@ -783,7 +783,11 @@ class Encore {
783783
*
784784
* // ...or keep the default rule but only allow
785785
* // *some* Node modules to be processed by Babel
786-
* include_node_modules: ['foundation-sites']
786+
* includeNodeModules: ['foundation-sites']
787+
*
788+
* // automatically import polyfills where they
789+
* // are needed
790+
* useBuiltIns: 'usage'
787791
* });
788792
*
789793
* Supported options:
@@ -793,10 +797,18 @@ class Encore {
793797
* processed by Babel (https://webpack.js.org/configuration/module/#condition).
794798
* Cannot be used if the "include_node_modules" option is
795799
* also set.
796-
* * {string[]} include_node_modules
800+
* * {string[]} includeNodeModules
797801
* If set that option will include the given Node modules to
798802
* the files that are processed by Babel. Cannot be used if
799803
* the "exclude" option is also set.
804+
* * {'usage'|'entry'|false} useBuiltIns (default='entry')
805+
* Set the "useBuiltIns" option of @babel/preset-env that changes
806+
* how it handles polyfills (https://babeljs.io/docs/en/babel-preset-env#usebuiltins)
807+
* Using it with 'entry' will require you to import @babel/polyfill
808+
* once in your whole app and will result in that import being replaced
809+
* by individual polyfills. Using it with 'usage' will try to
810+
* automatically detect which polyfills are needed for each file and
811+
* add them accordingly.
800812
*
801813
* @param {function} callback
802814
* @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
@@ -499,7 +499,7 @@ describe('WebpackConfig object', () => {
499499
expect(config.babelOptions.exclude).to.equal('foo');
500500
});
501501

502-
it('Calling with "include_node_modules" option', () => {
502+
it('Calling with "includeNodeModules" option', () => {
503503
const config = createConfig();
504504
config.configureBabel(() => {}, { include_node_modules: ['foo', 'bar'] });
505505

@@ -530,6 +530,13 @@ describe('WebpackConfig object', () => {
530530
}
531531
});
532532

533+
it('Calling with "useBuiltIns" option', () => {
534+
const config = createConfig();
535+
config.configureBabel(() => { }, { useBuiltIns: 'foo' });
536+
537+
expect(config.babelOptions.useBuiltIns).to.equal('foo');
538+
});
539+
533540
it('Calling with non-callback throws an error', () => {
534541
const config = createConfig();
535542

@@ -555,19 +562,19 @@ describe('WebpackConfig object', () => {
555562
}).to.throw('Invalid option "fake_option" passed to configureBabel()');
556563
});
557564

558-
it('Calling with both "include_node_modules" and "exclude" options', () => {
565+
it('Calling with both "includeNodeModules" and "exclude" options', () => {
559566
const config = createConfig();
560567

561568
expect(() => {
562-
config.configureBabel(() => {}, { exclude: 'foo', include_node_modules: ['bar', 'baz'] });
569+
config.configureBabel(() => {}, { exclude: 'foo', includeNodeModules: ['bar', 'baz'] });
563570
}).to.throw('can\'t be used together');
564571
});
565572

566-
it('Calling with an invalid "include_node_modules" option value', () => {
573+
it('Calling with an invalid "includeNodeModules" option value', () => {
567574
const config = createConfig();
568575

569576
expect(() => {
570-
config.configureBabel(() => {}, { include_node_modules: 'foo' });
577+
config.configureBabel(() => {}, { includeNodeModules: 'foo' });
571578
}).to.throw('must be an Array');
572579
});
573580
});

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)