Skip to content
This repository was archived by the owner on Aug 4, 2021. It is now read-only.

Commit 97ac95b

Browse files
committedJan 10, 2019
Merge branch 'custom-builder'
2 parents ba2559a + f250dea commit 97ac95b

8 files changed

+472
-490
lines changed
 

‎.eslintrc

+17-24
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,19 @@
11
{
2-
"rules": {
3-
"indent": [ 2, "tab", { "SwitchCase": 1 } ],
4-
"quotes": [ 2, "single" , { "avoidEscape": true }],
5-
"linebreak-style": [ 2, "unix" ],
6-
"semi": [ 2, "always" ],
7-
"keyword-spacing": [ 2, { "before": true, "after": true } ],
8-
"space-before-blocks": [ 2, "always" ],
9-
"no-mixed-spaces-and-tabs": [ 2, "smart-tabs" ],
10-
"no-cond-assign": [ 0 ],
11-
},
12-
"env": {
13-
"es6": true,
14-
"browser": true,
15-
"mocha": true,
16-
"node": true
17-
},
18-
"extends": "eslint:recommended",
19-
"parserOptions": {
20-
"sourceType": "module",
21-
"ecmaVersion": 2018,
22-
"ecmaFeatures": {
23-
"spread": true
24-
}
25-
}
2+
"extends": ["eslint:recommended", "prettier", "plugin:prettier/recommended"],
3+
"rules": {
4+
"no-cond-assign": [0]
5+
},
6+
"env": {
7+
"es6": true,
8+
"browser": true,
9+
"mocha": true,
10+
"node": true
11+
},
12+
"parserOptions": {
13+
"sourceType": "module",
14+
"ecmaVersion": 2018,
15+
"ecmaFeatures": {
16+
"spread": true
17+
}
18+
}
2619
}

‎README.md

+63-4
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,10 @@ However, setting `modules: false` in your `.babelrc` may conflict if you are usi
105105

106106
```js
107107
plugins: [
108-
babel({
109-
babelrc: false,
110-
presets: [['env', { modules: false }]],
111-
}),
108+
babel({
109+
babelrc: false,
110+
presets: [['env', { modules: false }]],
111+
}),
112112
];
113113
```
114114

@@ -137,6 +137,65 @@ npm install --save-dev rollup-plugin-babel@3 babel-preset-env babel-plugin-exter
137137
}
138138
```
139139

140+
## Custom plugin builder
141+
142+
`rollup-plugin-babel` exposes a plugin-builder utility that allows users to add custom handling of Babel's configuration for each file that it processes.
143+
144+
`.custom` accepts a callback that will be called with the loader's instance of `babel` so that tooling can ensure that it using exactly the same `@babel/core` instance as the loader itself.
145+
146+
It's main purpose is to allow other tools for configuration of transpilation without forcing people to add extra configuration but still allow for using their own babelrc / babel config files.
147+
148+
### Example
149+
150+
```js
151+
import babel from 'rollup-plugin-babel';
152+
153+
export default babel.custom(babelCore => {
154+
function myPlugin() {
155+
return {
156+
visitor: {},
157+
};
158+
}
159+
160+
return {
161+
// Passed the plugin options.
162+
options({ opt1, opt2, ...pluginOptions }) {
163+
return {
164+
// Pull out any custom options that the plugin might have.
165+
customOptions: { opt1, opt2 },
166+
167+
// Pass the options back with the two custom options removed.
168+
pluginOptions,
169+
};
170+
},
171+
172+
config(cfg /* Passed Babel's 'PartialConfig' object. */, { code, customOptions }) {
173+
if (cfg.hasFilesystemConfig()) {
174+
// Use the normal config
175+
return cfg.options;
176+
}
177+
178+
return {
179+
...cfg.options,
180+
plugins: [
181+
...(cfg.options.plugins || []),
182+
183+
// Include a custom plugin in the options.
184+
myPlugin,
185+
],
186+
};
187+
},
188+
189+
result(result, { code, customOptions, config, transformOptions }) {
190+
return {
191+
...result,
192+
code: result.code + '\n// Generated by some custom loader',
193+
};
194+
},
195+
};
196+
});
197+
```
198+
140199
## License
141200

142201
MIT

‎package-lock.json

+187-356
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+11-8
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,18 @@
1717
"homepage": "https://github.com/rollup/rollup-plugin-babel",
1818
"author": "Rich Harris",
1919
"contributors": [
20-
"Bogdan Chadkin <trysound@yandex.ru>"
20+
"Bogdan Chadkin <trysound@yandex.ru>",
21+
"Mateusz Burzyński <mateuszburzynski@gmail.com> (https://github.com/Andarist)"
2122
],
2223
"license": "MIT",
2324
"scripts": {
24-
"test": "mocha",
25-
"prepare": "npm run build",
26-
"prepublish": "npm run lint && npm test",
25+
"lint": "eslint src",
2726
"pretest": "npm run build",
28-
"build": "rollup -c",
27+
"test": "mocha",
2928
"prebuild": "rm -rf dist/*",
30-
"lint": "eslint src"
29+
"build": "rollup -c",
30+
"prepare": "npm run build",
31+
"preversion": "npm run lint && npm test"
3132
},
3233
"dependencies": {
3334
"@babel/helper-module-imports": "^7.0.0",
@@ -44,11 +45,13 @@
4445
"@babel/plugin-transform-runtime": "^7.0.0",
4546
"@babel/preset-env": "^7.0.0",
4647
"buble": "^0.19.3",
47-
"eslint": "^5.0.1",
48+
"eslint": "^5.11.0",
49+
"eslint-config-prettier": "^3.3.0",
50+
"eslint-plugin-prettier": "^3.0.0",
4851
"husky": "^1.0.1",
4952
"lint-staged": "^7.2.2",
5053
"mocha": "^5.2.0",
51-
"prettier": "^1.14.2",
54+
"prettier": "^1.15.3",
5255
"rollup": "^1.0.0",
5356
"rollup-plugin-buble": "^0.19.2",
5457
"rollup-plugin-json": "^3.0.0",

‎src/index.js

+99-79
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import { buildExternalHelpers, DEFAULT_EXTENSIONS, loadPartialConfig, transform } from '@babel/core';
1+
import * as babel from '@babel/core';
22
import { createFilter } from 'rollup-pluginutils';
33
import createPreflightCheck from './preflightCheck.js';
44
import helperPlugin from './helperPlugin.js';
5-
import { escapeRegExpCharacters, warnOnce } from './utils.js';
5+
import { addBabelPlugin, escapeRegExpCharacters, warnOnce } from './utils.js';
66
import { RUNTIME, EXTERNAL, HELPERS } from './constants.js';
77

88
const unpackOptions = ({
9-
extensions = DEFAULT_EXTENSIONS,
9+
extensions = babel.DEFAULT_EXTENSIONS,
1010
// rollup uses sourcemap, babel uses sourceMaps
1111
// just normalize them here so people don't have to worry about it
1212
sourcemap = true,
@@ -27,87 +27,107 @@ const unpackOptions = ({
2727
},
2828
});
2929

30-
export default function babel(options) {
31-
// TODO: remove it later, just provide a helpful warning to people for now
32-
try {
33-
loadPartialConfig({
34-
caller: undefined,
35-
babelrc: false,
36-
configFile: false,
37-
});
38-
} catch (err) {
39-
throw new Error(
40-
'You should be using @babel/core@^7.0.0-rc.2. Please upgrade or pin rollup-plugin-babel to 4.0.0-beta.8',
41-
);
42-
}
43-
44-
const {
45-
exclude,
46-
extensions,
47-
externalHelpers,
48-
externalHelpersWhitelist,
49-
include,
50-
runtimeHelpers,
51-
...babelOptions
52-
} = unpackOptions(options);
53-
54-
const extensionRegExp = new RegExp(`(${extensions.map(escapeRegExpCharacters).join('|')})$`);
55-
const includeExcludeFilter = createFilter(include, exclude);
56-
const filter = id => extensionRegExp.test(id) && includeExcludeFilter(id);
57-
const preflightCheck = createPreflightCheck();
58-
59-
return {
60-
name: 'babel',
61-
62-
resolveId(id) {
63-
if (id === HELPERS) return id;
64-
},
65-
66-
load(id) {
67-
if (id !== HELPERS) {
68-
return;
69-
}
70-
71-
return buildExternalHelpers(externalHelpersWhitelist, 'module');
72-
},
30+
const returnObject = () => ({});
7331

74-
transform(code, id) {
75-
if (!filter(id)) return null;
76-
if (id === HELPERS) return null;
32+
function createBabelPluginFactory(customCallback = returnObject) {
33+
const overrides = customCallback(babel);
7734

78-
const helpers = preflightCheck(this, babelOptions, id);
35+
return pluginOptions => {
36+
let customOptions = null;
7937

80-
if (!helpers) {
81-
return null;
82-
}
38+
if (overrides.options) {
39+
const overridden = overrides.options(pluginOptions);
8340

84-
if (helpers === EXTERNAL && !externalHelpers) {
85-
warnOnce(
86-
this,
87-
'Using "external-helpers" plugin with rollup-plugin-babel is deprecated, as it now automatically deduplicates your Babel helpers.',
88-
);
89-
} else if (helpers === RUNTIME && !runtimeHelpers) {
90-
this.error(
91-
'Runtime helpers are not enabled. Either exclude the transform-runtime Babel plugin or pass the `runtimeHelpers: true` option. See https://github.com/rollup/rollup-plugin-babel#configuring-babel for more information',
41+
if (typeof overridden.then === 'function') {
42+
throw new Error(
43+
".options hook can't be asynchronous. It should return `{ customOptions, pluginsOptions }` synchronously.",
9244
);
9345
}
94-
95-
const localOpts = {
96-
filename: id,
97-
...babelOptions,
98-
plugins: helpers !== RUNTIME ? [...babelOptions.plugins, helperPlugin] : babelOptions.plugins,
99-
};
100-
101-
const transformed = transform(code, localOpts);
102-
103-
if (!transformed) {
104-
return null;
105-
}
106-
107-
return {
108-
code: transformed.code,
109-
map: transformed.map,
110-
};
111-
},
46+
({ customOptions = null, pluginOptions } = overridden);
47+
}
48+
49+
const {
50+
exclude,
51+
extensions,
52+
externalHelpers,
53+
externalHelpersWhitelist,
54+
include,
55+
runtimeHelpers,
56+
...babelOptions
57+
} = unpackOptions(pluginOptions);
58+
59+
const extensionRegExp = new RegExp(`(${extensions.map(escapeRegExpCharacters).join('|')})$`);
60+
const includeExcludeFilter = createFilter(include, exclude);
61+
const filter = id => extensionRegExp.test(id) && includeExcludeFilter(id);
62+
const preflightCheck = createPreflightCheck();
63+
64+
return {
65+
name: 'babel',
66+
resolveId(id) {
67+
if (id === HELPERS) return id;
68+
},
69+
load(id) {
70+
if (id !== HELPERS) {
71+
return;
72+
}
73+
74+
return babel.buildExternalHelpers(externalHelpersWhitelist, 'module');
75+
},
76+
transform(code, filename) {
77+
if (!filter(filename)) return Promise.resolve(null);
78+
if (filename === HELPERS) return Promise.resolve(null);
79+
80+
const config = babel.loadPartialConfig({ ...babelOptions, filename });
81+
82+
// file is ignored
83+
if (!config) {
84+
return Promise.resolve(null);
85+
}
86+
87+
return Promise.resolve(
88+
!overrides.config
89+
? config.options
90+
: overrides.config.call(this, config, {
91+
code,
92+
customOptions,
93+
}),
94+
).then(transformOptions => {
95+
const helpers = preflightCheck(this, transformOptions);
96+
97+
if (helpers === EXTERNAL && !externalHelpers) {
98+
warnOnce(
99+
this,
100+
'Using "external-helpers" plugin with rollup-plugin-babel is deprecated, as it now automatically deduplicates your Babel helpers.',
101+
);
102+
} else if (helpers === RUNTIME && !runtimeHelpers) {
103+
this.error(
104+
'Runtime helpers are not enabled. Either exclude the transform-runtime Babel plugin or pass the `runtimeHelpers: true` option. See https://github.com/rollup/rollup-plugin-babel#configuring-babel for more information',
105+
);
106+
}
107+
108+
if (helpers !== RUNTIME) {
109+
transformOptions = addBabelPlugin(transformOptions, helperPlugin);
110+
}
111+
112+
const result = babel.transformSync(code, transformOptions);
113+
114+
return Promise.resolve(
115+
!overrides.result
116+
? result
117+
: overrides.result.call(this, result, {
118+
code,
119+
customOptions,
120+
config,
121+
transformOptions,
122+
}),
123+
).then(({ code, map }) => ({ code, map }));
124+
});
125+
},
126+
};
112127
};
113128
}
129+
130+
const babelPluginFactory = createBabelPluginFactory();
131+
babelPluginFactory.custom = createBabelPluginFactory;
132+
133+
export default babelPluginFactory;

‎src/preflightCheck.js

+10-19
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { join, dirname } from 'path';
2-
import { transform } from '@babel/core';
1+
import { transformSync } from '@babel/core';
32
import { INLINE, RUNTIME, EXTERNAL } from './constants.js';
3+
import { addBabelPlugin } from './utils.js';
44

55
const MODULE_ERROR =
66
'Rollup requires that your Babel configuration keeps ES6 module syntax intact. ' +
@@ -28,28 +28,19 @@ function fallbackClassTransform() {
2828
export default function createPreflightCheck() {
2929
let preflightCheckResults = {};
3030

31-
return (ctx, options, file) => {
32-
if (preflightCheckResults[file] === undefined) {
33-
let helpers;
34-
35-
options = Object.assign({}, options);
36-
delete options.only;
37-
delete options.ignore;
31+
return (ctx, options) => {
32+
const key = options.filename;
3833

39-
options.filename = join(dirname(file), 'x.js');
34+
if (preflightCheckResults[key] === undefined) {
35+
let helpers;
4036

4137
const inputCode = 'class Foo extends Bar {};\nexport default Foo;';
42-
const transformed = transform(inputCode, options);
43-
44-
if (!transformed) {
45-
return (preflightCheckResults[file] = null);
46-
}
38+
const transformed = transformSync(inputCode, options);
4739

4840
let check = transformed.code;
4941

5042
if (~check.indexOf('class ')) {
51-
options.plugins = (options.plugins || []).concat(fallbackClassTransform);
52-
check = transform(inputCode, options).code;
43+
check = transformSync(inputCode, addBabelPlugin(options, fallbackClassTransform)).code;
5344
}
5445

5546
if (
@@ -67,9 +58,9 @@ export default function createPreflightCheck() {
6758
ctx.error(UNEXPECTED_ERROR);
6859
}
6960

70-
preflightCheckResults[file] = helpers;
61+
preflightCheckResults[key] = helpers;
7162
}
7263

73-
return preflightCheckResults[file];
64+
return preflightCheckResults[key];
7465
};
7566
}

‎src/utils.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
export const addBabelPlugin = (options, plugin) => ({ ...options, plugins: options.plugins.concat(plugin) });
2+
13
let warned = {};
24
export function warnOnce(ctx, msg) {
35
if (warned[msg]) return;

‎test/test.js

+83
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,20 @@ function getLocation(source, charIndex) {
3333
throw new Error('Could not determine location of character');
3434
}
3535

36+
function replaceConsoleLogProperty() {
37+
return {
38+
name: 'replace-console-log-property',
39+
visitor: {
40+
MemberExpression(path, state) {
41+
const opts = state.opts;
42+
if (path.node.property.name === 'log') {
43+
path.node.property.name = opts.replace;
44+
}
45+
},
46+
},
47+
};
48+
}
49+
3650
describe('rollup-plugin-babel', function() {
3751
this.timeout(15000);
3852

@@ -264,4 +278,73 @@ describe('rollup-plugin-babel', function() {
264278
},
265279
);
266280
});
281+
282+
it('supports customizing the loader', () => {
283+
const customBabelPlugin = babelPlugin.custom(() => {
284+
return {
285+
config(cfg) {
286+
return Object.assign({}, cfg.options, {
287+
plugins: [
288+
...(cfg.options.plugins || []),
289+
290+
// Include a custom plugin in the options.
291+
[replaceConsoleLogProperty, { replace: 'foobaz' }],
292+
],
293+
});
294+
},
295+
result(result) {
296+
return Object.assign({}, result, { code: result.code + '\n// Generated by some custom loader' });
297+
},
298+
};
299+
});
300+
return rollup
301+
.rollup({ input: 'samples/basic/main.js', plugins: [customBabelPlugin()] })
302+
.then(bundle => {
303+
return bundle.generate({ format: 'cjs' });
304+
})
305+
.then(({ output: [{ code }] }) => {
306+
assert.ok(code.includes('// Generated by some custom loader'), 'adds the custom comment');
307+
assert.ok(code.includes('console.foobaz'), 'runs the plugin');
308+
});
309+
});
310+
311+
it('supports overriding the plugin options in custom loader', () => {
312+
const customBabelPlugin = babelPlugin.custom(() => {
313+
return {
314+
options(options) {
315+
// Ignore the js extension to test overriding the options
316+
return { pluginOptions: Object.assign({}, options, { extensions: ['.x'] }) };
317+
},
318+
config(cfg) {
319+
return Object.assign({}, cfg.options, {
320+
plugins: [
321+
...(cfg.options.plugins || []),
322+
// Include a custom plugin in the options.
323+
[replaceConsoleLogProperty, { replace: 'foobaz' }],
324+
],
325+
});
326+
},
327+
result(result) {
328+
return Object.assign({}, result, { code: result.code + '\n// Generated by some custom loader' });
329+
},
330+
};
331+
});
332+
return rollup
333+
.rollup({ input: 'samples/basic/main.js', plugins: [customBabelPlugin()] })
334+
.then(bundle => {
335+
return bundle.generate({ format: 'cjs' });
336+
})
337+
.then(({ output: [{ code }] }) => {
338+
assert.ok(!code.includes('// Generated by some custom loader'), 'does not add the comment to ignored file');
339+
assert.ok(!code.includes('console.foobaz'), 'does not run the plugin on ignored file');
340+
});
341+
});
342+
343+
it('uses babel plugins passed in to the rollup plugin', () => {
344+
return bundle('samples/basic/main.js', {
345+
plugins: [[replaceConsoleLogProperty, { replace: 'foobaz' }]],
346+
}).then(({ code }) => {
347+
assert.ok(code.indexOf('console.foobaz') !== -1);
348+
});
349+
});
267350
});

0 commit comments

Comments
 (0)
This repository has been archived.