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

Commit

Permalink
Recommend explicit babelHelpers option to be used (#339)
Browse files Browse the repository at this point in the history
* Refactored babelHelpers settings - require user declaring which kind of helpers they want to use

* Adjust tests to new babelHelpers logic

* Keep UNRESOLVED_IMPORT warnings out of the console when running tests

* 5.0.0-alpha.0

* Rename skipBabelHelpersCheck to skipPreflightCheck

* Make missing babelHelpers a warning

* 5.0.0-alpha.1

* Use transformAsync in preflight check

* Tweak implementation of the preflight helpers check
  • Loading branch information
Andarist authored Dec 17, 2019
1 parent 33fab39 commit ae788a3
Show file tree
Hide file tree
Showing 9 changed files with 4,137 additions and 4,116 deletions.
8,008 changes: 4,004 additions & 4,004 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "rollup-plugin-babel",
"version": "4.3.3",
"version": "5.0.0-alpha.1",
"description": "Seamless integration between Rollup and Babel.",
"main": "dist/rollup-plugin-babel.cjs.js",
"module": "dist/rollup-plugin-babel.esm.js",
Expand Down
File renamed without changes.
7 changes: 4 additions & 3 deletions src/constants.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export const INLINE = {};
export const RUNTIME = {};
export const EXTERNAL = {};
export const BUNDLED = 'bundled';
export const INLINE = 'inline';
export const RUNTIME = 'runtime';
export const EXTERNAL = 'external';

// NOTE: DO NOT REMOVE the null character `\0` as it may be used by other plugins
// e.g. https://github.com/rollup/rollup-plugin-node-resolve/blob/313a3e32f432f9eb18cc4c231cc7aac6df317a51/src/index.js#L74
Expand Down
73 changes: 41 additions & 32 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as babel from '@babel/core';
import { createFilter } from 'rollup-pluginutils';
import { EXTERNAL, HELPERS, RUNTIME } from './constants.js';
import helperPlugin from './helperPlugin.js';
import createPreflightCheck from './preflightCheck.js';
import { RUNTIME, EXTERNAL, BUNDLED, INLINE, HELPERS } from './constants.js';
import bundledHelpersPlugin from './bundledHelpersPlugin.js';
import preflightCheck from './preflightCheck.js';
import transformCode from './transformCode';
import { addBabelPlugin, escapeRegExpCharacters, warnOnce } from './utils.js';

Expand All @@ -26,16 +26,29 @@ const unpackOptions = ({
},
});

const unpackInputPluginOptions = options =>
unpackOptions({
...options,
const unpackInputPluginOptions = ({ skipPreflightCheck = false, ...rest }) => {
if (!rest.babelHelpers) {
console.warn(
'You should specify how do you want to bundle/import "Babel helpers" (runtime functions inserted by Babel which are used by some transformations).\n\n' +
`Please pass \`babelHelpers\` option to the rollup-plugin-babel with one of the following values ("${BUNDLED}" is the default):\n` +
` - "${RUNTIME}" - you should use it especially when building libraries with rollup. It has to be used in combination with \`@babel/plugin-transform-runtime\` and you should also specify \`@babel/runtime\` as dependency of your package (don't forget to tell rollup to treat it is your external dependency when bundling for cjs & esm formats).\n` +
` - "${BUNDLED}" - you should use it if you want your resulting bundle to contain those helpers (at most one copy of each). Useful especially if you bundle an application code.\n` +
` - "${EXTERNAL}" - use it only if you know what you are doing. It will reference helpers on **global** \`babelHelpers\` object. Used most commonly in combination with \`@babel/plugin-external-helpers\`.\n` +
` - "${INLINE}" - this is not recommended. Helpers will be inserted in each file using them, this can cause serious code duplication (this is default Babel behaviour)\n`,
);
}
return unpackOptions({
...rest,
skipPreflightCheck,
babelHelpers: rest.babelHelpers || BUNDLED,
caller: {
supportsStaticESM: true,
supportsDynamicImport: true,
supportsTopLevelAwait: true,
...options.caller,
...rest.caller,
},
});
};

const unpackOutputPluginOptions = (options, { format }) =>
unpackOptions({
Expand Down Expand Up @@ -75,14 +88,12 @@ function createBabelInputPluginFactory(customCallback = returnObject) {
const {
exclude,
extensions,
externalHelpers,
externalHelpersWhitelist,
babelHelpers,
include,
runtimeHelpers,
skipPreflightCheck,
...babelOptions
} = unpackInputPluginOptions(pluginOptionsWithOverrides);

const preflightCheck = createPreflightCheck(true);
const extensionRegExp = new RegExp(`(${extensions.map(escapeRegExpCharacters).join('|')})$`);
const includeExcludeFilter = createFilter(include, exclude);
const filter = id => extensionRegExp.test(id) && includeExcludeFilter(id);
Expand All @@ -95,33 +106,31 @@ function createBabelInputPluginFactory(customCallback = returnObject) {
},

load(id) {
if (id === HELPERS) return babel.buildExternalHelpers(externalHelpersWhitelist, 'module');
if (id === HELPERS) return babel.buildExternalHelpers(null, 'module');
},

transform(code, filename) {
if (!filter(filename)) return null;
if (filename === HELPERS) return null;

return transformCode(code, { ...babelOptions, filename }, overrides, customOptions, this, transformOptions => {
const helpers = preflightCheck(this, transformOptions);

if (helpers === EXTERNAL && !externalHelpers) {
warnOnce(
this,
'Using "external-helpers" plugin with rollup-plugin-babel is deprecated, as it now automatically deduplicates your Babel helpers.',
);
} else if (helpers === RUNTIME && !runtimeHelpers) {
this.error(
'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',
);
}

if (helpers !== RUNTIME && !externalHelpers) {
return addBabelPlugin(transformOptions, helperPlugin);
}

return transformOptions;
});
return transformCode(
code,
{ ...babelOptions, filename },
overrides,
customOptions,
this,
async transformOptions => {
if (!skipPreflightCheck) {
await preflightCheck(this, babelHelpers, transformOptions);
}

if (babelHelpers === BUNDLED) {
transformOptions = addBabelPlugin(transformOptions, bundledHelpersPlugin);
}

return transformOptions;
},
);
},
};
};
Expand Down
74 changes: 40 additions & 34 deletions src/preflightCheck.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as babel from '@babel/core';
import { INLINE, RUNTIME, EXTERNAL } from './constants.js';
import { INLINE, RUNTIME, EXTERNAL, BUNDLED } from './constants.js';
import { addBabelPlugin } from './utils.js';

const MODULE_ERROR =
Expand All @@ -15,52 +15,58 @@ const UNEXPECTED_ERROR =
'An unexpected situation arose. Please raise an issue at ' +
'https://github.com/rollup/rollup-plugin-babel/issues. Thanks!';

function fallbackClassTransform() {
const PREFLIGHT_TEST_STRING = '__ROLLUP__PREFLIGHT_CHECK_DO_NOT_TOUCH__';
const PREFLIGHT_INPUT = `export default "${PREFLIGHT_TEST_STRING}";`;

function helpersTestTransform() {
return {
visitor: {
ClassDeclaration(path, state) {
path.replaceWith(state.file.addHelper('inherits'));
StringLiteral(path, state) {
if (path.node.value === PREFLIGHT_TEST_STRING) {
path.replaceWith(state.file.addHelper('inherits'));
}
},
},
};
}

export default function createPreflightCheck() {
let preflightCheckResults = {};

return (ctx, options) => {
const key = options.filename;
const mismatchError = (actual, expected, filename) =>
`You have declared using "${expected}" babelHelpers, but transforming ${filename} resulted in "${actual}". Please check your configuration.`;

if (preflightCheckResults[key] === undefined) {
let helpers;
const inheritsHelperRe = /\/helpers\/(esm\/)?inherits/;

const inputCode = 'class Foo extends Bar {};\nexport default Foo;';
const transformed = babel.transformSync(inputCode, options);
export default async function preflightCheck(ctx, babelHelpers, transformOptions) {
const finalOptions = addBabelPlugin(transformOptions, helpersTestTransform);
const check = (await babel.transformAsync(PREFLIGHT_INPUT, finalOptions)).code;

let check = transformed.code;
// Babel sometimes splits ExportDefaultDeclaration into 2 statements, so we also check for ExportNamedDeclaration
if (!/export (d|{)/.test(check)) {
ctx.error(MODULE_ERROR);
}

if (~check.indexOf('class ')) {
check = babel.transformSync(inputCode, addBabelPlugin(options, fallbackClassTransform)).code;
}

if (
!~check.indexOf('export default') &&
!~check.indexOf('export default Foo') &&
!~check.indexOf('export { Foo as default }')
) {
ctx.error(MODULE_ERROR);
}
if (inheritsHelperRe.test(check)) {
if (babelHelpers === RUNTIME) {
return;
}
ctx.error(mismatchError(RUNTIME, babelHelpers, transformOptions.filename));
}

if (check.match(/\/helpers\/(esm\/)?inherits/)) helpers = RUNTIME;
else if (~check.indexOf('function _inherits')) helpers = INLINE;
else if (~check.indexOf('babelHelpers')) helpers = EXTERNAL;
else {
ctx.error(UNEXPECTED_ERROR);
}
if (~check.indexOf('babelHelpers.inherits')) {
if (babelHelpers === EXTERNAL) {
return;
}
ctx.error(mismatchError(EXTERNAL, babelHelpers, transformOptions.filename));
}

preflightCheckResults[key] = helpers;
if (~check.indexOf('function _inherits')) {
if (babelHelpers === INLINE || babelHelpers === BUNDLED) {
return;
}
if (babelHelpers === RUNTIME && !transformOptions.plugins.length) {
ctx.error(`You must use the \`@babel/plugin-transform-runtime\` plugin when \`babelHelpers\` is "${RUNTIME}".\n`);
}
ctx.error(mismatchError(INLINE, babelHelpers, transformOptions.filename));
}

return preflightCheckResults[key];
};
ctx.error(UNEXPECTED_ERROR);
}
11 changes: 9 additions & 2 deletions src/transformCode.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as babel from '@babel/core';
export default async function transformCode(inputCode, babelOptions, overrides, customOptions, ctx, finalizeOptions) {
const config = babel.loadPartialConfig(babelOptions);

// file is ignored by babel
if (!config) {
return null;
}
Expand All @@ -20,7 +21,10 @@ export default async function transformCode(inputCode, babelOptions, overrides,

if (!overrides.result) {
const { code, map } = await babel.transformAsync(inputCode, transformOptions);
return { code, map };
return {
code,
map,
};
}

const result = await babel.transformAsync(inputCode, transformOptions);
Expand All @@ -30,5 +34,8 @@ export default async function transformCode(inputCode, babelOptions, overrides,
config,
transformOptions,
});
return { code, map };
return {
code,
map,
};
}
5 changes: 4 additions & 1 deletion src/utils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export const addBabelPlugin = (options, plugin) => ({ ...options, plugins: options.plugins.concat(plugin) });
export const addBabelPlugin = (options, plugin) => ({
...options,
plugins: options.plugins.concat(plugin),
});

let warned = {};
export function warnOnce(ctx, msg) {
Expand Down
Loading

0 comments on commit ae788a3

Please sign in to comment.