@parcel/scope-hoisting
Advanced tools
Comparing version 2.0.0-nightly.214 to 2.0.0-nightly.219
@@ -40,3 +40,3 @@ "use strict"; | ||
async function concat(bundle, bundleGraph) { | ||
async function concat(bundle, bundleGraph, wrappedAssets) { | ||
let queue = new _utils.PromiseQueue({ | ||
@@ -53,3 +53,3 @@ maxConcurrent: 32 | ||
if (resolved) { | ||
resolved.meta.shouldWrap = true; | ||
wrappedAssets.add(resolved.id); | ||
} | ||
@@ -63,3 +63,3 @@ | ||
case 'asset': | ||
queue.add(() => processAsset(bundle, node.value)); | ||
queue.add(() => processAsset(bundle, node.value, wrappedAssets)); | ||
} | ||
@@ -127,3 +127,3 @@ }); | ||
async function processAsset(bundle, asset) { | ||
async function processAsset(bundle, asset, wrappedAssets) { | ||
let statements; | ||
@@ -139,3 +139,3 @@ | ||
if (asset.meta.shouldWrap) { | ||
if (wrappedAssets.has(asset.id)) { | ||
statements = wrapModule(asset, statements); | ||
@@ -142,0 +142,0 @@ } |
@@ -74,3 +74,3 @@ "use strict"; | ||
if (entry && (!(0, _utils2.isEntry)(bundle, bundleGraph) || (0, _utils2.isReferenced)(bundle, bundleGraph))) { | ||
if (entry && !referencedAssets.has(entry) && (!(0, _utils2.isEntry)(bundle, bundleGraph) || (0, _utils2.isReferenced)(bundle, bundleGraph))) { | ||
let exportsId = (0, _utils2.assertString)(entry.meta.exportsIdentifier); | ||
@@ -77,0 +77,0 @@ exported.add(exportsId); |
@@ -28,7 +28,24 @@ "use strict"; | ||
const REGISTER_TEMPLATE = _template.default.statement('parcelRequire.registerBundle(ID, function () { STATEMENTS; })'); | ||
const REGISTER_TEMPLATE = _template.default.statement(`(function() { | ||
function $parcel$bundleWrapper() { | ||
if ($parcel$bundleWrapper._executed) return; | ||
STATEMENTS; | ||
$parcel$bundleWrapper._executed = true; | ||
} | ||
parcelRequire.registerBundle(ID, $parcel$bundleWrapper); | ||
var $parcel$referencedAssets = REFERENCED_IDS; | ||
for (var $parcel$i = 0; $parcel$i < $parcel$referencedAssets.length; $parcel$i++) { | ||
parcelRequire.registerBundle($parcel$referencedAssets[$parcel$i], $parcel$bundleWrapper); | ||
} | ||
})()`); | ||
const WRAPPER_TEMPLATE = _template.default.statement('(function () { STATEMENTS; })()'); | ||
function generate(bundleGraph, bundle, ast, options) { | ||
function generate({ | ||
bundleGraph, | ||
bundle, | ||
ast, | ||
referencedAssets, | ||
options | ||
}) { | ||
let interpreter; | ||
@@ -51,3 +68,4 @@ | ||
ID: t.stringLiteral((0, _nullthrows.default)(entry).id), | ||
STATEMENTS: statements | ||
STATEMENTS: statements, | ||
REFERENCED_IDS: t.arrayExpression([...referencedAssets].map(asset => t.stringLiteral(asset.id))) | ||
})] : [WRAPPER_TEMPLATE({ | ||
@@ -54,0 +72,0 @@ STATEMENTS: statements |
@@ -48,3 +48,4 @@ "use strict"; | ||
ast, | ||
options | ||
options, | ||
wrappedAssets | ||
}) { | ||
@@ -397,3 +398,3 @@ let format = _index.default[bundle.env.outputFormat]; | ||
if (mod.meta.shouldWrap) { | ||
if (wrappedAssets.has(mod.id)) { | ||
node = t.callExpression((0, _utils.getIdentifier)(mod, 'init'), []); | ||
@@ -609,3 +610,3 @@ } // Replace with nothing if the require call's result is not used. | ||
// not in the current bundle. | ||
let decls = path.pushContainer('body', [...referencedAssets].filter(a => !a.meta.shouldWrap).map(a => { | ||
let decls = path.pushContainer('body', [...referencedAssets].filter(a => !wrappedAssets.has(a.id)).map(a => { | ||
return FAKE_INIT_TEMPLATE({ | ||
@@ -631,3 +632,3 @@ INIT: (0, _utils.getIdentifier)(a, 'init'), | ||
let exported = format.generateExports(bundleGraph, bundle, referencedAssets, path, replacements, options); | ||
(0, _shake.default)(path.scope, exported); | ||
(0, _shake.default)(path.scope, exported, exportsMap); | ||
} | ||
@@ -637,3 +638,6 @@ | ||
}); | ||
return ast; | ||
return { | ||
ast, | ||
referencedAssets | ||
}; | ||
} |
@@ -22,3 +22,3 @@ "use strict"; | ||
*/ | ||
function treeShake(scope, exportedIdentifiers) { | ||
function treeShake(scope, exportedIdentifiers, exportsMap) { | ||
// Keep passing over all bindings in the scope until we don't remove any. | ||
@@ -32,3 +32,3 @@ // This handles cases where we remove one binding which had a reference to | ||
Object.keys(scope.bindings).forEach(name => { | ||
let binding = getUnusedBinding(scope.path, name); // If it is not safe to remove the binding don't touch it. | ||
let binding = getUnusedBinding(scope.path, name, exportsMap); // If it is not safe to remove the binding don't touch it. | ||
@@ -41,3 +41,3 @@ if (!binding || exportedIdentifiers.has(name)) { | ||
(0, _utils.pathRemove)(binding.path); | ||
[...binding.referencePaths, ...binding.constantViolations].forEach(p => remove(p, scope)); | ||
[...binding.referencePaths, ...binding.constantViolations].forEach(p => remove(p, scope, exportsMap)); | ||
scope.removeBinding(name); | ||
@@ -50,3 +50,3 @@ removed = true; | ||
function getUnusedBinding(path, name) { | ||
function getUnusedBinding(path, name, exportsMap) { | ||
let binding = path.scope.getBinding(name); | ||
@@ -58,3 +58,3 @@ | ||
if (!isPure(binding.path)) { | ||
if (!isPure(binding)) { | ||
// declaration (~= init) isn't pure | ||
@@ -64,2 +64,11 @@ return null; | ||
if (hasSideEffects(binding)) { | ||
// e.g. | ||
// let foo = {}; | ||
// foo = window; | ||
// foo.xyz = 2; | ||
// console.log(window.xyz); | ||
return null; | ||
} | ||
if (!binding.referenced) { | ||
@@ -70,3 +79,3 @@ return binding; | ||
let bailout = binding.referencePaths.some(path => !isExportAssignment(path) && !isWildcardDest(path)); | ||
let bailout = binding.referencePaths.some(path => !isExportAssignment(path, exportsMap) && !isWildcardDest(path)); | ||
@@ -80,4 +89,7 @@ if (!bailout) { | ||
function isPure(path) { | ||
function isPure(binding) { | ||
let { | ||
path | ||
} = binding; | ||
let { | ||
node | ||
@@ -96,8 +108,22 @@ } = path; | ||
function isExportAssignment(path) { | ||
function hasSideEffects(binding) { | ||
let { | ||
node | ||
} = binding.path; | ||
if ((0, _types.isVariableDeclarator)(node)) { | ||
return !((!binding.referenced || (0, _types.isObjectExpression)(node.init)) && (binding.constant || binding.constantViolations.every(({ | ||
node | ||
}) => !(0, _types.isAssignmentExpression)(node) || (0, _types.isObjectExpression)(node.right)))); | ||
} | ||
return false; | ||
} | ||
function isExportAssignment(path, exportsMap) { | ||
let { | ||
parent | ||
} = path; // match "path.foo = bar;" | ||
} = path; // match "path.foo = bar;", where path is a known exports identifier. | ||
if ((0, _types.isMemberExpression)(parent) && parent.object === path.node && ((0, _types.isIdentifier)(parent.property) && !parent.computed || (0, _types.isStringLiteral)(parent.property))) { | ||
if ((0, _types.isMemberExpression)(parent) && parent.object === path.node && (0, _types.isIdentifier)(path.node) && exportsMap.has(path.node.name) && ((0, _types.isIdentifier)(parent.property) && !parent.computed || (0, _types.isStringLiteral)(parent.property))) { | ||
let parentParent = path.parentPath.parent; | ||
@@ -118,3 +144,3 @@ return (0, _types.isAssignmentExpression)(parentParent) && parentParent.left === parent; | ||
function remove(path, scope) { | ||
function remove(path, scope, exportsMap) { | ||
let { | ||
@@ -132,3 +158,3 @@ node, | ||
path.parentPath.replaceWith(node); | ||
remove(path.parentPath, scope); | ||
remove(path.parentPath, scope, exportsMap); | ||
} else if ( //e.g. `exports.foo = bar;`, `bar` needs to be pure (an Identifier isn't ?!) | ||
@@ -141,4 +167,4 @@ (0, _types.isExpressionStatement)(parent) && ((right = path.get('right')).isPure() || right.isIdentifier())) { | ||
} | ||
} else if (isExportAssignment(path)) { | ||
remove(path.parentPath.parentPath, scope); | ||
} else if (isExportAssignment(path, exportsMap)) { | ||
remove(path.parentPath.parentPath, scope, exportsMap); | ||
} else if (isWildcardDest(path)) { | ||
@@ -160,3 +186,3 @@ let wildcard = path.parent; | ||
(0, _assert.default)((0, _types.isIdentifier)(src) || (0, _types.isObjectExpression)(src) && src.properties.length === 0); | ||
remove(path.parentPath, scope); | ||
remove(path.parentPath, scope, exportsMap); | ||
} | ||
@@ -168,3 +194,3 @@ } else if (!path.removed) { | ||
path.parentPath.replaceWith(node); | ||
remove(path.parentPath, scope); | ||
remove(path.parentPath, scope, exportsMap); | ||
} else { | ||
@@ -171,0 +197,0 @@ (0, _utils.pathRemove)(path); |
@@ -33,6 +33,2 @@ "use strict"; | ||
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } | ||
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } | ||
function getName(asset, type, ...rest) { | ||
@@ -184,5 +180,3 @@ return '$' + t.toIdentifier(asset.id) + '$' + type + (rest.length ? '$' + rest.map(name => name === 'default' ? name : t.toIdentifier(name)).join('$') : ''); | ||
(0, _assert.default)(newBindings[name], name); | ||
let _oldBindings$name = oldBindings[name], | ||
{ | ||
let { | ||
scope: aScope, | ||
@@ -192,8 +186,6 @@ constantViolations: aConstantViolations, | ||
identifier: aId, | ||
path: aPath | ||
} = _oldBindings$name, | ||
a = _objectWithoutProperties(_oldBindings$name, ["scope", "constantViolations", "referencePaths", "identifier", "path"]); | ||
let _newBindings$name = newBindings[name], | ||
{ | ||
path: aPath, | ||
...a | ||
} = oldBindings[name]; | ||
let { | ||
scope: bScope, | ||
@@ -203,6 +195,5 @@ constantViolations: bConstantViolations, | ||
identifier: bId, | ||
path: bPath | ||
} = _newBindings$name, | ||
b = _objectWithoutProperties(_newBindings$name, ["scope", "constantViolations", "referencePaths", "identifier", "path"]); | ||
path: bPath, | ||
...b | ||
} = newBindings[name]; | ||
(0, _assert.default)(aPath === bPath, name); | ||
@@ -209,0 +200,0 @@ (0, _assert.default)(aId === bId, name); |
{ | ||
"name": "@parcel/scope-hoisting", | ||
"version": "2.0.0-nightly.214+52fd6741", | ||
"version": "2.0.0-nightly.219+f9f7320b", | ||
"description": "Blazing fast, zero configuration web application bundler", | ||
@@ -24,9 +24,9 @@ "license": "MIT", | ||
"@babel/types": "^7.3.3", | ||
"@parcel/babylon-walk": "2.0.0-nightly.1836+52fd6741", | ||
"@parcel/diagnostic": "2.0.0-nightly.214+52fd6741", | ||
"@parcel/babylon-walk": "2.0.0-nightly.1841+f9f7320b", | ||
"@parcel/diagnostic": "2.0.0-nightly.219+f9f7320b", | ||
"@parcel/source-map": "^2.0.0-alpha.4.9", | ||
"@parcel/utils": "2.0.0-nightly.214+52fd6741", | ||
"@parcel/utils": "2.0.0-nightly.219+f9f7320b", | ||
"nullthrows": "^1.1.1" | ||
}, | ||
"gitHead": "52fd6741a0ea1f2e043c628cf6b7be0715b1c837" | ||
"gitHead": "f9f7320bed19a9a2a7d75d5c6da657272b4b44ef" | ||
} |
@@ -53,3 +53,7 @@ // @flow | ||
export async function concat(bundle: Bundle, bundleGraph: BundleGraph) { | ||
export async function concat( | ||
bundle: Bundle, | ||
bundleGraph: BundleGraph, | ||
wrappedAssets: Set<string>, | ||
) { | ||
let queue = new PromiseQueue({maxConcurrent: 32}); | ||
@@ -66,3 +70,3 @@ bundle.traverse((node, shouldWrap) => { | ||
if (resolved) { | ||
resolved.meta.shouldWrap = true; | ||
wrappedAssets.add(resolved.id); | ||
} | ||
@@ -73,3 +77,3 @@ return true; | ||
case 'asset': | ||
queue.add(() => processAsset(bundle, node.value)); | ||
queue.add(() => processAsset(bundle, node.value, wrappedAssets)); | ||
} | ||
@@ -146,3 +150,7 @@ }); | ||
async function processAsset(bundle: Bundle, asset: Asset) { | ||
async function processAsset( | ||
bundle: Bundle, | ||
asset: Asset, | ||
wrappedAssets: Set<string>, | ||
) { | ||
let statements: Array<Statement>; | ||
@@ -157,3 +165,3 @@ if (asset.astGenerator && asset.astGenerator.type === 'babel') { | ||
if (asset.meta.shouldWrap) { | ||
if (wrappedAssets.has(asset.id)) { | ||
statements = wrapModule(asset, statements); | ||
@@ -160,0 +168,0 @@ } |
@@ -93,2 +93,3 @@ // @flow | ||
entry && | ||
!referencedAssets.has(entry) && | ||
(!isEntry(bundle, bundleGraph) || isReferenced(bundle, bundleGraph)) | ||
@@ -95,0 +96,0 @@ ) { |
// @flow | ||
import type {Bundle, BundleGraph, PluginOptions} from '@parcel/types'; | ||
import type {Asset, Bundle, BundleGraph, PluginOptions} from '@parcel/types'; | ||
import type { | ||
ArrayExpression, | ||
ExpressionStatement, | ||
@@ -20,5 +21,20 @@ File, | ||
const REGISTER_TEMPLATE = template.statement< | ||
{|ID: StringLiteral, STATEMENTS: Array<Statement>|}, | ||
{| | ||
ID: StringLiteral, | ||
REFERENCED_IDS: ArrayExpression, | ||
STATEMENTS: Array<Statement>, | ||
|}, | ||
ExpressionStatement, | ||
>('parcelRequire.registerBundle(ID, function () { STATEMENTS; })'); | ||
>(`(function() { | ||
function $parcel$bundleWrapper() { | ||
if ($parcel$bundleWrapper._executed) return; | ||
STATEMENTS; | ||
$parcel$bundleWrapper._executed = true; | ||
} | ||
parcelRequire.registerBundle(ID, $parcel$bundleWrapper); | ||
var $parcel$referencedAssets = REFERENCED_IDS; | ||
for (var $parcel$i = 0; $parcel$i < $parcel$referencedAssets.length; $parcel$i++) { | ||
parcelRequire.registerBundle($parcel$referencedAssets[$parcel$i], $parcel$bundleWrapper); | ||
} | ||
})()`); | ||
const WRAPPER_TEMPLATE = template.statement< | ||
@@ -29,3 +45,9 @@ {|STATEMENTS: Array<Statement>|}, | ||
export function generate( | ||
export function generate({ | ||
bundleGraph, | ||
bundle, | ||
ast, | ||
referencedAssets, | ||
options, | ||
}: {| | ||
bundleGraph: BundleGraph, | ||
@@ -35,3 +57,4 @@ bundle: Bundle, | ||
options: PluginOptions, | ||
) { | ||
referencedAssets: Set<Asset>, | ||
|}) { | ||
let interpreter; | ||
@@ -56,2 +79,5 @@ if (!bundle.target.env.isBrowser()) { | ||
STATEMENTS: statements, | ||
REFERENCED_IDS: t.arrayExpression( | ||
[...referencedAssets].map(asset => t.stringLiteral(asset.id)), | ||
), | ||
}), | ||
@@ -58,0 +84,0 @@ ] |
@@ -71,2 +71,3 @@ // @flow | ||
options, | ||
wrappedAssets, | ||
}: {| | ||
@@ -77,3 +78,4 @@ bundle: Bundle, | ||
options: PluginOptions, | ||
|}) { | ||
wrappedAssets: Set<string>, | ||
|}): {|ast: File, referencedAssets: Set<Asset>|} { | ||
let format = OutputFormats[bundle.env.outputFormat]; | ||
@@ -453,3 +455,3 @@ let replacements: Map<Symbol, Symbol> = new Map(); | ||
// function, if statement, or conditional expression. | ||
if (mod.meta.shouldWrap) { | ||
if (wrappedAssets.has(mod.id)) { | ||
node = t.callExpression(getIdentifier(mod, 'init'), []); | ||
@@ -666,3 +668,3 @@ } | ||
([...referencedAssets]: Array<Asset>) | ||
.filter(a => !a.meta.shouldWrap) | ||
.filter(a => !wrappedAssets.has(a.id)) | ||
.map(a => { | ||
@@ -702,3 +704,3 @@ return FAKE_INIT_TEMPLATE({ | ||
treeShake(path.scope, exported); | ||
treeShake(path.scope, exported, exportsMap); | ||
}, | ||
@@ -708,3 +710,3 @@ }, | ||
return ast; | ||
return {ast, referencedAssets}; | ||
} |
// @flow | ||
import type {Symbol} from '@parcel/types'; | ||
import type {Asset, Symbol} from '@parcel/types'; | ||
import type {NodePath, Scope} from '@babel/traverse'; | ||
@@ -28,2 +28,3 @@ import type {Expression, Identifier, Node} from '@babel/types'; | ||
exportedIdentifiers: Set<Symbol>, | ||
exportsMap: Map<Symbol, Asset>, | ||
) { | ||
@@ -38,3 +39,3 @@ // Keep passing over all bindings in the scope until we don't remove any. | ||
Object.keys(scope.bindings).forEach((name: string) => { | ||
let binding = getUnusedBinding(scope.path, name); | ||
let binding = getUnusedBinding(scope.path, name, exportsMap); | ||
@@ -49,3 +50,3 @@ // If it is not safe to remove the binding don't touch it. | ||
[...binding.referencePaths, ...binding.constantViolations].forEach(p => | ||
remove(p, scope), | ||
remove(p, scope, exportsMap), | ||
); | ||
@@ -60,3 +61,3 @@ | ||
// Check if a binding is safe to remove and returns it if it is. | ||
function getUnusedBinding(path, name) { | ||
function getUnusedBinding(path, name, exportsMap) { | ||
let binding = path.scope.getBinding(name); | ||
@@ -67,3 +68,3 @@ if (!binding) { | ||
if (!isPure(binding.path)) { | ||
if (!isPure(binding)) { | ||
// declaration (~= init) isn't pure | ||
@@ -73,2 +74,11 @@ return null; | ||
if (hasSideEffects(binding)) { | ||
// e.g. | ||
// let foo = {}; | ||
// foo = window; | ||
// foo.xyz = 2; | ||
// console.log(window.xyz); | ||
return null; | ||
} | ||
if (!binding.referenced) { | ||
@@ -80,3 +90,3 @@ return binding; | ||
let bailout = binding.referencePaths.some( | ||
path => !isExportAssignment(path) && !isWildcardDest(path), | ||
path => !isExportAssignment(path, exportsMap) && !isWildcardDest(path), | ||
); | ||
@@ -91,3 +101,4 @@ | ||
function isPure(path) { | ||
function isPure(binding) { | ||
let {path} = binding; | ||
let {node} = path; | ||
@@ -108,8 +119,26 @@ if (isVariableDeclarator(node) && isIdentifier(node.id)) { | ||
function isExportAssignment(path) { | ||
function hasSideEffects(binding) { | ||
let {node} = binding.path; | ||
if (isVariableDeclarator(node)) { | ||
return !( | ||
(!binding.referenced || isObjectExpression(node.init)) && | ||
(binding.constant || | ||
binding.constantViolations.every( | ||
({node}) => | ||
!isAssignmentExpression(node) || isObjectExpression(node.right), | ||
)) | ||
); | ||
} | ||
return false; | ||
} | ||
function isExportAssignment(path, exportsMap: Map<Symbol, Asset>) { | ||
let {parent} = path; | ||
// match "path.foo = bar;" | ||
// match "path.foo = bar;", where path is a known exports identifier. | ||
if ( | ||
isMemberExpression(parent) && | ||
parent.object === path.node && | ||
isIdentifier(path.node) && | ||
exportsMap.has(path.node.name) && | ||
((isIdentifier(parent.property) && !parent.computed) || | ||
@@ -135,3 +164,7 @@ isStringLiteral(parent.property)) | ||
function remove(path: NodePath<Node>, scope: Scope) { | ||
function remove( | ||
path: NodePath<Node>, | ||
scope: Scope, | ||
exportsMap: Map<Symbol, Asset>, | ||
) { | ||
let {node, parent} = path; | ||
@@ -144,3 +177,3 @@ if (isAssignmentExpression(node)) { | ||
path.parentPath.replaceWith(node); | ||
remove(path.parentPath, scope); | ||
remove(path.parentPath, scope, exportsMap); | ||
} else if ( | ||
@@ -156,4 +189,4 @@ //e.g. `exports.foo = bar;`, `bar` needs to be pure (an Identifier isn't ?!) | ||
} | ||
} else if (isExportAssignment(path)) { | ||
remove(path.parentPath.parentPath, scope); | ||
} else if (isExportAssignment(path, exportsMap)) { | ||
remove(path.parentPath.parentPath, scope, exportsMap); | ||
} else if (isWildcardDest(path)) { | ||
@@ -178,3 +211,3 @@ let wildcard = path.parent; | ||
); | ||
remove(path.parentPath, scope); | ||
remove(path.parentPath, scope, exportsMap); | ||
} | ||
@@ -186,3 +219,3 @@ } else if (!path.removed) { | ||
path.parentPath.replaceWith(node); | ||
remove(path.parentPath, scope); | ||
remove(path.parentPath, scope, exportsMap); | ||
} else { | ||
@@ -189,0 +222,0 @@ pathRemove(path); |
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
216276
5696