From 40e86276c9a0576b804caee0bff06fa5703a0855 Mon Sep 17 00:00:00 2001 From: gogoend Date: Mon, 16 Oct 2023 15:23:57 +0800 Subject: [PATCH 1/3] feat(packager): add the default js packager from parcel repo and use it in config file to bundle js file. --- core/parcel-config/index.json | 3 +- core/parcel-config/package.json | 1 + .../.gitignore | 3 + .../package.json | 40 + .../src/CJSOutputFormat.js | 36 + .../src/DevPackager.js | 192 ++++ .../src/ESMOutputFormat.js | 94 ++ .../src/GlobalOutputFormat.js | 19 + .../src/ScopeHoistingPackager.js | 925 ++++++++++++++++++ .../src/dev-prelude.js | 145 +++ .../src/helpers.js | 79 ++ .../src/index.js | 121 +++ .../src/utils.js | 51 + .../tsconfig.json | 5 + pnpm-lock.yaml | 373 ++++++- 15 files changed, 2058 insertions(+), 29 deletions(-) create mode 100644 core/parcel-packager-vue-content-script-style-injector/.gitignore create mode 100644 core/parcel-packager-vue-content-script-style-injector/package.json create mode 100644 core/parcel-packager-vue-content-script-style-injector/src/CJSOutputFormat.js create mode 100644 core/parcel-packager-vue-content-script-style-injector/src/DevPackager.js create mode 100644 core/parcel-packager-vue-content-script-style-injector/src/ESMOutputFormat.js create mode 100644 core/parcel-packager-vue-content-script-style-injector/src/GlobalOutputFormat.js create mode 100644 core/parcel-packager-vue-content-script-style-injector/src/ScopeHoistingPackager.js create mode 100644 core/parcel-packager-vue-content-script-style-injector/src/dev-prelude.js create mode 100644 core/parcel-packager-vue-content-script-style-injector/src/helpers.js create mode 100644 core/parcel-packager-vue-content-script-style-injector/src/index.js create mode 100644 core/parcel-packager-vue-content-script-style-injector/src/utils.js create mode 100644 core/parcel-packager-vue-content-script-style-injector/tsconfig.json diff --git a/core/parcel-config/index.json b/core/parcel-config/index.json index afc2b6d68..93948bc26 100644 --- a/core/parcel-config/index.json +++ b/core/parcel-config/index.json @@ -53,7 +53,8 @@ }, "namers": ["@plasmohq/parcel-namer-manifest", "..."], "packagers": { - "manifest.json": "@plasmohq/parcel-packager" + "manifest.json": "@plasmohq/parcel-packager", + "*.{js,mjs,cjs}": "@plasmohq/parcel-packager-vue-content-script-style-injector" }, "optimizers": { "data-base64:*": ["...", "@parcel/optimizer-data-url"], diff --git a/core/parcel-config/package.json b/core/parcel-config/package.json index 0550945a0..01f7a333f 100644 --- a/core/parcel-config/package.json +++ b/core/parcel-config/package.json @@ -35,6 +35,7 @@ "@plasmohq/parcel-optimizer-encapsulate": "workspace:*", "@plasmohq/parcel-optimizer-es": "workspace:*", "@plasmohq/parcel-packager": "workspace:*", + "@plasmohq/parcel-packager-vue-content-script-style-injector": "workspace:*", "@plasmohq/parcel-resolver": "workspace:*", "@plasmohq/parcel-resolver-post": "workspace:*", "@plasmohq/parcel-runtime": "workspace:*", diff --git a/core/parcel-packager-vue-content-script-style-injector/.gitignore b/core/parcel-packager-vue-content-script-style-injector/.gitignore new file mode 100644 index 000000000..c7df64ac6 --- /dev/null +++ b/core/parcel-packager-vue-content-script-style-injector/.gitignore @@ -0,0 +1,3 @@ +node_modules + +dist/ \ No newline at end of file diff --git a/core/parcel-packager-vue-content-script-style-injector/package.json b/core/parcel-packager-vue-content-script-style-injector/package.json new file mode 100644 index 000000000..5d981139d --- /dev/null +++ b/core/parcel-packager-vue-content-script-style-injector/package.json @@ -0,0 +1,40 @@ +{ + "name": "@plasmohq/parcel-packager-vue-content-script-style-injector", + "version": "0.6.14", + "description": "Plasmo Parcel Packager for Web Extension Manifest", + "files": [ + "dist" + ], + "main": "dist/index.js", + "scripts": { + "prepublishOnly": "pnpm build", + "build": "rm -rf ./dist && mkdir dist && cp ./src/* ./dist" + }, + "author": "Plasmo Corp. ", + "homepage": "https://docs.plasmo.com/", + "engines": { + "parcel": ">= 2.7.0" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/PlasmoHQ/plasmo.git" + }, + "devDependencies": { + "@plasmo/config": "workspace:*", + "@plasmo/constants": "workspace:*", + "@plasmo/utils": "workspace:*", + "tsup": "7.2.0" + }, + "dependencies": { + "@parcel/core": "2.9.3", + "@parcel/diagnostic": "2.9.3", + "@parcel/hash": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/source-map": "2.9.3", + "@parcel/types": "2.9.3", + "@parcel/utils": "2.9.3", + "globals": "13.23.0", + "nullthrows": "1.1.1" + } +} diff --git a/core/parcel-packager-vue-content-script-style-injector/src/CJSOutputFormat.js b/core/parcel-packager-vue-content-script-style-injector/src/CJSOutputFormat.js new file mode 100644 index 000000000..5d07f02a7 --- /dev/null +++ b/core/parcel-packager-vue-content-script-style-injector/src/CJSOutputFormat.js @@ -0,0 +1,36 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.CJSOutputFormat = void 0; +class CJSOutputFormat { + constructor(packager) { + this.packager = packager; + } + buildBundlePrelude() { + let res = ''; + let lines = 0; + for (let [source, specifiers] of this.packager.externals) { + // CJS only supports the namespace symbol. This ensures that all accesses + // are live and the `this` binding is correct. + let namespace = specifiers.get('*'); + if (namespace) { + res += `var ${namespace} = require(${JSON.stringify(source)});\n`; + lines++; + } else { + res += `require(${JSON.stringify(source)});\n`; + lines++; + } + } + if (res.length > 0) { + res += '\n'; + lines++; + } + return [res, lines]; + } + buildBundlePostlude() { + return ['', 0]; + } +} +exports.CJSOutputFormat = CJSOutputFormat; \ No newline at end of file diff --git a/core/parcel-packager-vue-content-script-style-injector/src/DevPackager.js b/core/parcel-packager-vue-content-script-style-injector/src/DevPackager.js new file mode 100644 index 000000000..1ea741357 --- /dev/null +++ b/core/parcel-packager-vue-content-script-style-injector/src/DevPackager.js @@ -0,0 +1,192 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.DevPackager = void 0; +function _utils() { + const data = require("@parcel/utils"); + _utils = function () { + return data; + }; + return data; +} +function _sourceMap() { + const data = _interopRequireDefault(require("@parcel/source-map")); + _sourceMap = function () { + return data; + }; + return data; +} +function _assert() { + const data = _interopRequireDefault(require("assert")); + _assert = function () { + return data; + }; + return data; +} +function _path() { + const data = _interopRequireDefault(require("path")); + _path = function () { + return data; + }; + return data; +} +function _fs() { + const data = _interopRequireDefault(require("fs")); + _fs = function () { + return data; + }; + return data; +} +var _utils2 = require("./utils"); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +const PRELUDE = _fs().default.readFileSync(_path().default.join(__dirname, 'dev-prelude.js'), 'utf8').trim().replace(/;$/, ''); +class DevPackager { + constructor(options, bundleGraph, bundle, parcelRequireName) { + this.options = options; + this.bundleGraph = bundleGraph; + this.bundle = bundle; + this.parcelRequireName = parcelRequireName; + } + async package() { + // Load assets + let queue = new (_utils().PromiseQueue)({ + maxConcurrent: 32 + }); + this.bundle.traverseAssets(asset => { + queue.add(async () => { + let [code, mapBuffer] = await Promise.all([asset.getCode(), this.bundle.env.sourceMap && asset.getMapBuffer()]); + return { + code, + mapBuffer + }; + }); + }); + let results = await queue.run(); + let assets = ''; + let i = 0; + let first = true; + let map = new (_sourceMap().default)(this.options.projectRoot); + let prefix = this.getPrefix(); + let lineOffset = (0, _utils().countLines)(prefix); + let script = null; + this.bundle.traverse(node => { + let wrapped = first ? '' : ','; + if (node.type === 'dependency') { + let resolved = this.bundleGraph.getResolvedAsset(node.value, this.bundle); + if (resolved && resolved.type !== 'js') { + // if this is a reference to another javascript asset, we should not include + // its output, as its contents should already be loaded. + (0, _assert().default)(!this.bundle.hasAsset(resolved)); + wrapped += JSON.stringify(this.bundleGraph.getAssetPublicId(resolved)) + ':[function() {},{}]'; + } else { + return; + } + } + if (node.type === 'asset') { + let asset = node.value; + (0, _assert().default)(asset.type === 'js', 'all assets in a js bundle must be js assets'); + + // If this is the main entry of a script rather than a module, we need to hoist it + // outside the bundle wrapper function so that its variables are exposed as globals. + if (this.bundle.env.sourceType === 'script' && asset === this.bundle.getMainEntry()) { + script = results[i++]; + return; + } + let deps = {}; + let dependencies = this.bundleGraph.getDependencies(asset); + for (let dep of dependencies) { + let resolved = this.bundleGraph.getResolvedAsset(dep, this.bundle); + if (this.bundleGraph.isDependencySkipped(dep)) { + deps[(0, _utils2.getSpecifier)(dep)] = false; + } else if (resolved) { + deps[(0, _utils2.getSpecifier)(dep)] = this.bundleGraph.getAssetPublicId(resolved); + } else { + // An external module - map placeholder to original specifier. + deps[(0, _utils2.getSpecifier)(dep)] = dep.specifier; + } + } + let { + code, + mapBuffer + } = results[i]; + let output = code || ''; + wrapped += JSON.stringify(this.bundleGraph.getAssetPublicId(asset)) + ':[function(require,module,exports) {\n' + output + '\n},'; + wrapped += JSON.stringify(deps); + wrapped += ']'; + if (this.bundle.env.isNode() && asset.meta.has_node_replacements === true) { + const relPath = (0, _utils().normalizeSeparators)(_path().default.relative(this.bundle.target.distDir, _path().default.dirname(asset.filePath))); + wrapped = wrapped.replace('$parcel$dirnameReplace', relPath); + wrapped = wrapped.replace('$parcel$filenameReplace', relPath); + } + if (this.bundle.env.sourceMap) { + if (mapBuffer) { + map.addBuffer(mapBuffer, lineOffset); + } else { + map.addEmptyMap(_path().default.relative(this.options.projectRoot, asset.filePath).replace(/\\+/g, '/'), output, lineOffset); + } + lineOffset += (0, _utils().countLines)(output) + 1; + } + i++; + } + assets += wrapped; + first = false; + }); + let entries = this.bundle.getEntryAssets(); + let mainEntry = this.bundle.getMainEntry(); + if (!this.isEntry() && this.bundle.env.outputFormat === 'global' || this.bundle.env.sourceType === 'script') { + // In async bundles we don't want the main entry to execute until we require it + // as there might be dependencies in a sibling bundle that hasn't loaded yet. + entries = entries.filter(a => { + var _mainEntry; + return a.id !== ((_mainEntry = mainEntry) === null || _mainEntry === void 0 ? void 0 : _mainEntry.id); + }); + mainEntry = null; + } + let contents = prefix + '({' + assets + '},' + JSON.stringify(entries.map(asset => this.bundleGraph.getAssetPublicId(asset))) + ', ' + JSON.stringify(mainEntry ? this.bundleGraph.getAssetPublicId(mainEntry) : null) + ', ' + JSON.stringify(this.parcelRequireName) + ')' + '\n'; + + // The entry asset of a script bundle gets hoisted outside the bundle wrapper function + // so that its variables become globals. We need to replace any require calls for + // runtimes with a parcelRequire call. + if (this.bundle.env.sourceType === 'script' && script) { + let entryMap; + let mapBuffer = script.mapBuffer; + if (mapBuffer) { + entryMap = new (_sourceMap().default)(this.options.projectRoot, mapBuffer); + } + contents += (0, _utils2.replaceScriptDependencies)(this.bundleGraph, this.bundle, script.code, entryMap, this.parcelRequireName); + if (this.bundle.env.sourceMap && entryMap) { + map.addSourceMap(entryMap, lineOffset); + } + } + return { + contents, + map + }; + } + getPrefix() { + let interpreter; + let mainEntry = this.bundle.getMainEntry(); + if (mainEntry && this.isEntry() && !this.bundle.target.env.isBrowser()) { + let _interpreter = mainEntry.meta.interpreter; + (0, _assert().default)(_interpreter == null || typeof _interpreter === 'string'); + interpreter = _interpreter; + } + let importScripts = ''; + if (this.bundle.env.isWorker()) { + let bundles = this.bundleGraph.getReferencedBundles(this.bundle); + for (let b of bundles) { + importScripts += `importScripts("${(0, _utils().relativeBundlePath)(this.bundle, b)}");\n`; + } + } + return ( + // If the entry asset included a hashbang, repeat it at the top of the bundle + (interpreter != null ? `#!${interpreter}\n` : '') + importScripts + PRELUDE + ); + } + isEntry() { + return !this.bundleGraph.hasParentBundleOfType(this.bundle, 'js') || this.bundle.env.isIsolated() || this.bundle.bundleBehavior === 'isolated'; + } +} +exports.DevPackager = DevPackager; \ No newline at end of file diff --git a/core/parcel-packager-vue-content-script-style-injector/src/ESMOutputFormat.js b/core/parcel-packager-vue-content-script-style-injector/src/ESMOutputFormat.js new file mode 100644 index 000000000..143ecb79a --- /dev/null +++ b/core/parcel-packager-vue-content-script-style-injector/src/ESMOutputFormat.js @@ -0,0 +1,94 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.ESMOutputFormat = void 0; +class ESMOutputFormat { + constructor(packager) { + this.packager = packager; + } + buildBundlePrelude() { + let res = ''; + let lines = 0; + for (let [source, specifiers] of this.packager.externals) { + let defaultSpecifier = null; + let namespaceSpecifier = null; + let namedSpecifiers = []; + for (let [imported, symbol] of specifiers) { + if (imported === 'default' /* || isCommonJS*/) { + defaultSpecifier = symbol; + } else if (imported === '*') { + namespaceSpecifier = `* as ${symbol}`; + } else { + let specifier = imported; + if (symbol !== imported) { + specifier += ` as ${symbol}`; + } + namedSpecifiers.push(specifier); + } + } + + // ESModule syntax allows combining default and namespace specifiers, or default and named, but not all three. + + let imported = ''; + if (namespaceSpecifier) { + let s = namespaceSpecifier; + if (defaultSpecifier) { + s = `${defaultSpecifier}, ${namespaceSpecifier}`; + } + res += `import ${s} from ${JSON.stringify(source)};\n`; + lines++; + } else if (defaultSpecifier) { + imported = defaultSpecifier; + if (namedSpecifiers.length > 0) { + imported += `, {${namedSpecifiers.join(', ')}}`; + } + } else if (namedSpecifiers.length > 0) { + imported = `{${namedSpecifiers.join(', ')}}`; + } + if (imported.length > 0) { + res += `import ${imported} from ${JSON.stringify(source)};\n`; + lines++; + } else if (!namespaceSpecifier) { + res += `import ${JSON.stringify(source)};\n`; + lines++; + } + } + if (res.length > 0) { + res += '\n'; + lines++; + } + return [res, lines]; + } + buildBundlePostlude() { + let res = ''; + let lines = 0; + let exportSpecifiers = []; + for (let { + asset, + exportSymbol, + local, + exportAs + } of this.packager.exportedSymbols.values()) { + if (this.packager.wrappedAssets.has(asset.id)) { + let obj = `parcelRequire("${this.packager.bundleGraph.getAssetPublicId(asset)}")`; + res += `\nvar ${local} = ${this.packager.getPropertyAccess(obj, exportSymbol)};`; + lines++; + } + for (let as of exportAs) { + let specifier = local; + if (exportAs !== local) { + specifier += ` as ${as}`; + } + exportSpecifiers.push(specifier); + } + } + if (exportSpecifiers.length > 0) { + res += `\nexport {${exportSpecifiers.join(', ')}};`; + lines++; + } + return [res, lines]; + } +} +exports.ESMOutputFormat = ESMOutputFormat; \ No newline at end of file diff --git a/core/parcel-packager-vue-content-script-style-injector/src/GlobalOutputFormat.js b/core/parcel-packager-vue-content-script-style-injector/src/GlobalOutputFormat.js new file mode 100644 index 000000000..e8fe9f483 --- /dev/null +++ b/core/parcel-packager-vue-content-script-style-injector/src/GlobalOutputFormat.js @@ -0,0 +1,19 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.GlobalOutputFormat = void 0; +class GlobalOutputFormat { + constructor(packager) { + this.packager = packager; + } + buildBundlePrelude() { + let prelude = this.packager.bundle.env.supports('arrow-functions', true) ? '(() => {\n' : '(function () {\n'; + return [prelude, 1]; + } + buildBundlePostlude() { + return ['})();', 0]; + } +} +exports.GlobalOutputFormat = GlobalOutputFormat; \ No newline at end of file diff --git a/core/parcel-packager-vue-content-script-style-injector/src/ScopeHoistingPackager.js b/core/parcel-packager-vue-content-script-style-injector/src/ScopeHoistingPackager.js new file mode 100644 index 000000000..f8ef7507f --- /dev/null +++ b/core/parcel-packager-vue-content-script-style-injector/src/ScopeHoistingPackager.js @@ -0,0 +1,925 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.ScopeHoistingPackager = void 0; +function _utils() { + const data = require("@parcel/utils"); + _utils = function () { + return data; + }; + return data; +} +function _sourceMap2() { + const data = _interopRequireDefault(require("@parcel/source-map")); + _sourceMap2 = function () { + return data; + }; + return data; +} +function _nullthrows() { + const data = _interopRequireDefault(require("nullthrows")); + _nullthrows = function () { + return data; + }; + return data; +} +function _assert() { + const data = _interopRequireDefault(require("assert")); + _assert = function () { + return data; + }; + return data; +} +function _diagnostic() { + const data = _interopRequireWildcard(require("@parcel/diagnostic")); + _diagnostic = function () { + return data; + }; + return data; +} +function _globals() { + const data = _interopRequireDefault(require("globals")); + _globals = function () { + return data; + }; + return data; +} +function _path() { + const data = _interopRequireDefault(require("path")); + _path = function () { + return data; + }; + return data; +} +var _ESMOutputFormat = require("./ESMOutputFormat"); +var _CJSOutputFormat = require("./CJSOutputFormat"); +var _GlobalOutputFormat = require("./GlobalOutputFormat"); +var _helpers = require("./helpers"); +var _utils2 = require("./utils"); +function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } +function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +// https://262.ecma-international.org/6.0/#sec-names-and-keywords +const IDENTIFIER_RE = /^[$_\p{ID_Start}][$_\u200C\u200D\p{ID_Continue}]*$/u; +const ID_START_RE = /^[$_\p{ID_Start}]/u; +const NON_ID_CONTINUE_RE = /[^$_\u200C\u200D\p{ID_Continue}]/gu; + +// General regex used to replace imports with the resolved code, references with resolutions, +// and count the number of newlines in the file for source maps. +const REPLACEMENT_RE = /\n|import\s+"([0-9a-f]{16}:.+?)";|(?:\$[0-9a-f]{16}\$exports)|(?:\$[0-9a-f]{16}\$(?:import|importAsync|require)\$[0-9a-f]+(?:\$[0-9a-f]+)?)/g; +const BUILTINS = Object.keys(_globals().default.builtin); +const GLOBALS_BY_CONTEXT = { + browser: new Set([...BUILTINS, ...Object.keys(_globals().default.browser)]), + 'web-worker': new Set([...BUILTINS, ...Object.keys(_globals().default.worker)]), + 'service-worker': new Set([...BUILTINS, ...Object.keys(_globals().default.serviceworker)]), + worklet: new Set([...BUILTINS]), + node: new Set([...BUILTINS, ...Object.keys(_globals().default.node)]), + 'electron-main': new Set([...BUILTINS, ...Object.keys(_globals().default.node)]), + 'electron-renderer': new Set([...BUILTINS, ...Object.keys(_globals().default.node), ...Object.keys(_globals().default.browser)]) +}; +const OUTPUT_FORMATS = { + esmodule: _ESMOutputFormat.ESMOutputFormat, + commonjs: _CJSOutputFormat.CJSOutputFormat, + global: _GlobalOutputFormat.GlobalOutputFormat +}; +class ScopeHoistingPackager { + exportedSymbols = new Map(); + externals = new Map(); + topLevelNames = new Map(); + seenAssets = new Set(); + wrappedAssets = new Set(); + hoistedRequires = new Map(); + needsPrelude = false; + usedHelpers = new Set(); + constructor(options, bundleGraph, bundle, parcelRequireName) { + this.options = options; + this.bundleGraph = bundleGraph; + this.bundle = bundle; + this.parcelRequireName = parcelRequireName; + let OutputFormat = OUTPUT_FORMATS[this.bundle.env.outputFormat]; + this.outputFormat = new OutputFormat(this); + this.isAsyncBundle = this.bundleGraph.hasParentBundleOfType(this.bundle, 'js') && !this.bundle.env.isIsolated() && this.bundle.bundleBehavior !== 'isolated'; + this.globalNames = GLOBALS_BY_CONTEXT[bundle.env.context]; + } + async package() { + var _sourceMap; + let wrappedAssets = await this.loadAssets(); + this.buildExportedSymbols(); + + // If building a library, the target is actually another bundler rather + // than the final output that could be loaded in a browser. So, loader + // runtimes are excluded, and instead we add imports into the entry bundle + // of each bundle group pointing at the sibling bundles. These can be + // picked up by another bundler later at which point runtimes will be added. + if (this.bundle.env.isLibrary || this.bundle.env.outputFormat === 'commonjs') { + let bundles = this.bundleGraph.getReferencedBundles(this.bundle); + for (let b of bundles) { + this.externals.set((0, _utils().relativeBundlePath)(this.bundle, b), new Map()); + } + } + let res = ''; + let lineCount = 0; + let sourceMap = null; + let processAsset = asset => { + let [content, map, lines] = this.visitAsset(asset); + if (sourceMap && map) { + sourceMap.addSourceMap(map, lineCount); + } else if (this.bundle.env.sourceMap) { + sourceMap = map; + } + res += content + '\n'; + lineCount += lines + 1; + }; + + // Hoist wrapped asset to the top of the bundle to ensure that they are registered + // before they are used. + for (let asset of wrappedAssets) { + if (!this.seenAssets.has(asset.id)) { + processAsset(asset); + } + } + + // Add each asset that is directly connected to the bundle. Dependencies will be handled + // by replacing `import` statements in the code. + this.bundle.traverseAssets((asset, _, actions) => { + if (this.seenAssets.has(asset.id)) { + actions.skipChildren(); + return; + } + processAsset(asset); + actions.skipChildren(); + }); + let [prelude, preludeLines] = this.buildBundlePrelude(); + res = prelude + res; + lineCount += preludeLines; + (_sourceMap = sourceMap) === null || _sourceMap === void 0 ? void 0 : _sourceMap.offsetLines(1, preludeLines); + let entries = this.bundle.getEntryAssets(); + let mainEntry = this.bundle.getMainEntry(); + if (this.isAsyncBundle) { + // In async bundles we don't want the main entry to execute until we require it + // as there might be dependencies in a sibling bundle that hasn't loaded yet. + entries = entries.filter(a => { + var _mainEntry; + return a.id !== ((_mainEntry = mainEntry) === null || _mainEntry === void 0 ? void 0 : _mainEntry.id); + }); + mainEntry = null; + } + + // If any of the entry assets are wrapped, call parcelRequire so they are executed. + for (let entry of entries) { + if (this.wrappedAssets.has(entry.id) && !this.isScriptEntry(entry)) { + var _entry$symbols$get; + let parcelRequire = `parcelRequire(${JSON.stringify(this.bundleGraph.getAssetPublicId(entry))});\n`; + let entryExports = (_entry$symbols$get = entry.symbols.get('*')) === null || _entry$symbols$get === void 0 ? void 0 : _entry$symbols$get.local; + if (entryExports && entry === mainEntry && this.exportedSymbols.has(entryExports)) { + res += `\nvar ${entryExports} = ${parcelRequire}`; + } else { + res += `\n${parcelRequire}`; + } + lineCount += 2; + } + } + let [postlude, postludeLines] = this.outputFormat.buildBundlePostlude(); + res += postlude; + lineCount += postludeLines; + + // The entry asset of a script bundle gets hoisted outside the bundle wrapper so that + // its top-level variables become globals like a real browser script. We need to replace + // all dependency references for runtimes with a parcelRequire call. + if (this.bundle.env.outputFormat === 'global' && this.bundle.env.sourceType === 'script') { + res += '\n'; + lineCount++; + let mainEntry = (0, _nullthrows().default)(this.bundle.getMainEntry()); + let { + code, + map: mapBuffer + } = (0, _nullthrows().default)(this.assetOutputs.get(mainEntry.id)); + let map; + if (mapBuffer) { + map = new (_sourceMap2().default)(this.options.projectRoot, mapBuffer); + } + res += (0, _utils2.replaceScriptDependencies)(this.bundleGraph, this.bundle, code, map, this.parcelRequireName); + if (sourceMap && map) { + sourceMap.addSourceMap(map, lineCount); + } + } + return { + contents: res, + map: sourceMap + }; + } + async loadAssets() { + let queue = new (_utils().PromiseQueue)({ + maxConcurrent: 32 + }); + let wrapped = []; + this.bundle.traverseAssets(asset => { + queue.add(async () => { + let [code, map] = await Promise.all([asset.getCode(), this.bundle.env.sourceMap ? asset.getMapBuffer() : null]); + return [asset.id, { + code, + map + }]; + }); + if (asset.meta.shouldWrap || this.isAsyncBundle || this.bundle.env.sourceType === 'script' || this.bundleGraph.isAssetReferenced(this.bundle, asset) || this.bundleGraph.getIncomingDependencies(asset).some(dep => dep.meta.shouldWrap && dep.specifierType !== 'url')) { + this.wrappedAssets.add(asset.id); + wrapped.push(asset); + } + }); + for (let wrappedAssetRoot of [...wrapped]) { + this.bundle.traverseAssets((asset, _, actions) => { + if (asset === wrappedAssetRoot) { + return; + } + if (this.wrappedAssets.has(asset.id)) { + actions.skipChildren(); + return; + } + this.wrappedAssets.add(asset.id); + wrapped.push(asset); + }, wrappedAssetRoot); + } + this.assetOutputs = new Map(await queue.run()); + return wrapped; + } + buildExportedSymbols() { + if (this.isAsyncBundle || !this.bundle.env.isLibrary || this.bundle.env.outputFormat !== 'esmodule') { + return; + } + + // TODO: handle ESM exports of wrapped entry assets... + let entry = this.bundle.getMainEntry(); + if (entry && !this.wrappedAssets.has(entry.id)) { + for (let { + asset, + exportAs, + symbol, + exportSymbol + } of this.bundleGraph.getExportedSymbols(entry)) { + if (typeof symbol === 'string') { + var _this$exportedSymbols, _entry$symbols$get2; + let symbols = (_this$exportedSymbols = this.exportedSymbols.get(symbol === '*' ? (0, _nullthrows().default)((_entry$symbols$get2 = entry.symbols.get('*')) === null || _entry$symbols$get2 === void 0 ? void 0 : _entry$symbols$get2.local) : symbol)) === null || _this$exportedSymbols === void 0 ? void 0 : _this$exportedSymbols.exportAs; + if (!symbols) { + symbols = []; + this.exportedSymbols.set(symbol, { + asset, + exportSymbol, + local: symbol, + exportAs: symbols + }); + } + if (exportAs === '*') { + exportAs = 'default'; + } + symbols.push(exportAs); + } else if (symbol === null) { + // TODO `meta.exportsIdentifier[exportSymbol]` should be exported + // let relativePath = relative(options.projectRoot, asset.filePath); + // throw getThrowableDiagnosticForNode( + // md`${relativePath} couldn't be statically analyzed when importing '${exportSymbol}'`, + // entry.filePath, + // loc, + // ); + } else if (symbol !== false) { + // let relativePath = relative(options.projectRoot, asset.filePath); + // throw getThrowableDiagnosticForNode( + // md`${relativePath} does not export '${exportSymbol}'`, + // entry.filePath, + // loc, + // ); + } + } + } + } + getTopLevelName(name) { + name = name.replace(NON_ID_CONTINUE_RE, ''); + if (!ID_START_RE.test(name) || this.globalNames.has(name)) { + name = '_' + name; + } + let count = this.topLevelNames.get(name); + if (count == null) { + this.topLevelNames.set(name, 1); + return name; + } + this.topLevelNames.set(name, count + 1); + return name + count; + } + getPropertyAccess(obj, property) { + if (IDENTIFIER_RE.test(property)) { + return `${obj}.${property}`; + } + return `${obj}[${JSON.stringify(property)}]`; + } + visitAsset(asset) { + (0, _assert().default)(!this.seenAssets.has(asset.id), 'Already visited asset'); + this.seenAssets.add(asset.id); + let { + code, + map + } = (0, _nullthrows().default)(this.assetOutputs.get(asset.id)); + return this.buildAsset(asset, code, map); + } + buildAsset(asset, code, map) { + let shouldWrap = this.wrappedAssets.has(asset.id); + let deps = this.bundleGraph.getDependencies(asset); + let sourceMap = this.bundle.env.sourceMap && map ? new (_sourceMap2().default)(this.options.projectRoot, map) : null; + + // If this asset is skipped, just add dependencies and not the asset's content. + if (this.shouldSkipAsset(asset)) { + let depCode = ''; + let lineCount = 0; + for (let dep of deps) { + let resolved = this.bundleGraph.getResolvedAsset(dep, this.bundle); + let skipped = this.bundleGraph.isDependencySkipped(dep); + if (skipped) { + continue; + } + if (!resolved) { + if (!dep.isOptional) { + this.addExternal(dep); + } + continue; + } + if (this.bundle.hasAsset(resolved) && !this.seenAssets.has(resolved.id)) { + let [code, map, lines] = this.visitAsset(resolved); + depCode += code + '\n'; + if (sourceMap && map) { + sourceMap.addSourceMap(map, lineCount); + } + lineCount += lines + 1; + } + } + return [depCode, sourceMap, lineCount]; + } + + // TODO: maybe a meta prop? + if (code.includes('$parcel$global')) { + this.usedHelpers.add('$parcel$global'); + } + if (this.bundle.env.isNode() && asset.meta.has_node_replacements) { + const relPath = (0, _utils().normalizeSeparators)(_path().default.relative(this.bundle.target.distDir, _path().default.dirname(asset.filePath))); + code = code.replace('$parcel$dirnameReplace', relPath); + code = code.replace('$parcel$filenameReplace', relPath); + } + let [depMap, replacements] = this.buildReplacements(asset, deps); + let [prepend, prependLines, append] = this.buildAssetPrelude(asset, deps); + if (prependLines > 0) { + sourceMap === null || sourceMap === void 0 ? void 0 : sourceMap.offsetLines(1, prependLines); + code = prepend + code; + } + code += append; + let lineCount = 0; + let depContent = []; + if (depMap.size === 0 && replacements.size === 0) { + // If there are no dependencies or replacements, use a simple function to count the number of lines. + lineCount = (0, _utils().countLines)(code) - 1; + } else { + // Otherwise, use a regular expression to perform replacements. + // We need to track how many newlines there are for source maps, replace + // all import statements with dependency code, and perform inline replacements + // of all imported symbols with their resolved export symbols. This is all done + // in a single regex so that we only do one pass over the whole code. + let offset = 0; + let columnStartIndex = 0; + code = code.replace(REPLACEMENT_RE, (m, d, i) => { + var _replacements$get; + if (m === '\n') { + columnStartIndex = i + offset + 1; + lineCount++; + return '\n'; + } + + // If we matched an import, replace with the source code for the dependency. + if (d != null) { + let deps = depMap.get(d); + if (!deps) { + return m; + } + let replacement = ''; + + // A single `${id}:${specifier}:esm` might have been resolved to multiple assets due to + // reexports. + for (let dep of deps) { + let resolved = this.bundleGraph.getResolvedAsset(dep, this.bundle); + let skipped = this.bundleGraph.isDependencySkipped(dep); + if (resolved && !skipped) { + // Hoist variable declarations for the referenced parcelRequire dependencies + // after the dependency is declared. This handles the case where the resulting asset + // is wrapped, but the dependency in this asset is not marked as wrapped. This means + // that it was imported/required at the top-level, so its side effects should run immediately. + let [res, lines] = this.getHoistedParcelRequires(asset, dep, resolved); + let map; + if (this.bundle.hasAsset(resolved) && !this.seenAssets.has(resolved.id)) { + // If this asset is wrapped, we need to hoist the code for the dependency + // outside our parcelRequire.register wrapper. This is safe because all + // assets referenced by this asset will also be wrapped. Otherwise, inline the + // asset content where the import statement was. + if (shouldWrap) { + depContent.push(this.visitAsset(resolved)); + } else { + let [depCode, depMap, depLines] = this.visitAsset(resolved); + res = depCode + '\n' + res; + lines += 1 + depLines; + map = depMap; + } + } + + // Push this asset's source mappings down by the number of lines in the dependency + // plus the number of hoisted parcelRequires. Then insert the source map for the dependency. + if (sourceMap) { + if (lines > 0) { + sourceMap.offsetLines(lineCount + 1, lines); + } + if (map) { + sourceMap.addSourceMap(map, lineCount); + } + } + replacement += res; + lineCount += lines; + } + } + return replacement; + } + + // If it wasn't a dependency, then it was an inline replacement (e.g. $id$import$foo -> $id$export$foo). + let replacement = (_replacements$get = replacements.get(m)) !== null && _replacements$get !== void 0 ? _replacements$get : m; + if (sourceMap) { + // Offset the source map columns for this line if the replacement was a different length. + // This assumes that the match and replacement both do not contain any newlines. + let lengthDifference = replacement.length - m.length; + if (lengthDifference !== 0) { + sourceMap.offsetColumns(lineCount + 1, i + offset - columnStartIndex + m.length, lengthDifference); + offset += lengthDifference; + } + } + return replacement; + }); + } + + // If the asset is wrapped, we need to insert the dependency code outside the parcelRequire.register + // wrapper. Dependencies must be inserted AFTER the asset is registered so that circular dependencies work. + if (shouldWrap) { + // Offset by one line for the parcelRequire.register wrapper. + sourceMap === null || sourceMap === void 0 ? void 0 : sourceMap.offsetLines(1, 1); + lineCount++; + code = `parcelRequire.register(${JSON.stringify(this.bundleGraph.getAssetPublicId(asset))}, function(module, exports) { +${code} +}); +`; + lineCount += 2; + for (let [depCode, map, lines] of depContent) { + if (!depCode) continue; + code += depCode + '\n'; + if (sourceMap && map) { + sourceMap.addSourceMap(map, lineCount); + } + lineCount += lines + 1; + } + this.needsPrelude = true; + } + return [code, sourceMap, lineCount]; + } + buildReplacements(asset, deps) { + let assetId = asset.meta.id; + (0, _assert().default)(typeof assetId === 'string'); + + // Build two maps: one of import specifiers, and one of imported symbols to replace. + // These will be used to build a regex below. + let depMap = new (_utils().DefaultMap)(() => []); + let replacements = new Map(); + for (let dep of deps) { + let specifierType = dep.specifierType === 'esm' ? `:${dep.specifierType}` : ''; + depMap.get(`${assetId}:${(0, _utils2.getSpecifier)(dep)}${!dep.meta.placeholder ? specifierType : ''}`).push(dep); + let asyncResolution = this.bundleGraph.resolveAsyncDependency(dep, this.bundle); + let resolved = (asyncResolution === null || asyncResolution === void 0 ? void 0 : asyncResolution.type) === 'asset' ? + // Prefer the underlying asset over a runtime to load it. It will + // be wrapped in Promise.resolve() later. + asyncResolution.value : this.bundleGraph.getResolvedAsset(dep, this.bundle); + if (!resolved && !dep.isOptional && !this.bundleGraph.isDependencySkipped(dep)) { + this.addExternal(dep, replacements); + } + if (!resolved) { + continue; + } + for (let [imported, { + local + }] of dep.symbols) { + if (local === '*') { + continue; + } + let symbol = this.getSymbolResolution(asset, resolved, imported, dep); + replacements.set(local, + // If this was an internalized async asset, wrap in a Promise.resolve. + (asyncResolution === null || asyncResolution === void 0 ? void 0 : asyncResolution.type) === 'asset' ? `Promise.resolve(${symbol})` : symbol); + } + + // Async dependencies need a namespace object even if all used symbols were statically analyzed. + // This is recorded in the promiseSymbol meta property set by the transformer rather than in + // symbols so that we don't mark all symbols as used. + if (dep.priority === 'lazy' && dep.meta.promiseSymbol) { + let promiseSymbol = dep.meta.promiseSymbol; + (0, _assert().default)(typeof promiseSymbol === 'string'); + let symbol = this.getSymbolResolution(asset, resolved, '*', dep); + replacements.set(promiseSymbol, (asyncResolution === null || asyncResolution === void 0 ? void 0 : asyncResolution.type) === 'asset' ? `Promise.resolve(${symbol})` : symbol); + } + } + + // If this asset is wrapped, we need to replace the exports namespace with `module.exports`, + // which will be provided to us by the wrapper. + if (this.wrappedAssets.has(asset.id) || this.bundle.env.outputFormat === 'commonjs' && asset === this.bundle.getMainEntry()) { + var _asset$symbols$get; + let exportsName = ((_asset$symbols$get = asset.symbols.get('*')) === null || _asset$symbols$get === void 0 ? void 0 : _asset$symbols$get.local) || `$${assetId}$exports`; + replacements.set(exportsName, 'module.exports'); + } + return [depMap, replacements]; + } + addExternal(dep, replacements) { + if (this.bundle.env.outputFormat === 'global') { + throw new (_diagnostic().default)({ + diagnostic: { + message: 'External modules are not supported when building for browser', + codeFrames: [{ + filePath: (0, _nullthrows().default)(dep.sourcePath), + codeHighlights: dep.loc ? [(0, _diagnostic().convertSourceLocationToHighlight)(dep.loc)] : [] + }] + } + }); + } + + // Map of DependencySpecifier -> Map> + let external = this.externals.get(dep.specifier); + if (!external) { + external = new Map(); + this.externals.set(dep.specifier, external); + } + for (let [imported, { + local + }] of dep.symbols) { + // If already imported, just add the already renamed variable to the mapping. + let renamed = external.get(imported); + if (renamed && local !== '*' && replacements) { + replacements.set(local, renamed); + continue; + } + + // For CJS output, always use a property lookup so that exports remain live. + // For ESM output, use named imports which are always live. + if (this.bundle.env.outputFormat === 'commonjs') { + renamed = external.get('*'); + if (!renamed) { + renamed = this.getTopLevelName(`$${this.bundle.publicId}$${dep.specifier}`); + external.set('*', renamed); + } + if (local !== '*' && replacements) { + let replacement; + if (imported === '*') { + replacement = renamed; + } else if (imported === 'default') { + replacement = `($parcel$interopDefault(${renamed}))`; + this.usedHelpers.add('$parcel$interopDefault'); + } else { + replacement = this.getPropertyAccess(renamed, imported); + } + replacements.set(local, replacement); + } + } else { + // Rename the specifier so that multiple local imports of the same imported specifier + // are deduplicated. We have to prefix the imported name with the bundle id so that + // local variables do not shadow it. + if (this.exportedSymbols.has(local)) { + renamed = local; + } else if (imported === 'default' || imported === '*') { + renamed = this.getTopLevelName(`$${this.bundle.publicId}$${dep.specifier}`); + } else { + renamed = this.getTopLevelName(`$${this.bundle.publicId}$${imported}`); + } + external.set(imported, renamed); + if (local !== '*' && replacements) { + replacements.set(local, renamed); + } + } + } + } + getSymbolResolution(parentAsset, resolved, imported, dep) { + var _resolvedAsset$symbol; + let { + asset: resolvedAsset, + exportSymbol, + symbol + } = this.bundleGraph.getSymbolResolution(resolved, imported, this.bundle); + if (resolvedAsset.type !== 'js' || dep && this.bundleGraph.isDependencySkipped(dep)) { + // Graceful fallback for non-js imports or when trying to resolve a symbol + // that is actually unused but we still need a placeholder value. + return '{}'; + } + let isWrapped = !this.bundle.hasAsset(resolvedAsset) || this.wrappedAssets.has(resolvedAsset.id) && resolvedAsset !== parentAsset; + let staticExports = resolvedAsset.meta.staticExports !== false; + let publicId = this.bundleGraph.getAssetPublicId(resolvedAsset); + + // If the resolved asset is wrapped, but imported at the top-level by this asset, + // then we hoist parcelRequire calls to the top of this asset so side effects run immediately. + if (isWrapped && dep && !(dep !== null && dep !== void 0 && dep.meta.shouldWrap) && symbol !== false && ( + // Only do this if the asset is part of a different bundle (so it was definitely + // parcelRequire.register'ed there), or if it is indeed registered in this bundle. + !this.bundle.hasAsset(resolvedAsset) || !this.shouldSkipAsset(resolvedAsset))) { + let hoisted = this.hoistedRequires.get(dep.id); + if (!hoisted) { + hoisted = new Map(); + this.hoistedRequires.set(dep.id, hoisted); + } + hoisted.set(resolvedAsset.id, `var $${publicId} = parcelRequire(${JSON.stringify(publicId)});`); + } + if (isWrapped) { + this.needsPrelude = true; + } + + // If this is an ESM default import of a CJS module with a `default` symbol, + // and no __esModule flag, we need to resolve to the namespace instead. + let isDefaultInterop = exportSymbol === 'default' && staticExports && !isWrapped && ((dep === null || dep === void 0 ? void 0 : dep.meta.kind) === 'Import' || (dep === null || dep === void 0 ? void 0 : dep.meta.kind) === 'Export') && resolvedAsset.symbols.hasExportSymbol('*') && resolvedAsset.symbols.hasExportSymbol('default') && !resolvedAsset.symbols.hasExportSymbol('__esModule'); + + // Find the namespace object for the resolved module. If wrapped and this + // is an inline require (not top-level), use a parcelRequire call, otherwise + // the hoisted variable declared above. Otherwise, if not wrapped, use the + // namespace export symbol. + let assetId = resolvedAsset.meta.id; + (0, _assert().default)(typeof assetId === 'string'); + let obj = isWrapped && (!dep || dep !== null && dep !== void 0 && dep.meta.shouldWrap) ? + // Wrap in extra parenthesis to not change semantics, e.g.`new (parcelRequire("..."))()`. + `(parcelRequire(${JSON.stringify(publicId)}))` : isWrapped && dep ? `$${publicId}` : ((_resolvedAsset$symbol = resolvedAsset.symbols.get('*')) === null || _resolvedAsset$symbol === void 0 ? void 0 : _resolvedAsset$symbol.local) || `$${assetId}$exports`; + if (imported === '*' || exportSymbol === '*' || isDefaultInterop) { + // Resolve to the namespace object if requested or this is a CJS default interop reqiure. + if (parentAsset === resolvedAsset && this.wrappedAssets.has(resolvedAsset.id)) { + // Directly use module.exports for wrapped assets importing themselves. + return 'module.exports'; + } else { + return obj; + } + } else if ((!staticExports || isWrapped || !symbol) && resolvedAsset !== parentAsset) { + // If the resolved asset is wrapped or has non-static exports, + // we need to use a member access off the namespace object rather + // than a direct reference. If importing default from a CJS module, + // use a helper to check the __esModule flag at runtime. + let kind = dep === null || dep === void 0 ? void 0 : dep.meta.kind; + if ((!dep || kind === 'Import' || kind === 'Export') && exportSymbol === 'default' && resolvedAsset.symbols.hasExportSymbol('*') && this.needsDefaultInterop(resolvedAsset)) { + this.usedHelpers.add('$parcel$interopDefault'); + return `(/*@__PURE__*/$parcel$interopDefault(${obj}))`; + } else { + return this.getPropertyAccess(obj, exportSymbol); + } + } else if (!symbol) { + (0, _assert().default)(false, 'Asset was skipped or not found.'); + } else { + return symbol; + } + } + getHoistedParcelRequires(parentAsset, dep, resolved) { + if (resolved.type !== 'js') { + return ['', 0]; + } + let hoisted = this.hoistedRequires.get(dep.id); + let res = ''; + let lineCount = 0; + let isWrapped = !this.bundle.hasAsset(resolved) || this.wrappedAssets.has(resolved.id) && resolved !== parentAsset; + + // If the resolved asset is wrapped and is imported in the top-level by this asset, + // we need to run side effects when this asset runs. If the resolved asset is not + // the first one in the hoisted requires, we need to insert a parcelRequire here + // so it runs first. + if (isWrapped && !dep.meta.shouldWrap && (!hoisted || hoisted.keys().next().value !== resolved.id) && !this.bundleGraph.isDependencySkipped(dep) && !this.shouldSkipAsset(resolved)) { + this.needsPrelude = true; + res += `parcelRequire(${JSON.stringify(this.bundleGraph.getAssetPublicId(resolved))});`; + } + if (hoisted) { + this.needsPrelude = true; + res += '\n' + [...hoisted.values()].join('\n'); + lineCount += hoisted.size; + } + return [res, lineCount]; + } + buildAssetPrelude(asset, deps) { + let prepend = ''; + let prependLineCount = 0; + let append = ''; + let shouldWrap = this.wrappedAssets.has(asset.id); + let usedSymbols = (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(asset)); + let assetId = asset.meta.id; + (0, _assert().default)(typeof assetId === 'string'); + + // If the asset has a namespace export symbol, it is CommonJS. + // If there's no __esModule flag, and default is a used symbol, we need + // to insert an interop helper. + let defaultInterop = asset.symbols.hasExportSymbol('*') && usedSymbols.has('default') && !asset.symbols.hasExportSymbol('__esModule'); + let usedNamespace = + // If the asset has * in its used symbols, we might need the exports namespace. + // The one case where this isn't true is in ESM library entries, where the only + // dependency on * is the entry dependency. In this case, we will use ESM exports + // instead of the namespace object. + usedSymbols.has('*') && (this.bundle.env.outputFormat !== 'esmodule' || !this.bundle.env.isLibrary || asset !== this.bundle.getMainEntry() || this.bundleGraph.getIncomingDependencies(asset).some(dep => !dep.isEntry && (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(dep)).has('*'))) || + // If a symbol is imported (used) from a CJS asset but isn't listed in the symbols, + // we fallback on the namespace object. + asset.symbols.hasExportSymbol('*') && [...usedSymbols].some(s => !asset.symbols.hasExportSymbol(s)) || + // If the exports has this asset's namespace (e.g. ESM output from CJS input), + // include the namespace object for the default export. + this.exportedSymbols.has(`$${assetId}$exports`); + + // If the asset doesn't have static exports, should wrap, the namespace is used, + // or we need default interop, then we need to synthesize a namespace object for + // this asset. + if (asset.meta.staticExports === false || shouldWrap || usedNamespace || defaultInterop) { + // Insert a declaration for the exports namespace object. If the asset is wrapped + // we don't need to do this, because we'll use the `module.exports` object provided + // by the wrapper instead. This is also true of CommonJS entry assets, which will use + // the `module.exports` object provided by CJS. + if (!shouldWrap && (this.bundle.env.outputFormat !== 'commonjs' || asset !== this.bundle.getMainEntry())) { + prepend += `var $${assetId}$exports = {};\n`; + prependLineCount++; + } + + // Insert the __esModule interop flag for this module if it has a `default` export + // and the namespace symbol is used. + // TODO: only if required by CJS? + if (asset.symbols.hasExportSymbol('default') && usedSymbols.has('*')) { + prepend += `\n$parcel$defineInteropFlag($${assetId}$exports);\n`; + prependLineCount += 2; + this.usedHelpers.add('$parcel$defineInteropFlag'); + } + + // Find wildcard re-export dependencies, and make sure their exports are also included in + // ours. Importantly, add them before the asset's own exports so that wildcard exports get + // correctly overwritten by own exports of the same name. + for (let dep of deps) { + let resolved = this.bundleGraph.getResolvedAsset(dep, this.bundle); + if (dep.isOptional || this.bundleGraph.isDependencySkipped(dep)) { + continue; + } + let isWrapped = resolved && resolved.meta.shouldWrap; + for (let [imported, { + local + }] of dep.symbols) { + if (imported === '*' && local === '*') { + if (!resolved) { + // Re-exporting an external module. This should have already been handled in buildReplacements. + let external = (0, _nullthrows().default)((0, _nullthrows().default)(this.externals.get(dep.specifier)).get('*')); + append += `$parcel$exportWildcard($${assetId}$exports, ${external});\n`; + this.usedHelpers.add('$parcel$exportWildcard'); + continue; + } + + // If the resolved asset has an exports object, use the $parcel$exportWildcard helper + // to re-export all symbols. Otherwise, if there's no namespace object available, add + // $parcel$export calls for each used symbol of the dependency. + if (isWrapped || resolved.meta.staticExports === false || (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(resolved)).has('*') || + // an empty asset + !resolved.meta.hasCJSExports && resolved.symbols.hasExportSymbol('*')) { + let obj = this.getSymbolResolution(asset, resolved, '*', dep); + append += `$parcel$exportWildcard($${assetId}$exports, ${obj});\n`; + this.usedHelpers.add('$parcel$exportWildcard'); + } else { + for (let symbol of (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(dep))) { + if (symbol === 'default' || + // `export * as ...` does not include the default export + symbol === '__esModule') { + continue; + } + let resolvedSymbol = this.getSymbolResolution(asset, resolved, symbol); + let get = this.buildFunctionExpression([], resolvedSymbol); + let set = asset.meta.hasCJSExports ? ', ' + this.buildFunctionExpression(['v'], `${resolvedSymbol} = v`) : ''; + prepend += `$parcel$export($${assetId}$exports, ${JSON.stringify(symbol)}, ${get}${set});\n`; + this.usedHelpers.add('$parcel$export'); + prependLineCount++; + } + } + } + } + } + + // Find the used exports of this module. This is based on the used symbols of + // incoming dependencies rather than the asset's own used exports so that we include + // re-exported symbols rather than only symbols declared in this asset. + let incomingDeps = this.bundleGraph.getIncomingDependencies(asset); + let usedExports = [...asset.symbols.exportSymbols()].filter(symbol => { + if (symbol === '*') { + return false; + } + + // If we need default interop, then all symbols are needed because the `default` + // symbol really maps to the whole namespace. + if (defaultInterop) { + return true; + } + let unused = incomingDeps.every(d => { + let symbols = (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(d)); + return !symbols.has(symbol) && !symbols.has('*'); + }); + return !unused; + }); + if (usedExports.length > 0) { + // Insert $parcel$export calls for each of the used exports. This creates a getter/setter + // for the symbol so that when the value changes the object property also changes. This is + // required to simulate ESM live bindings. It's easier to do it this way rather than inserting + // additional assignments after each mutation of the original binding. + prepend += `\n${usedExports.map(exp => { + var _asset$symbols$get2, _asset$symbols$get2$m; + let resolved = this.getSymbolResolution(asset, asset, exp); + let get = this.buildFunctionExpression([], resolved); + let isEsmExport = !!((_asset$symbols$get2 = asset.symbols.get(exp)) !== null && _asset$symbols$get2 !== void 0 && (_asset$symbols$get2$m = _asset$symbols$get2.meta) !== null && _asset$symbols$get2$m !== void 0 && _asset$symbols$get2$m.isEsm); + let set = !isEsmExport && asset.meta.hasCJSExports ? ', ' + this.buildFunctionExpression(['v'], `${resolved} = v`) : ''; + return `$parcel$export($${assetId}$exports, ${JSON.stringify(exp)}, ${get}${set});`; + }).join('\n')}\n`; + this.usedHelpers.add('$parcel$export'); + prependLineCount += 1 + usedExports.length; + } + } + return [prepend, prependLineCount, append]; + } + buildBundlePrelude() { + let enableSourceMaps = this.bundle.env.sourceMap; + let res = ''; + let lines = 0; + + // Add hashbang if the entry asset recorded an interpreter. + let mainEntry = this.bundle.getMainEntry(); + if (mainEntry && !this.isAsyncBundle && !this.bundle.target.env.isBrowser()) { + let interpreter = mainEntry.meta.interpreter; + (0, _assert().default)(interpreter == null || typeof interpreter === 'string'); + if (interpreter != null) { + res += `#!${interpreter}\n`; + lines++; + } + } + + // The output format may have specific things to add at the start of the bundle (e.g. imports). + let [outputFormatPrelude, outputFormatLines] = this.outputFormat.buildBundlePrelude(); + res += outputFormatPrelude; + lines += outputFormatLines; + + // Add used helpers. + if (this.needsPrelude) { + this.usedHelpers.add('$parcel$global'); + } + for (let helper of this.usedHelpers) { + res += _helpers.helpers[helper]; + if (enableSourceMaps) { + lines += (0, _utils().countLines)(_helpers.helpers[helper]) - 1; + } + } + if (this.needsPrelude) { + // Add the prelude if this is potentially the first JS bundle to load in a + // particular context (e.g. entry scripts in HTML, workers, etc.). + let parentBundles = this.bundleGraph.getParentBundles(this.bundle); + let mightBeFirstJS = parentBundles.length === 0 || parentBundles.some(b => b.type !== 'js') || this.bundleGraph.getBundleGroupsContainingBundle(this.bundle).some(g => this.bundleGraph.isEntryBundleGroup(g)) || this.bundle.env.isIsolated() || this.bundle.bundleBehavior === 'isolated'; + if (mightBeFirstJS) { + let preludeCode = (0, _helpers.prelude)(this.parcelRequireName); + res += preludeCode; + if (enableSourceMaps) { + lines += (0, _utils().countLines)(preludeCode) - 1; + } + } else { + // Otherwise, get the current parcelRequire global. + res += `var parcelRequire = $parcel$global[${JSON.stringify(this.parcelRequireName)}];\n`; + lines++; + } + } + + // Add importScripts for sibling bundles in workers. + if (this.bundle.env.isWorker() || this.bundle.env.isWorklet()) { + let importScripts = ''; + let bundles = this.bundleGraph.getReferencedBundles(this.bundle); + for (let b of bundles) { + if (this.bundle.env.outputFormat === 'esmodule') { + // importScripts() is not allowed in native ES module workers. + importScripts += `import "${(0, _utils().relativeBundlePath)(this.bundle, b)}";\n`; + } else { + importScripts += `importScripts("${(0, _utils().relativeBundlePath)(this.bundle, b)}");\n`; + } + } + res += importScripts; + lines += bundles.length; + } + return [res, lines]; + } + needsDefaultInterop(asset) { + if (asset.symbols.hasExportSymbol('*') && !asset.symbols.hasExportSymbol('default')) { + let deps = this.bundleGraph.getIncomingDependencies(asset); + return deps.some(dep => this.bundle.hasDependency(dep) && + // dep.meta.isES6Module && + dep.symbols.hasExportSymbol('default')); + } + return false; + } + shouldSkipAsset(asset) { + if (this.isScriptEntry(asset)) { + return true; + } + return asset.sideEffects === false && (0, _nullthrows().default)(this.bundleGraph.getUsedSymbols(asset)).size == 0 && !this.bundleGraph.isAssetReferenced(this.bundle, asset); + } + isScriptEntry(asset) { + return this.bundle.env.outputFormat === 'global' && this.bundle.env.sourceType === 'script' && asset === this.bundle.getMainEntry(); + } + buildFunctionExpression(args, expr) { + return this.bundle.env.supports('arrow-functions', true) ? `(${args.join(', ')}) => ${expr}` : `function (${args.join(', ')}) { return ${expr}; }`; + } +} +exports.ScopeHoistingPackager = ScopeHoistingPackager; \ No newline at end of file diff --git a/core/parcel-packager-vue-content-script-style-injector/src/dev-prelude.js b/core/parcel-packager-vue-content-script-style-injector/src/dev-prelude.js new file mode 100644 index 000000000..5636da413 --- /dev/null +++ b/core/parcel-packager-vue-content-script-style-injector/src/dev-prelude.js @@ -0,0 +1,145 @@ +// modules are defined as an array +// [ module function, map of requires ] +// +// map of requires is short require name -> numeric require +// +// anything defined in a previous bundle is accessed via the +// orig method which is the require for previous bundles + +(function (modules, entry, mainEntry, parcelRequireName, globalName) { + /* eslint-disable no-undef */ + var globalObject = + typeof globalThis !== 'undefined' + ? globalThis + : typeof self !== 'undefined' + ? self + : typeof window !== 'undefined' + ? window + : typeof global !== 'undefined' + ? global + : {}; + /* eslint-enable no-undef */ + + // Save the require from previous bundle to this closure if any + var previousRequire = + typeof globalObject[parcelRequireName] === 'function' && + globalObject[parcelRequireName]; + + var cache = previousRequire.cache || {}; + // Do not use `require` to prevent Webpack from trying to bundle this call + var nodeRequire = + typeof module !== 'undefined' && + typeof module.require === 'function' && + module.require.bind(module); + + function newRequire(name, jumped) { + if (!cache[name]) { + if (!modules[name]) { + // if we cannot find the module within our internal map or + // cache jump to the current global require ie. the last bundle + // that was added to the page. + var currentRequire = + typeof globalObject[parcelRequireName] === 'function' && + globalObject[parcelRequireName]; + if (!jumped && currentRequire) { + return currentRequire(name, true); + } + + // If there are other bundles on this page the require from the + // previous one is saved to 'previousRequire'. Repeat this as + // many times as there are bundles until the module is found or + // we exhaust the require chain. + if (previousRequire) { + return previousRequire(name, true); + } + + // Try the node require function if it exists. + if (nodeRequire && typeof name === 'string') { + return nodeRequire(name); + } + + var err = new Error("Cannot find module '" + name + "'"); + err.code = 'MODULE_NOT_FOUND'; + throw err; + } + + localRequire.resolve = resolve; + localRequire.cache = {}; + + var module = (cache[name] = new newRequire.Module(name)); + + modules[name][0].call( + module.exports, + localRequire, + module, + module.exports, + this + ); + } + + return cache[name].exports; + + function localRequire(x) { + var res = localRequire.resolve(x); + return res === false ? {} : newRequire(res); + } + + function resolve(x) { + var id = modules[name][1][x]; + return id != null ? id : x; + } + } + + function Module(moduleName) { + this.id = moduleName; + this.bundle = newRequire; + this.exports = {}; + } + + newRequire.isParcelRequire = true; + newRequire.Module = Module; + newRequire.modules = modules; + newRequire.cache = cache; + newRequire.parent = previousRequire; + newRequire.register = function (id, exports) { + modules[id] = [ + function (require, module) { + module.exports = exports; + }, + {}, + ]; + }; + + Object.defineProperty(newRequire, 'root', { + get: function () { + return globalObject[parcelRequireName]; + }, + }); + + globalObject[parcelRequireName] = newRequire; + + for (var i = 0; i < entry.length; i++) { + newRequire(entry[i]); + } + + if (mainEntry) { + // Expose entry point to Node, AMD or browser globals + // Based on https://github.com/ForbesLindesay/umd/blob/master/template.js + var mainExports = newRequire(mainEntry); + + // CommonJS + if (typeof exports === 'object' && typeof module !== 'undefined') { + module.exports = mainExports; + + // RequireJS + } else if (typeof define === 'function' && define.amd) { + define(function () { + return mainExports; + }); + + //