mirror of
https://github.com/developit/microbundle.git
synced 2026-01-25 14:06:50 +00:00
Add fast rest parameters transform
This commit is contained in:
parent
e082be1672
commit
d0ca19157e
@ -1,6 +1,7 @@
|
||||
import { createConfigItem } from '@babel/core';
|
||||
import babelPlugin from 'rollup-plugin-babel';
|
||||
import merge from 'lodash.merge';
|
||||
import transformFastRest from './transform-fast-rest';
|
||||
import { isTruthy } from '../utils';
|
||||
|
||||
const ESMODULES_TARGET = {
|
||||
@ -13,7 +14,9 @@ const mergeConfigItems = (type, ...configItemsToMerge) => {
|
||||
configItemsToMerge.forEach(configItemToMerge => {
|
||||
configItemToMerge.forEach(item => {
|
||||
const itemToMergeWithIndex = mergedItems.findIndex(
|
||||
mergedItem => mergedItem.file.resolved === item.file.resolved,
|
||||
mergedItem =>
|
||||
(mergedItem.name || mergedItem.file.resolved) ===
|
||||
(item.name || item.file.resolved),
|
||||
);
|
||||
|
||||
if (itemToMergeWithIndex === -1) {
|
||||
@ -37,8 +40,10 @@ const mergeConfigItems = (type, ...configItemsToMerge) => {
|
||||
};
|
||||
|
||||
const createConfigItems = (type, items) => {
|
||||
return items.map(({ name, ...options }) => {
|
||||
return createConfigItem([require.resolve(name), options], { type });
|
||||
return items.map(item => {
|
||||
let { name, value, ...options } = item;
|
||||
value = value || [require.resolve(name), options];
|
||||
return createConfigItem(value, { type });
|
||||
});
|
||||
};
|
||||
|
||||
@ -59,6 +64,9 @@ export default () => {
|
||||
},
|
||||
|
||||
config(config, { customOptions }) {
|
||||
const targets = customOptions.targets;
|
||||
const isNodeTarget = targets && targets.node != null;
|
||||
|
||||
const defaultPlugins = createConfigItems(
|
||||
'plugin',
|
||||
[
|
||||
@ -80,6 +88,18 @@ export default () => {
|
||||
externalHelpers: false,
|
||||
minify: true,
|
||||
},
|
||||
!customOptions.modern &&
|
||||
!isNodeTarget && {
|
||||
value: [
|
||||
transformFastRest,
|
||||
{
|
||||
// Use inline [].slice.call(arguments)
|
||||
helper: false,
|
||||
literal: true,
|
||||
},
|
||||
'transform-fast-rest',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: '@babel/plugin-proposal-class-properties',
|
||||
loose: true,
|
||||
|
||||
90
src/lib/transform-fast-rest.js
Normal file
90
src/lib/transform-fast-rest.js
Normal file
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* @type {import('@babel/core')}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Transform ...rest parameters to [].slice.call(arguments,offset).
|
||||
* Demo: https://astexplorer.net/#/gist/70aaa0306db9a642171ef3e2f35df2e0/576c150f647e4936fa6960e0453a11cdc5d81f21
|
||||
* Benchmark: https://jsperf.com/rest-arguments-babel-pr-9152/4
|
||||
* @param {object} opts
|
||||
* @param {babel.template} opts.template
|
||||
* @param {babel.types} opts.types
|
||||
* @returns {babel.PluginObj}
|
||||
*/
|
||||
export default function fastRestTransform({ template, types: t }) {
|
||||
const slice = template`var IDENT = Array.prototype.slice;`;
|
||||
|
||||
const VISITOR = {
|
||||
RestElement(path, state) {
|
||||
if (path.parentKey !== 'params') return;
|
||||
|
||||
// Create a global _slice alias
|
||||
let slice = state.get('slice');
|
||||
if (!slice) {
|
||||
slice = path.scope.generateUidIdentifier('slice');
|
||||
state.set('slice', slice);
|
||||
}
|
||||
|
||||
// _slice.call(arguments) or _slice.call(arguments, 1)
|
||||
const args = [t.identifier('arguments')];
|
||||
if (path.key) args.push(t.numericLiteral(path.key));
|
||||
const sliced = t.callExpression(
|
||||
t.memberExpression(t.clone(slice), t.identifier('call')),
|
||||
args,
|
||||
);
|
||||
|
||||
const ident = path.node.argument;
|
||||
const binding = path.scope.getBinding(ident.name);
|
||||
|
||||
if (binding.referencePaths.length !== 0) {
|
||||
// arguments access requires a non-Arrow function:
|
||||
const func = path.parentPath;
|
||||
if (t.isArrowFunctionExpression(func)) {
|
||||
func.arrowFunctionToExpression();
|
||||
}
|
||||
|
||||
if (binding.constant && binding.referencePaths.length === 1) {
|
||||
// one usage, never assigned - replace usage inline
|
||||
binding.referencePaths[0].replaceWith(sliced);
|
||||
} else {
|
||||
// unknown usage, create a binding
|
||||
const decl = t.variableDeclaration('var', [
|
||||
t.variableDeclarator(t.clone(ident), sliced),
|
||||
]);
|
||||
func.get('body').unshiftContainer('body', decl);
|
||||
}
|
||||
}
|
||||
|
||||
path.remove();
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
name: 'transform-fast-rest',
|
||||
visitor: {
|
||||
Program(path, state) {
|
||||
const childState = new Map();
|
||||
const useHelper = state.opts.helper === true; // defaults to false
|
||||
|
||||
if (!useHelper) {
|
||||
let inlineHelper;
|
||||
if (state.opts.literal === false) {
|
||||
inlineHelper = template.expression.ast`Array.prototype.slice`;
|
||||
} else {
|
||||
inlineHelper = template.expression.ast`[].slice`;
|
||||
}
|
||||
childState.set('slice', inlineHelper);
|
||||
}
|
||||
|
||||
path.traverse(VISITOR, childState);
|
||||
|
||||
const name = childState.get('slice');
|
||||
if (name && useHelper) {
|
||||
const helper = slice({ IDENT: name });
|
||||
t.addComment(helper.declarations[0].init, 'leading', '#__PURE__');
|
||||
path.unshiftContainer('body', helper);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user