Skip to content

Commit 96a666b

Browse files
committed
feat: implement Encore.enableBabelTypeScriptPreset()
1 parent 6f992b0 commit 96a666b

File tree

8 files changed

+90
-26
lines changed

8 files changed

+90
-26
lines changed

lib/WebpackConfig.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ class WebpackConfig {
131131
useBuiltIns: false,
132132
corejs: null,
133133
};
134+
this.babelTypeScriptPresetOptions = {};
134135
this.vueOptions = {
135136
useJsx: false,
136137
};
@@ -685,6 +686,7 @@ class WebpackConfig {
685686
}
686687

687688
this.useBabelTypeScriptPreset = true;
689+
this.babelTypeScriptPresetOptions = options;
688690
}
689691

690692
enableVueLoader(vueLoaderOptionsCallback = () => {}, vueOptions = {}) {

lib/config-generator.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,7 @@ class ConfigGenerator {
250250

251251
let rules = [
252252
applyRuleConfigurationCallback('javascript', {
253-
// match .js and .jsx
254-
test: /\.jsx?$/,
253+
test: babelLoaderUtil.getTest(this.webpackConfig),
255254
exclude: this.webpackConfig.babelOptions.exclude,
256255
use: babelLoaderUtil.getLoaders(this.webpackConfig)
257256
}),

lib/features.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,15 @@ const features = {
7878
],
7979
description: 'check TypeScript types in a separate process'
8080
},
81+
'typescript-babel': {
82+
method: 'enableBabelTypeScriptPreset',
83+
packages: [
84+
{ name: 'typescript' },
85+
{ name: '@babel/preset-typescript', enforce_version: true },
86+
{ name: '@babel/plugin-proposal-class-properties', enforce_version: true },
87+
],
88+
description: 'process TypeScript files with Babel'
89+
},
8190
vue: {
8291
method: 'enableVueLoader()',
8392
// vue is needed so the end-user can do things

lib/loaders/babel.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ module.exports = {
5858
plugins: ['@babel/plugin-syntax-dynamic-import']
5959
});
6060

61+
if (webpackConfig.useBabelTypeScriptPreset) {
62+
loaderFeatures.ensurePackagesExistAndAreCorrectVersion('typescript-babel');
63+
64+
babelConfig.presets.push(['@babel/preset-typescript', webpackConfig.babelTypeScriptPresetOptions]);
65+
babelConfig.plugins.push('@babel/plugin-proposal-class-properties');
66+
}
67+
6168
if (webpackConfig.useReact) {
6269
loaderFeatures.ensurePackagesExistAndAreCorrectVersion('react');
6370

@@ -95,5 +102,21 @@ module.exports = {
95102
options: babelConfig
96103
}
97104
];
105+
},
106+
107+
/**
108+
* @param {WebpackConfig} webpackConfig
109+
* @return {RegExp} to use for eslint-loader `test` rule
110+
*/
111+
getTest(webpackConfig) {
112+
const extensions = [
113+
'jsx?', // match .js and .jsx
114+
];
115+
116+
if (webpackConfig.useBabelTypeScriptPreset) {
117+
extensions.push('tsx?'); // match .ts and .tsx
118+
}
119+
120+
return new RegExp(`\\.(${extensions.join('|')})$`);
98121
}
99122
};

test/WebpackConfig.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -929,7 +929,16 @@ describe('WebpackConfig object', () => {
929929
config.enableBabelTypeScriptPreset();
930930
}).to.throw('Encore.enableBabelTypeScriptPreset() can not be called when Encore.enableForkedTypeScriptTypesChecking() has been called.');
931931
});
932-
})
932+
933+
it('Options should be defined', () => {
934+
const config = createConfig();
935+
const options = { isTSX: true };
936+
937+
config.enableBabelTypeScriptPreset(options);
938+
939+
expect(config.babelTypeScriptPresetOptions).to.equal(options);
940+
});
941+
});
933942

934943
describe('enableVueLoader', () => {
935944
it('Call with no config', () => {

test/config-generator.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@ describe('The config-generator function', () => {
520520

521521
const actualConfig = configGenerator(config);
522522

523-
const jsRule = findRule(/\.jsx?$/, actualConfig.module.rules);
523+
const jsRule = findRule(/\.(jsx?)$/, actualConfig.module.rules);
524524

525525
// check for the default env preset only
526526
expect(JSON.stringify(jsRule.use[0].options.presets)).contains('@babel/preset-env');
@@ -932,7 +932,7 @@ describe('The config-generator function', () => {
932932

933933
const actualConfig = configGenerator(config);
934934

935-
const jsRule = findRule(/\.jsx?$/, actualConfig.module.rules);
935+
const jsRule = findRule(/\.(jsx?)$/, actualConfig.module.rules);
936936
expect(String(jsRule.exclude)).to.equal(String(/(node_modules|bower_components)/));
937937

938938
const babelLoader = jsRule.use.find(loader => loader.loader === 'babel-loader');
@@ -951,7 +951,7 @@ describe('The config-generator function', () => {
951951

952952
const actualConfig = configGenerator(config);
953953

954-
const jsRule = findRule(/\.jsx?$/, actualConfig.module.rules);
954+
const jsRule = findRule(/\.(jsx?)$/, actualConfig.module.rules);
955955
expect(String(jsRule.exclude)).to.equal(String(/foo/));
956956
});
957957

@@ -966,7 +966,7 @@ describe('The config-generator function', () => {
966966

967967
const actualConfig = configGenerator(config);
968968

969-
const jsRule = findRule(/\.jsx?$/, actualConfig.module.rules);
969+
const jsRule = findRule(/\.(jsx?)$/, actualConfig.module.rules);
970970
expect(jsRule.exclude).to.be.a('Function');
971971
expect(jsRule.exclude(path.join('test', 'node_modules', 'foo', 'index.js'))).to.be.false;
972972
expect(jsRule.exclude(path.join('test', 'node_modules', 'bar', 'index.js'))).to.be.true;
@@ -984,7 +984,7 @@ describe('The config-generator function', () => {
984984

985985
const actualConfig = configGenerator(config);
986986

987-
const jsRule = findRule(/\.jsx?$/, actualConfig.module.rules);
987+
const jsRule = findRule(/\.(jsx?)$/, actualConfig.module.rules);
988988
const babelLoader = jsRule.use.find(loader => loader.loader === 'babel-loader');
989989
const babelEnvPreset = babelLoader.options.presets.find(([name]) => name === '@babel/preset-env');
990990
expect(babelEnvPreset[1].useBuiltIns).to.equal('usage');
@@ -1001,7 +1001,7 @@ describe('The config-generator function', () => {
10011001

10021002
const actualConfig = configGenerator(config);
10031003

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

10191019
const actualConfig = configGenerator(config);
10201020

1021-
const jsRule = findRule(/\.jsx?$/, actualConfig.module.rules);
1021+
const jsRule = findRule(/\.(jsx?)$/, actualConfig.module.rules);
10221022
const babelLoader = jsRule.use.find(loader => loader.loader === 'babel-loader');
10231023
const babelEnvPreset = babelLoader.options.presets.find(([name]) => name === '@babel/preset-env');
10241024
expect(babelEnvPreset[1].useBuiltIns).to.equal('usage');

test/functional.js

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,22 +1325,7 @@ module.exports = {
13251325
const config = createWebpackConfig('www/build', 'dev');
13261326
config.setPublicPath('/build');
13271327
config.addEntry('main', ['./js/render.ts', './js/index.ts']);
1328-
config.configureBabel(function(config) {
1329-
config.presets = [
1330-
['@babel/preset-env', {
1331-
'targets': {
1332-
'chrome': 52,
1333-
},
1334-
}],
1335-
'@babel/typescript', // required preset
1336-
];
1337-
// not required, but recommended
1338-
config.plugins = ['@babel/proposal-class-properties'];
1339-
});
1340-
1341-
config.configureLoaderRule('javascript', loader => {
1342-
loader.test = /.(j|t)sx?$/; // let Babel to run over .tsx? files too
1343-
});
1328+
config.enableBabelTypeScriptPreset();
13441329

13451330
testSetup.runWebpack(config, (webpackAssert) => {
13461331
// check that babel-loader transformed the ts file

test/loaders/babel.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,4 +166,41 @@ describe('loaders/babel', () => {
166166
expect(actualLoaders[0].options.presets[0][1].corejs).to.equal(3);
167167
expect(actualLoaders[0].options.presets[0][1].include).to.have.members(['bar']);
168168
});
169+
170+
it('getLoaders() with TypeScript', () => {
171+
const config = createConfig();
172+
const presetTypeScriptOptions = { isTSX: true };
173+
174+
config.enableBabelTypeScriptPreset(presetTypeScriptOptions);
175+
176+
config.configureBabel(function(babelConfig) {
177+
babelConfig.plugins.push('foo');
178+
});
179+
180+
const actualLoaders = babelLoader.getLoaders(config);
181+
182+
expect(actualLoaders[0].options.presets[0][0]).to.equal('@babel/preset-env');
183+
expect(actualLoaders[0].options.presets[1][0]).to.equal('@babel/preset-typescript');
184+
expect(actualLoaders[0].options.presets[1][1]).to.equal(presetTypeScriptOptions);
185+
expect(actualLoaders[0].options.plugins).to.deep.include.members([
186+
'@babel/plugin-syntax-dynamic-import',
187+
'@babel/plugin-proposal-class-properties',
188+
'foo'
189+
]);
190+
});
191+
192+
it('getTest() base behavior', () => {
193+
const config = createConfig();
194+
195+
const actualTest = babelLoader.getTest(config);
196+
expect(actualTest.toString()).to.equals(/\.(jsx?)$/.toString());
197+
});
198+
199+
it('getTest() with TypeScript', () => {
200+
const config = createConfig();
201+
config.enableBabelTypeScriptPreset();
202+
203+
const actualTest = babelLoader.getTest(config);
204+
expect(actualTest.toString()).to.equals(/\.(jsx?|tsx?)$/.toString());
205+
});
169206
});

0 commit comments

Comments
 (0)