docs/Scopehoisting Packager.md
(The skipping of single assets is described in Scopehoisting).
package():loadAssets(): Load the assets contents from cache and determine which assets are wrapped.processAsset()/visitAsset() which call buildAsset(): These will recursively resolve dependency specifiers and inline dependencies, and append the result to the top level res string.processAsset() for all assets (and skip some to only process assets once if it was already inlined somewhere else).buildAsset():buildAsset() for dependency assets and concatenate only them together.buildReplacements(), generating the Maps used during the text replacement:
import "..."; declarations inserted by the transformer: ${assetId}:${specifier}${specifiertype} -> Dependency$id$import$foo) -> result of getSymbolResolution (e.g. $id$export$bar or parcelRequire("id").bar)buildAssetPrelude():
$parcel$defineInteropFlag($id$exports) call for this asset if needed.$parcel$export and $parcel$exportWildcard calls only for used re/exports)REPLACEMENT_RE matching one of
import "id";
buildAsset() recursively ). If the referenced asset is wrapped, don't inline but place it after the current asset (into depContent).getHoistedParcelRequires to read the hoistedRequires list from getSymbolResolution and prepend needed requires.$id$exports
module.exports inside the asset gets replaced with $id$exports in the transformer, but for wrapped assets, this has to be replaced back to module.exports$id$import|importAsync|require$foo
parcelRequire.register("id", ...).getSymbolResolution():This is a wrapper around bundleGraph.getSymbolResolution().
The additional dependency argument is used to determine whether CJS interop has to be applied (if it's a ESM import), or whether it's a non-conditional import (and a hoisted parcelRequire call has to be generated).
Compared to the bundle graph's method, the parentAsset is used to make wrapped assets using their own namespace object refer to module.exports instead of $id$exports.
$id$export$bar (e.g. same-bundle ESM import),$id$exports (e.g. same-bundle ESM import),id$exports.bar (e.g. non statically analyzable exports) orparcelRequire("id").bar (wrapped/in another bundle)$parcel$interopDefault (if an ESM default import resolved to a non-statically analyzable CJS asset)parcelRequire call) by mutating the hoistedRequires listbundleGraph.getSymbolResolution()This method transitively/recursively traverses the reexports of the asset to find the specified export. This enables resolving some import to the actual value and not just some reexporting binding.
The result is an asset, the exportSymbol string, and symbol. The value can be accessed from $asset.id$exports[exportSymbol], which is potentially also already (or only) available via the top-level variable symbol. So for the add/square example above, getSymbolResolution(math.js, "add") would return {asset: "math.js", exportSymbol: "add", symbol: "$fa6943ce8a6b29$export$add"}.
While this improves code size, an imperfection with this system is that it actually means that an asset A can use a value from asset B (which is usually modelled with a dependency from A to B) without there actually being a dependency between the two. Dependencies are also used to determine if an asset is required from another bundle and has to therefore be registered with parcelRequiree. This discrepancy can be handled inside of a single bundle, but not across multiple bundles, so the boundary parameter makes the resolution stop once the bundle is left.
There are three possible resolution results:
the export has been found (with top level variable symbol).
the export has not been found (symbol === undefined), this should have been caught already by symbol propagation
the export has been found and is unused (symbol === false)
it had to bailout because there are multiple possibilities (symbol === null), and the caller should fallback to $resolvedAsset$exports[exportsSymbol]. Some examples for bailouts are:
export * from "./nonstatic-cjs1.js"; export * from "./nonstatic-cjs1.js";, so the decision between which reexport to follow should happen at runtime.resolvedAsset is a non-static cjs asset itself, then module.exports[exportsSymbol] should be used anyway.