Skip to content

Commit 2ba0f92

Browse files
committed
feat(babel): merges babelrc with microbunde babel config
1 parent 3483790 commit 2ba0f92

File tree

8 files changed

+313
-60
lines changed

8 files changed

+313
-60
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
"filesize": "^4.1.2",
6060
"gzip-size": "^5.1.0",
6161
"kleur": "^3.0.3",
62+
"lodash.merge": "^4.6.1",
6263
"module-details-from-path": "^1.0.3",
6364
"pretty-bytes": "^5.2.0",
6465
"rollup": "^1.11.3",
@@ -85,6 +86,7 @@
8586
"@babel/preset-env": "^7.4.4",
8687
"babel-core": "^7.0.0-bridge.0",
8788
"babel-jest": "^24.8.0",
89+
"core-js": "^3.1.2",
8890
"cross-env": "^5.2.0",
8991
"directory-tree": "^2.2.2",
9092
"eslint": "^5.16.0",

src/index.js

Lines changed: 23 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import cssnano from 'cssnano';
88
import { rollup, watch } from 'rollup';
99
import commonjs from 'rollup-plugin-commonjs';
1010
import babel from 'rollup-plugin-babel';
11+
import customBabel from './lib/babel-custom';
1112
import nodeResolve from 'rollup-plugin-node-resolve';
1213
import { terser } from 'rollup-plugin-terser';
1314
import alias from 'rollup-plugin-alias';
@@ -18,7 +19,7 @@ import prettyBytes from 'pretty-bytes';
1819
import typescript from 'rollup-plugin-typescript2';
1920
import json from 'rollup-plugin-json';
2021
import logError from './log-error';
21-
import { readFile, isDir, isFile, stdout, stderr } from './utils';
22+
import { readFile, isDir, isFile, stdout, stderr, isTruthy } from './utils';
2223
import camelCase from 'camelcase';
2324

2425
const removeScope = name => name.replace(/^@.*\//, '');
@@ -537,56 +538,31 @@ function createConfig(options, entry, format, writeMeta) {
537538
},
538539
},
539540
}),
540-
babel({
541-
babelrc: false,
542-
configFile: false,
543-
compact: false,
544-
include: 'node_modules/**',
545-
plugins: [
546-
[
547-
require.resolve('babel-plugin-transform-replace-expressions'),
548-
{ replace: defines },
541+
// if defines is not set, we shouldn't run babel through node_modules
542+
isTruthy(defines) &&
543+
babel({
544+
babelrc: false,
545+
configFile: false,
546+
compact: false,
547+
include: 'node_modules/**',
548+
plugins: [
549+
[
550+
require.resolve('babel-plugin-transform-replace-expressions'),
551+
{ replace: defines },
552+
],
549553
],
550-
],
551-
}),
552-
babel({
554+
}),
555+
customBabel({
553556
extensions: EXTENSIONS,
554557
exclude: 'node_modules/**',
555558
passPerPreset: true, // @see https://babeljs.io/docs/en/options#passperpreset
556-
presets: [
557-
[
558-
'@babel/preset-env',
559-
{
560-
loose: true,
561-
modules: false,
562-
targets:
563-
options.target === 'node' ? { node: '8' } : undefined,
564-
exclude: ['transform-async-to-generator'],
565-
},
566-
],
567-
!useTypescript && ['@babel/preset-flow', { all: true }],
568-
].filter(Boolean),
569-
plugins: [
570-
[
571-
require.resolve('@babel/plugin-transform-react-jsx'),
572-
{
573-
pragma: options.jsx || 'h',
574-
pragmaFrag: options.jsxFragment || 'Fragment',
575-
},
576-
],
577-
[
578-
require.resolve('babel-plugin-transform-replace-expressions'),
579-
{ replace: defines },
580-
],
581-
[
582-
require.resolve('babel-plugin-transform-async-to-promises'),
583-
{ inlineHelpers: true, externalHelpers: true },
584-
],
585-
[
586-
require.resolve('@babel/plugin-proposal-class-properties'),
587-
{ loose: true },
588-
],
589-
],
559+
custom: {
560+
defines,
561+
targets: options.target === 'node' ? { node: '8' } : undefined,
562+
pragma: options.jsx || 'h',
563+
pragmaFrag: options.jsxFragment || 'Fragment',
564+
typescript: !!useTypescript,
565+
},
590566
}),
591567
options.compress !== false && [
592568
terser({

src/lib/babel-custom.js

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import { createConfigItem } from '@babel/core';
2+
import babelPlugin from 'rollup-plugin-babel';
3+
import merge from 'lodash.merge';
4+
import { isTruthy } from '../utils';
5+
6+
const mergeConfigItems = (type, ...configItemsToMerge) => {
7+
const mergedItems = [];
8+
9+
configItemsToMerge.forEach(configItemToMerge => {
10+
configItemToMerge.forEach(item => {
11+
const itemToMergeWithIndex = mergedItems.findIndex(
12+
mergedItem => mergedItem.file.resolved === item.file.resolved,
13+
);
14+
15+
if (itemToMergeWithIndex === -1) {
16+
mergedItems.push(item);
17+
return;
18+
}
19+
20+
mergedItems[itemToMergeWithIndex] = createConfigItem(
21+
[
22+
mergedItems[itemToMergeWithIndex].file.resolved,
23+
merge(mergedItems[itemToMergeWithIndex].options, item.options),
24+
],
25+
{
26+
type,
27+
},
28+
);
29+
});
30+
});
31+
32+
return mergedItems;
33+
};
34+
35+
const createConfigItems = (type, items) => {
36+
return items.map(({ name, ...options }) => {
37+
return createConfigItem([require.resolve(name), options], { type });
38+
});
39+
};
40+
41+
export default babelPlugin.custom(babelCore => {
42+
return {
43+
// Passed the plugin options.
44+
options({ custom: customOptions, ...pluginOptions }) {
45+
return {
46+
// Pull out any custom options that the plugin might have.
47+
customOptions,
48+
49+
// Pass the options back with the two custom options removed.
50+
pluginOptions,
51+
};
52+
},
53+
54+
config(config, { customOptions }) {
55+
const defaultPlugins = createConfigItems(
56+
'plugin',
57+
[
58+
{
59+
name: '@babel/plugin-transform-react-jsx',
60+
pragma: customOptions.jsx || 'h',
61+
pragmaFrag: customOptions.jsxFragment || 'Fragment',
62+
},
63+
isTruthy(customOptions.defines) && {
64+
name: 'babel-plugin-transform-replace-expressions',
65+
replace: customOptions.defines,
66+
},
67+
{
68+
name: 'babel-plugin-transform-async-to-promises',
69+
inlineHelpers: true,
70+
externalHelpers: true,
71+
},
72+
{
73+
name: '@babel/plugin-proposal-class-properties',
74+
loose: true,
75+
},
76+
].filter(Boolean),
77+
);
78+
79+
let babelOptions = {
80+
presets: [],
81+
plugins: [],
82+
};
83+
if (config.hasFilesystemConfig()) {
84+
babelOptions = config.options;
85+
86+
if (babelOptions.presets) {
87+
babelOptions.presets = babelOptions.presets.map(preset => {
88+
// When preset-env is configured we want to make sure we override some settings.
89+
// We want to make sure microbundle is still fast & creates small bundles
90+
if (preset.file.request === '@babel/preset-env') {
91+
preset = createConfigItem(
92+
[
93+
preset.file.resolved,
94+
merge(
95+
{
96+
loose: true,
97+
targets: customOptions.targets,
98+
},
99+
preset.options,
100+
{
101+
modules: false,
102+
exclude: merge(
103+
['transform-async-to-generator'],
104+
preset.options.exclude || [],
105+
),
106+
},
107+
),
108+
],
109+
{
110+
type: `preset`,
111+
},
112+
);
113+
}
114+
115+
return preset;
116+
});
117+
}
118+
} else {
119+
babelOptions.presets = createConfigItems('preset', [
120+
{
121+
name: '@babel/preset-env',
122+
targets: customOptions.targets,
123+
modules: false,
124+
loose: true,
125+
exclude: ['transform-async-to-generator'],
126+
},
127+
]);
128+
}
129+
130+
// Merge babelrc & our plugins together
131+
babelOptions.plugins = mergeConfigItems(
132+
'plugin',
133+
defaultPlugins,
134+
babelOptions.plugins || [],
135+
);
136+
137+
return babelOptions;
138+
},
139+
};
140+
});

src/utils.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,11 @@ export const isFile = name =>
1414
.catch(() => false);
1515
export const stdout = console.log.bind(console); // eslint-disable-line no-console
1616
export const stderr = console.error.bind(console);
17+
18+
export const isTruthy = obj => {
19+
if (!obj) {
20+
return false;
21+
}
22+
23+
return obj.constructor !== Object || Object.keys(obj).length > 0;
24+
};

test/__snapshots__/index.test.js.snap

Lines changed: 107 additions & 13 deletions
Large diffs are not rendered by default.

test/fixtures/custom-babelrc/.babelrc

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"presets": [
3+
[
4+
"@babel/preset-env",
5+
{
6+
"loose": true,
7+
"modules": false,
8+
"useBuiltIns": "usage",
9+
"corejs": 3,
10+
"targets": {
11+
"esmodules": true
12+
}
13+
}
14+
]
15+
],
16+
"plugins": [
17+
[
18+
"@babel/plugin-proposal-class-properties",
19+
{
20+
"loose": false
21+
}
22+
]
23+
]
24+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"name": "custom-babelrc"
3+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export class MyClass {
2+
myFields = ['foo', 'bar'];
3+
async foo() {
4+
return this.myFields.find(item => item === 'bar');
5+
}
6+
}

0 commit comments

Comments
 (0)