diff --git a/flow-libs/posthtml.js.flow b/flow-libs/posthtml.js.flow index 32ed17c10bf..1b2131653e9 100644 --- a/flow-libs/posthtml.js.flow +++ b/flow-libs/posthtml.js.flow @@ -11,6 +11,11 @@ declare module 'posthtml' { tag: string, attrs?: {[string]: string, ...}, content?: Array, + loc?: { + start: {|line: number, column: number|}, + end: {|line: number, column: number|}, + ... + }, ... }; @@ -26,7 +31,7 @@ declare module 'posthtml' { ... }; - declare var walk: (fn: (node: PostHTMLNode) => PostHTMLNode) => void; + declare var walk: (fn: (node: PostHTMLNode) => PostHTMLNode | PostHTMLNode[]) => void; declare var process: ( tree: PostHTMLTree | string, options: ?PostHTMLOptions, diff --git a/packages/configs/default/index.json b/packages/configs/default/index.json index 4524fa2ba25..2daad6a34e5 100644 --- a/packages/configs/default/index.json +++ b/packages/configs/default/index.json @@ -37,18 +37,11 @@ "url:*": ["@parcel/transformer-raw"] }, "namers": ["@parcel/namer-default"], - "runtimes": { - "browser": [ - "@parcel/runtime-js", - "@parcel/runtime-browser-hmr", - "@parcel/runtime-react-refresh" - ], - "service-worker": ["@parcel/runtime-js"], - "web-worker": ["@parcel/runtime-js"], - "node": ["@parcel/runtime-js"], - "electron-renderer": ["@parcel/runtime-js"], - "electron-main": ["@parcel/runtime-js"] - }, + "runtimes": [ + "@parcel/runtime-js", + "@parcel/runtime-browser-hmr", + "@parcel/runtime-react-refresh" + ], "optimizers": { "data-url:*": ["...", "@parcel/optimizer-data-url"], "*.css": ["@parcel/optimizer-cssnano"], diff --git a/packages/core/core/src/AssetGraph.js b/packages/core/core/src/AssetGraph.js index 941f94f7376..a107e7d0e0b 100644 --- a/packages/core/core/src/AssetGraph.js +++ b/packages/core/core/src/AssetGraph.js @@ -21,6 +21,7 @@ import {md5FromObject} from '@parcel/utils'; import nullthrows from 'nullthrows'; import Graph, {type GraphOpts} from './Graph'; import {createDependency} from './Dependency'; +import {getAssetGroupId} from './assetUtils'; type AssetGraphOpts = {| ...GraphOpts, @@ -55,13 +56,7 @@ export function nodeFromDep(dep: Dependency): DependencyNode { export function nodeFromAssetGroup(assetGroup: AssetGroup): AssetGroupNode { return { - id: md5FromObject({ - ...assetGroup, - // only influences building the asset graph - canDefer: undefined, - // if only the isURL property is different, no need to re-run transformation. - isURL: undefined, - }), + id: getAssetGroupId(assetGroup), type: 'asset_group', value: assetGroup, usedSymbolsDownDirty: true, diff --git a/packages/core/core/src/BundleGraph.js b/packages/core/core/src/BundleGraph.js index 65f93e3a3af..e29827d58da 100644 --- a/packages/core/core/src/BundleGraph.js +++ b/packages/core/core/src/BundleGraph.js @@ -23,7 +23,12 @@ import assert from 'assert'; import invariant from 'assert'; import crypto from 'crypto'; import nullthrows from 'nullthrows'; -import {flatMap, objectSortedEntriesDeep, unique} from '@parcel/utils'; +import { + flatMap, + objectSortedEntriesDeep, + unique, + isSubset, +} from '@parcel/utils'; import {getBundleGroupId, getPublicId} from './utils'; import Graph, {ALL_EDGE_TYPES, mapVisitor, type GraphOpts} from './Graph'; @@ -615,7 +620,7 @@ export default class BundleGraph { visitedBundles.add(descendant); if ( descendant.type !== bundle.type || - descendant.env.context !== bundle.env.context + !isSubset(descendant.env.context, bundle.env.context) ) { actions.skipChildren(); return; @@ -630,7 +635,7 @@ export default class BundleGraph { let similarSiblings = this.getSiblingBundles(descendant).filter( sibling => sibling.type === bundle.type && - sibling.env.context === bundle.env.context, + isSubset(sibling.env.context, bundle.env.context), ); if ( similarSiblings.some( @@ -713,7 +718,7 @@ export default class BundleGraph { // Don't deduplicate when context changes if ( node.type === 'bundle' && - node.value.env.context !== bundle.env.context + !isSubset(node.value.env.context, bundle.env.context) ) { actions.skipChildren(); } @@ -766,7 +771,7 @@ export default class BundleGraph { // Stop when context changes if ( node.type === 'bundle' && - node.value.env.context !== bundle.env.context + !isSubset(node.value.env.context, bundle.env.context) ) { actions.skipChildren(); } diff --git a/packages/core/core/src/Environment.js b/packages/core/core/src/Environment.js index 78a8316a579..30bef706695 100644 --- a/packages/core/core/src/Environment.js +++ b/packages/core/core/src/Environment.js @@ -17,6 +17,7 @@ export function createEnvironment({ isLibrary = false, scopeHoist = false, sourceMap, + loc, }: EnvironmentOpts = {}): Environment { if (context == null) { if (engines?.node) { @@ -28,58 +29,63 @@ export function createEnvironment({ } } + let ctx = new Set(typeof context === 'string' ? [context] : context); + if (engines == null) { - switch (context) { - case 'node': - case 'electron-main': - engines = { - node: DEFAULT_ENGINES.node, - }; - break; - case 'browser': - case 'web-worker': - case 'service-worker': - case 'electron-renderer': - engines = { - browsers: DEFAULT_ENGINES.browsers, - }; - break; - default: - engines = {}; + engines = {}; + for (let context of ctx) { + switch (context) { + case 'node': + case 'electron-main': + engines.node = DEFAULT_ENGINES.node; + break; + case 'browser': + case 'web-worker': + case 'service-worker': + case 'electron-renderer': + engines.browsers = DEFAULT_ENGINES.browsers; + break; + } } } if (includeNodeModules == null) { - switch (context) { - case 'node': - case 'electron-main': - case 'electron-renderer': - includeNodeModules = false; - break; - case 'browser': - case 'web-worker': - case 'service-worker': - default: - includeNodeModules = true; - break; + includeNodeModules = true; + for (let context of ctx) { + switch (context) { + case 'node': + case 'electron-main': + case 'electron-renderer': + includeNodeModules = false; + break; + case 'browser': + case 'web-worker': + case 'service-worker': + default: + includeNodeModules = true; + break; + } } } if (outputFormat == null) { - switch (context) { - case 'node': - case 'electron-main': - case 'electron-renderer': - outputFormat = 'commonjs'; - break; - default: - outputFormat = 'global'; - break; + outputFormat = 'global'; + for (let context of ctx) { + switch (context) { + case 'node': + case 'electron-main': + case 'electron-renderer': + outputFormat = 'commonjs'; + break; + default: + outputFormat = 'global'; + break; + } } } return { - context, + context: ctx, engines, includeNodeModules, outputFormat, @@ -87,6 +93,7 @@ export function createEnvironment({ minify, scopeHoist, sourceMap, + loc, }; } diff --git a/packages/core/core/src/PackagerRunner.js b/packages/core/core/src/PackagerRunner.js index eae47bf4b9e..d02d53a03bf 100644 --- a/packages/core/core/src/PackagerRunner.js +++ b/packages/core/core/src/PackagerRunner.js @@ -421,7 +421,7 @@ export default class PackagerRunner { sourceRoot = bundle.env.sourceMap.sourceRoot; } else if ( this.options.serve && - bundle.target.env.context === 'browser' + bundle.target.env.context.has('browser') ) { sourceRoot = '/__parcel_source_root'; } @@ -431,7 +431,7 @@ export default class PackagerRunner { bundle.env.sourceMap.inlineSources !== undefined ) { inlineSources = bundle.env.sourceMap.inlineSources; - } else if (bundle.target.env.context !== 'node') { + } else if (!bundle.target.env.context.has('node')) { // inlining should only happen in production for browser targets by default inlineSources = this.options.mode === 'production'; } diff --git a/packages/core/core/src/ParcelConfig.js b/packages/core/core/src/ParcelConfig.js index 400785cc5bc..ddb6524368d 100644 --- a/packages/core/core/src/ParcelConfig.js +++ b/packages/core/core/src/ParcelConfig.js @@ -7,7 +7,6 @@ import type { Bundler, Namer, Runtime, - EnvironmentContext, PackageName, Optimizer, Packager, @@ -52,7 +51,7 @@ export default class ParcelConfig { transformers: GlobMap; bundler: ?ParcelPluginNode; namers: PureParcelConfigPipeline; - runtimes: {[EnvironmentContext]: PureParcelConfigPipeline, ...}; + runtimes: PureParcelConfigPipeline; packagers: GlobMap; validators: GlobMap; optimizers: GlobMap; @@ -71,7 +70,7 @@ export default class ParcelConfig { this.filePath = config.filePath; this.resolvers = config.resolvers || []; this.transformers = config.transformers || {}; - this.runtimes = config.runtimes || {}; + this.runtimes = config.runtimes || []; this.bundler = config.bundler; this.namers = config.namers || []; this.packagers = config.packagers || {}; @@ -266,10 +265,8 @@ export default class ParcelConfig { return this.loadPlugins(this.namers); } - getRuntimes( - context: EnvironmentContext, - ): Promise>> { - let runtimes = this.runtimes[context]; + getRuntimes(): Promise>> { + let runtimes = this.runtimes; if (!runtimes) { return Promise.resolve([]); } diff --git a/packages/core/core/src/ParcelConfig.schema.js b/packages/core/core/src/ParcelConfig.schema.js index e0076de6a27..a54152577a2 100644 --- a/packages/core/core/src/ParcelConfig.schema.js +++ b/packages/core/core/src/ParcelConfig.schema.js @@ -122,7 +122,7 @@ export default { packagers: (mapStringSchema('packager', 'packagers'): SchemaEntity), optimizers: (mapPipelineSchema('optimizer', 'optimizers'): SchemaEntity), reporters: (pipelineSchema('reporter', 'reporters'): SchemaEntity), - runtimes: (mapPipelineSchema('runtime', 'runtimes'): SchemaEntity), + runtimes: (pipelineSchema('runtime', 'runtimes'): SchemaEntity), filePath: { type: 'string', }, diff --git a/packages/core/core/src/Transformation.js b/packages/core/core/src/Transformation.js index fdf493d9e93..b72b8061e70 100644 --- a/packages/core/core/src/Transformation.js +++ b/packages/core/core/src/Transformation.js @@ -402,7 +402,17 @@ export default class Transformation { .filter( asset => asset.ast != null && - !(asset.value.type === 'js' && asset.value.env.scopeHoist), + !( + asset.value.type === 'js' && + asset.value.env.scopeHoist && + // HACK: also handle global scripts with no dependencies. + // JSPackager calls getCode() for these even with scope hoisting, so we + // need to generate here until we find a way to make generate happen on demand. + !( + asset.value.env.context.has('script') && + asset.value.dependencies.size === 0 + ) + ), ) .map(async asset => { if (asset.isASTDirty) { diff --git a/packages/core/core/src/applyRuntimes.js b/packages/core/core/src/applyRuntimes.js index 593e739d771..10e25b8e3c8 100644 --- a/packages/core/core/src/applyRuntimes.js +++ b/packages/core/core/src/applyRuntimes.js @@ -22,6 +22,7 @@ import {setDifference} from '@parcel/utils'; import {PluginLogger} from '@parcel/logger'; import ThrowableDiagnostic, {errorToDiagnostic} from '@parcel/diagnostic'; import {dependencyToInternalDependency} from './public/Dependency'; +import {mergeEnvironments} from './Environment'; type RuntimeConnection = {| bundle: InternalBundle, @@ -46,7 +47,7 @@ export default async function applyRuntimes({ let connections: Array = []; for (let bundle of bundleGraph.getBundles()) { - let runtimes = await config.getRuntimes(bundle.env.context); + let runtimes = await config.getRuntimes(); for (let runtime of runtimes) { try { let applied = await runtime.plugin.apply({ @@ -62,11 +63,17 @@ export default async function applyRuntimes({ if (applied) { let runtimeAssets = Array.isArray(applied) ? applied : [applied]; - for (let {code, dependency, filePath, isEntry} of runtimeAssets) { + for (let { + code, + dependency, + filePath, + isEntry, + env, + } of runtimeAssets) { let assetGroup = { code, filePath, - env: bundle.env, + env: mergeEnvironments(bundle.env, env), // Runtime assets should be considered source, as they should be // e.g. compiled to run in the target environment isSource: true, diff --git a/packages/core/core/src/assetUtils.js b/packages/core/core/src/assetUtils.js index fd6e45ed935..f332eb019ff 100644 --- a/packages/core/core/src/assetUtils.js +++ b/packages/core/core/src/assetUtils.js @@ -14,6 +14,7 @@ import type { } from '@parcel/types'; import type { Asset, + AssetGroup, RequestInvalidation, Dependency, Environment, @@ -24,6 +25,7 @@ import type {ConfigOutput} from '@parcel/utils'; import {Readable} from 'stream'; import crypto from 'crypto'; import {PluginLogger} from '@parcel/logger'; +import {md5FromObject} from '@parcel/utils'; import nullthrows from 'nullthrows'; import CommittedAsset from './CommittedAsset'; import UncommittedAsset from './UncommittedAsset'; @@ -251,3 +253,14 @@ export async function getInvalidationHash( return hash.digest('hex'); } + +export function getAssetGroupId(assetGroup: AssetGroup): string { + return md5FromObject({ + ...assetGroup, + env: getEnvironmentHash(assetGroup.env), + // only influences building the asset graph + canDefer: undefined, + // if only the isURL property is different, no need to re-run transformation. + isURL: undefined, + }); +} diff --git a/packages/core/core/src/dumpGraphToGraphViz.js b/packages/core/core/src/dumpGraphToGraphViz.js index f98f0dbf979..6f7799835cb 100644 --- a/packages/core/core/src/dumpGraphToGraphViz.js +++ b/packages/core/core/src/dumpGraphToGraphViz.js @@ -138,10 +138,11 @@ export default async function dumpGraphToGraphViz( function getEnvDescription(env: Environment) { let description; + let context = [...env.context].join(', '); if (typeof env.engines.browsers === 'string') { - description = `${env.context}: ${env.engines.browsers}`; + description = `${context}: ${env.engines.browsers}`; } else if (Array.isArray(env.engines.browsers)) { - description = `${env.context}: ${env.engines.browsers.join(', ')}`; + description = `${context}: ${env.engines.browsers.join(', ')}`; } else if (env.engines.node) { description = `node: ${env.engines.node}`; } else if (env.engines.electron) { diff --git a/packages/core/core/src/public/Environment.js b/packages/core/core/src/public/Environment.js index 9f1283b93e2..d1bcd892471 100644 --- a/packages/core/core/src/public/Environment.js +++ b/packages/core/core/src/public/Environment.js @@ -2,26 +2,35 @@ import type { Environment as IEnvironment, EnvironmentContext, + EnvironmentFeature, Engines, OutputFormat, PackageName, VersionMap, TargetSourceMapOptions, + SourceLocation, } from '@parcel/types'; import type {Environment as InternalEnvironment} from '../types'; import nullthrows from 'nullthrows'; import browserslist from 'browserslist'; import semver from 'semver'; +import {setIntersects} from '@parcel/utils'; -export const BROWSER_ENVS: Set = new Set([ +export const BROWSER_ENVS: Set = new Set([ 'browser', 'web-worker', 'service-worker', 'electron-renderer', ]); -const ELECTRON_ENVS = new Set(['electron-main', 'electron-renderer']); -const NODE_ENVS = new Set(['node', ...ELECTRON_ENVS]); -const WORKER_ENVS = new Set(['web-worker', 'service-worker']); +const ELECTRON_ENVS = new Set([ + 'electron-main', + 'electron-renderer', +]); +const NODE_ENVS = new Set(['node', ...ELECTRON_ENVS]); +const WORKER_ENVS = new Set([ + 'web-worker', + 'service-worker', +]); const ISOLATED_ENVS = WORKER_ENVS; const ALL_BROWSERS = [ @@ -45,17 +54,39 @@ const ALL_BROWSERS = [ 'kaios', ]; -const ESMODULE_BROWSERS = { - edge: '16', - firefox: '60', - chrome: '61', - safari: '11', - opera: '48', - ios: '11', - android: '76', - and_chr: '76', - and_ff: '68', - samsung: '8.2', +const supportData = { + esmodules: { + edge: '16', + firefox: '60', + chrome: '61', + safari: '11', + opera: '48', + ios: '11', + android: '76', + and_chr: '76', + and_ff: '68', + samsung: '8.2', + }, + 'dynamic-import': { + edge: '76', + firefox: '67', + chrome: '63', + safari: '11.1', + opera: '50', + ios: '11.3', + android: '63', + and_chr: '63', + and_ff: '67', + samsung: '8', + }, + 'worker-type': { + edge: '80', + chrome: '80', + opera: '67', + android: '81', + and_chr: '86', + }, + 'service-worker-type': {}, }; const internalEnvironmentToEnvironment: WeakMap< @@ -87,7 +118,7 @@ export default class Environment implements IEnvironment { return this; } - get context(): EnvironmentContext { + get context(): Set { return this.#environment.context; } @@ -122,24 +153,28 @@ export default class Environment implements IEnvironment { return this.#environment.sourceMap; } + get loc(): ?SourceLocation { + return this.#environment.loc; + } + isBrowser(): boolean { - return BROWSER_ENVS.has(this.#environment.context); + return setIntersects(this.#environment.context, BROWSER_ENVS); } isNode(): boolean { - return NODE_ENVS.has(this.#environment.context); + return setIntersects(this.#environment.context, NODE_ENVS); } isElectron(): boolean { - return ELECTRON_ENVS.has(this.#environment.context); + return setIntersects(this.#environment.context, ELECTRON_ENVS); } isIsolated(): boolean { - return ISOLATED_ENVS.has(this.#environment.context); + return setIntersects(this.#environment.context, ISOLATED_ENVS); } isWorker(): boolean { - return WORKER_ENVS.has(this.#environment.context); + return setIntersects(this.#environment.context, WORKER_ENVS); } matchesEngines(minVersions: VersionMap): boolean { @@ -155,7 +190,7 @@ export default class Environment implements IEnvironment { // If outputting esmodules, exclude browsers without support. if (this.outputFormat === 'esmodule') { - browsers = [...browsers, ...getExcludedBrowsers(ESMODULE_BROWSERS)]; + browsers = [...browsers, ...getExcludedBrowsers(supportData.esmodules)]; } let matchedBrowsers = browserslist(browsers); @@ -168,6 +203,15 @@ export default class Environment implements IEnvironment { return false; } + + supports(feature: EnvironmentFeature): boolean { + let engines = supportData[feature]; + if (!engines) { + throw new Error('Unknown environment feature: ' + feature); + } + + return this.matchesEngines(engines); + } } function getExcludedBrowsers(minVersions: VersionMap) { diff --git a/packages/core/core/src/requests/AssetRequest.js b/packages/core/core/src/requests/AssetRequest.js index 0a06b35928b..2b84a9a0a8c 100644 --- a/packages/core/core/src/requests/AssetRequest.js +++ b/packages/core/core/src/requests/AssetRequest.js @@ -9,6 +9,7 @@ import type {TransformationResult} from '../Transformation'; import {md5FromObject} from '@parcel/utils'; import nullthrows from 'nullthrows'; import createParcelConfigRequest from './ParcelConfigRequest'; +import {getAssetGroupId} from '../assetUtils'; type RunInput = {| input: AssetRequestInput, @@ -42,7 +43,7 @@ const type = 'asset_request'; function getId(input: AssetRequestInput) { // eslint-disable-next-line no-unused-vars let {optionsRef, ...hashInput} = input; - return `${type}:${md5FromObject(hashInput)}`; + return `${type}:${getAssetGroupId(hashInput)}`; } async function run({input, api, options, farm}: RunInput) { diff --git a/packages/core/core/src/requests/ParcelConfigRequest.js b/packages/core/core/src/requests/ParcelConfigRequest.js index 0f1e5ca120c..d41b6132715 100644 --- a/packages/core/core/src/requests/ParcelConfigRequest.js +++ b/packages/core/core/src/requests/ParcelConfigRequest.js @@ -269,7 +269,11 @@ export function processConfig( } : undefined, namers: processPipeline(configFile.namers, '/namers', configFile.filePath), - runtimes: processMap(configFile.runtimes, '/runtimes', configFile.filePath), + runtimes: processPipeline( + configFile.runtimes, + '/runtimes', + configFile.filePath, + ), packagers: processMap( configFile.packagers, '/packagers', @@ -491,7 +495,7 @@ export function mergeConfigs( validators: mergeMaps(base.validators, ext.validators, mergePipelines), bundler: ext.bundler || base.bundler, namers: mergePipelines(base.namers, ext.namers), - runtimes: mergeMaps(base.runtimes, ext.runtimes, mergePipelines), + runtimes: mergePipelines(base.runtimes, ext.runtimes), packagers: mergeMaps(base.packagers, ext.packagers), optimizers: mergeMaps(base.optimizers, ext.optimizers, mergePipelines), reporters: mergePipelines(base.reporters, ext.reporters), diff --git a/packages/core/core/src/requests/TargetRequest.js b/packages/core/core/src/requests/TargetRequest.js index 8c88cfe044c..cc5cba9e392 100644 --- a/packages/core/core/src/requests/TargetRequest.js +++ b/packages/core/core/src/requests/TargetRequest.js @@ -24,6 +24,7 @@ import { resolveConfig, md5FromObject, validateSchema, + setIntersects, } from '@parcel/utils'; import {createEnvironment} from '../Environment'; import createParcelConfigRequest from './ParcelConfigRequest'; @@ -199,7 +200,7 @@ export class TargetResolver { }, }); } - if (!BROWSER_ENVS.has(targets[0].env.context)) { + if (!setIntersects(BROWSER_ENVS, targets[0].env.context)) { throw new ThrowableDiagnostic({ diagnostic: { message: `Only browser targets are supported in serve mode`, diff --git a/packages/core/core/src/types.js b/packages/core/core/src/types.js index 70a819fcaaf..9b0a3e98364 100644 --- a/packages/core/core/src/types.js +++ b/packages/core/core/src/types.js @@ -50,7 +50,7 @@ export type ProcessedParcelConfig = {| transformers?: {[Glob]: ExtendableParcelConfigPipeline, ...}, bundler: ?ParcelPluginNode, namers?: PureParcelConfigPipeline, - runtimes?: {[EnvironmentContext]: PureParcelConfigPipeline, ...}, + runtimes?: PureParcelConfigPipeline, packagers?: {[Glob]: ParcelPluginNode, ...}, optimizers?: {[Glob]: ExtendableParcelConfigPipeline, ...}, reporters?: PureParcelConfigPipeline, @@ -60,7 +60,7 @@ export type ProcessedParcelConfig = {| |}; export type Environment = {| - context: EnvironmentContext, + context: Set, engines: Engines, includeNodeModules: | boolean @@ -71,6 +71,7 @@ export type Environment = {| minify: boolean, scopeHoist: boolean, sourceMap: ?TargetSourceMapOptions, + loc: ?SourceLocation, |}; export type Target = {| diff --git a/packages/core/core/test/Environment.test.js b/packages/core/core/test/Environment.test.js index 40dd9b048f9..733097e4bfd 100644 --- a/packages/core/core/test/Environment.test.js +++ b/packages/core/core/test/Environment.test.js @@ -6,7 +6,7 @@ import {createEnvironment} from '../src/Environment'; describe('Environment', () => { it('assigns a default environment with nothing passed', () => { assert.deepEqual(createEnvironment(), { - context: 'browser', + context: new Set(['browser']), engines: { browsers: ['> 0.25%'], }, @@ -16,12 +16,13 @@ describe('Environment', () => { minify: false, scopeHoist: false, sourceMap: undefined, + loc: undefined, }); }); it('assigns a node context if a node engine is given', () => { assert.deepEqual(createEnvironment({engines: {node: '>= 10.0.0'}}), { - context: 'node', + context: new Set(['node']), engines: { node: '>= 10.0.0', }, @@ -31,6 +32,7 @@ describe('Environment', () => { minify: false, scopeHoist: false, sourceMap: undefined, + loc: undefined, }); }); @@ -38,7 +40,7 @@ describe('Environment', () => { assert.deepEqual( createEnvironment({engines: {browsers: ['last 1 version']}}), { - context: 'browser', + context: new Set(['browser']), engines: { browsers: ['last 1 version'], }, @@ -48,13 +50,14 @@ describe('Environment', () => { minify: false, scopeHoist: false, sourceMap: undefined, + loc: undefined, }, ); }); it('assigns default engines for node', () => { assert.deepEqual(createEnvironment({context: 'node'}), { - context: 'node', + context: new Set(['node']), engines: { node: '>= 8.0.0', }, @@ -64,12 +67,13 @@ describe('Environment', () => { minify: false, scopeHoist: false, sourceMap: undefined, + loc: undefined, }); }); it('assigns default engines for browsers', () => { assert.deepEqual(createEnvironment({context: 'browser'}), { - context: 'browser', + context: new Set(['browser']), engines: { browsers: ['> 0.25%'], }, @@ -79,6 +83,7 @@ describe('Environment', () => { minify: false, scopeHoist: false, sourceMap: undefined, + loc: undefined, }); }); }); diff --git a/packages/core/core/test/ParcelConfigRequest.test.js b/packages/core/core/test/ParcelConfigRequest.test.js index 572caf8d19c..509f4d38570 100644 --- a/packages/core/core/test/ParcelConfigRequest.test.js +++ b/packages/core/core/test/ParcelConfigRequest.test.js @@ -568,7 +568,7 @@ describe('loadParcelConfig', () => { resolveFrom: '.parcelrc', keyPath: '/bundler', }, - runtimes: {}, + runtimes: [], namers: [], optimizers: {}, packagers: {}, diff --git a/packages/core/core/test/TargetRequest.test.js b/packages/core/core/test/TargetRequest.test.js index 643450d51e3..1a74e436d31 100644 --- a/packages/core/core/test/TargetRequest.test.js +++ b/packages/core/core/test/TargetRequest.test.js @@ -103,7 +103,7 @@ describe('TargetResolver', () => { publicUrl: '/', distDir: path.resolve('customA'), env: { - context: 'browser', + context: new Set(['browser']), includeNodeModules: true, engines: { browsers: ['> 0.25%'], @@ -113,6 +113,7 @@ describe('TargetResolver', () => { minify: false, scopeHoist: false, sourceMap: {}, + loc: undefined, }, }, { @@ -120,7 +121,7 @@ describe('TargetResolver', () => { publicUrl: '/', distDir: path.resolve('customB'), env: { - context: 'node', + context: new Set(['node']), includeNodeModules: false, engines: { node: '>= 8.0.0', @@ -130,6 +131,7 @@ describe('TargetResolver', () => { minify: false, scopeHoist: false, sourceMap: {}, + loc: undefined, }, }, ], @@ -148,7 +150,7 @@ describe('TargetResolver', () => { distEntry: 'index.js', publicUrl: '/', env: { - context: 'node', + context: new Set(['node']), engines: { node: '>= 8.0.0', }, @@ -158,6 +160,7 @@ describe('TargetResolver', () => { minify: false, scopeHoist: false, sourceMap: {}, + loc: undefined, }, loc: { filePath: path.join(COMMON_TARGETS_FIXTURE_PATH, 'package.json'), @@ -177,7 +180,7 @@ describe('TargetResolver', () => { distEntry: 'index.js', publicUrl: '/', env: { - context: 'browser', + context: new Set(['browser']), engines: { browsers: ['last 1 version'], }, @@ -189,6 +192,7 @@ describe('TargetResolver', () => { sourceMap: { inlineSources: true, }, + loc: undefined, }, loc: { filePath: path.join(COMMON_TARGETS_FIXTURE_PATH, 'package.json'), @@ -208,7 +212,7 @@ describe('TargetResolver', () => { distEntry: 'index.js', publicUrl: '/assets', env: { - context: 'browser', + context: new Set(['browser']), engines: { browsers: ['last 1 version'], }, @@ -218,6 +222,7 @@ describe('TargetResolver', () => { minify: false, scopeHoist: false, sourceMap: {}, + loc: undefined, }, loc: { filePath: path.join(COMMON_TARGETS_FIXTURE_PATH, 'package.json'), @@ -247,7 +252,7 @@ describe('TargetResolver', () => { distEntry: 'index.js', publicUrl: '/', env: { - context: 'node', + context: new Set(['node']), engines: { node: '>= 8.0.0', }, @@ -257,6 +262,7 @@ describe('TargetResolver', () => { minify: false, scopeHoist: false, sourceMap: undefined, + loc: undefined, }, loc: { filePath: path.join( @@ -288,7 +294,7 @@ describe('TargetResolver', () => { distEntry: 'index.js', publicUrl: '/', env: { - context: 'node', + context: new Set(['node']), engines: { node: '>= 8.0.0', }, @@ -298,6 +304,7 @@ describe('TargetResolver', () => { minify: false, scopeHoist: false, sourceMap: {}, + loc: undefined, }, loc: { filePath: path.join(CUSTOM_TARGETS_FIXTURE_PATH, 'package.json'), @@ -320,7 +327,7 @@ describe('TargetResolver', () => { distEntry: 'index.js', publicUrl: '/', env: { - context: 'browser', + context: new Set(['browser']), engines: { browsers: ['last 1 version'], }, @@ -330,6 +337,7 @@ describe('TargetResolver', () => { minify: false, scopeHoist: false, sourceMap: {}, + loc: undefined, }, loc: { filePath: path.join(CUSTOM_TARGETS_FIXTURE_PATH, 'package.json'), @@ -352,7 +360,7 @@ describe('TargetResolver', () => { distEntry: 'index.js', publicUrl: '/', env: { - context: 'browser', + context: new Set(['browser']), engines: { browsers: ['ie11'], }, @@ -362,6 +370,7 @@ describe('TargetResolver', () => { minify: false, scopeHoist: false, sourceMap: {}, + loc: undefined, }, loc: { filePath: path.join(CUSTOM_TARGETS_FIXTURE_PATH, 'package.json'), @@ -390,7 +399,7 @@ describe('TargetResolver', () => { distEntry: undefined, publicUrl: 'www', env: { - context: 'browser', + context: new Set(['browser']), engines: { browsers: '> 0.25%', }, @@ -400,6 +409,7 @@ describe('TargetResolver', () => { minify: false, scopeHoist: false, sourceMap: {}, + loc: undefined, }, loc: undefined, }, @@ -416,7 +426,7 @@ describe('TargetResolver', () => { distEntry: 'index.js', publicUrl: '/', env: { - context: 'node', + context: new Set(['node']), engines: {}, includeNodeModules: false, isLibrary: true, @@ -424,6 +434,7 @@ describe('TargetResolver', () => { minify: false, scopeHoist: false, sourceMap: {}, + loc: undefined, }, loc: { filePath: path.join(CONTEXT_FIXTURE_PATH, 'package.json'), @@ -450,7 +461,7 @@ describe('TargetResolver', () => { distEntry: 'index.html', publicUrl: '/', env: { - context: 'browser', + context: new Set(['browser']), engines: {}, includeNodeModules: true, isLibrary: false, @@ -458,6 +469,7 @@ describe('TargetResolver', () => { minify: false, scopeHoist: false, sourceMap: {}, + loc: undefined, }, loc: { filePath: path.join(fixture, 'package.json'), @@ -489,7 +501,7 @@ describe('TargetResolver', () => { distEntry: 'index.js', publicUrl: '/', env: { - context: 'node', + context: new Set(['node']), engines: { node: '>= 8.0.0', }, @@ -499,6 +511,7 @@ describe('TargetResolver', () => { minify: false, scopeHoist: false, sourceMap: {}, + loc: undefined, }, loc: { filePath: path.join(COMMON_TARGETS_FIXTURE_PATH, 'package.json'), @@ -518,7 +531,7 @@ describe('TargetResolver', () => { distEntry: 'index.js', publicUrl: '/assets', env: { - context: 'browser', + context: new Set(['browser']), engines: { browsers: ['last 1 version'], }, @@ -528,6 +541,7 @@ describe('TargetResolver', () => { minify: false, scopeHoist: false, sourceMap: {}, + loc: undefined, }, loc: { filePath: path.join(COMMON_TARGETS_FIXTURE_PATH, 'package.json'), @@ -561,7 +575,7 @@ describe('TargetResolver', () => { distDir: serveDistDir, publicUrl: '/', env: { - context: 'browser', + context: new Set(['browser']), engines: {}, includeNodeModules: true, outputFormat: 'global', @@ -569,6 +583,7 @@ describe('TargetResolver', () => { minify: false, scopeHoist: false, sourceMap: {}, + loc: undefined, }, }, ], @@ -586,7 +601,7 @@ describe('TargetResolver', () => { distDir: path.join(DEFAULT_DISTPATH_FIXTURE_PATHS.none, 'dist'), publicUrl: '/', env: { - context: 'browser', + context: new Set(['browser']), engines: { browsers: ['Chrome 80'], }, @@ -596,6 +611,7 @@ describe('TargetResolver', () => { minify: false, scopeHoist: false, sourceMap: {}, + loc: undefined, }, }, ], @@ -614,7 +630,7 @@ describe('TargetResolver', () => { distEntry: undefined, publicUrl: '/', env: { - context: 'browser', + context: new Set(['browser']), engines: { browsers: ['Chrome 80'], }, @@ -624,6 +640,7 @@ describe('TargetResolver', () => { minify: false, scopeHoist: false, sourceMap: {}, + loc: undefined, }, loc: undefined, }, @@ -647,7 +664,7 @@ describe('TargetResolver', () => { distEntry: undefined, publicUrl: '/', env: { - context: 'browser', + context: new Set(['browser']), engines: { browsers: ['last 1 version'], }, @@ -657,6 +674,7 @@ describe('TargetResolver', () => { minify: false, scopeHoist: false, sourceMap: {}, + loc: undefined, }, loc: undefined, }, @@ -670,7 +688,7 @@ describe('TargetResolver', () => { distEntry: undefined, publicUrl: '/', env: { - context: 'browser', + context: new Set(['browser']), engines: { browsers: ['IE 11'], }, @@ -680,6 +698,7 @@ describe('TargetResolver', () => { minify: false, scopeHoist: false, sourceMap: {}, + loc: undefined, }, loc: undefined, }, diff --git a/packages/core/integration-tests/test/cache.js b/packages/core/integration-tests/test/cache.js index 4e1de620e17..8682d31b1fe 100644 --- a/packages/core/integration-tests/test/cache.js +++ b/packages/core/integration-tests/test/cache.js @@ -1808,7 +1808,7 @@ describe('cache', function() { 'utf8', ); assert( - contents.includes(' + diff --git a/packages/core/integration-tests/test/integration/child-bundle-different-types/index.html b/packages/core/integration-tests/test/integration/child-bundle-different-types/index.html index 369affb5284..5d598792931 100644 --- a/packages/core/integration-tests/test/integration/child-bundle-different-types/index.html +++ b/packages/core/integration-tests/test/integration/child-bundle-different-types/index.html @@ -11,7 +11,7 @@
Hello World Main1
- + GOOO diff --git a/packages/core/integration-tests/test/integration/child-bundle-different-types/other.html b/packages/core/integration-tests/test/integration/child-bundle-different-types/other.html index 039877f1c75..f8f2fd35821 100644 --- a/packages/core/integration-tests/test/integration/child-bundle-different-types/other.html +++ b/packages/core/integration-tests/test/integration/child-bundle-different-types/other.html @@ -12,6 +12,6 @@
Heelo
- + diff --git a/packages/core/integration-tests/test/integration/config-merging/node_modules/parcel-config-test1/index.json b/packages/core/integration-tests/test/integration/config-merging/node_modules/parcel-config-test1/index.json index f5c63dad559..bd936f973cf 100644 --- a/packages/core/integration-tests/test/integration/config-merging/node_modules/parcel-config-test1/index.json +++ b/packages/core/integration-tests/test/integration/config-merging/node_modules/parcel-config-test1/index.json @@ -1,5 +1,3 @@ { - "runtimes": { - "node": ["parcel-runtime-nothing"] - } -} \ No newline at end of file + "runtimes": ["parcel-runtime-nothing"] +} diff --git a/packages/core/integration-tests/test/integration/formats/esm-split-worker/index.html b/packages/core/integration-tests/test/integration/formats/esm-split-worker/index.html index f9757275016..8ef9a70b216 100644 --- a/packages/core/integration-tests/test/integration/formats/esm-split-worker/index.html +++ b/packages/core/integration-tests/test/integration/formats/esm-split-worker/index.html @@ -1 +1 @@ - + diff --git a/packages/core/integration-tests/test/integration/formats/global-split-worker/index.js b/packages/core/integration-tests/test/integration/formats/global-split-worker/index.js index acd15616078..4e92121ae11 100644 --- a/packages/core/integration-tests/test/integration/formats/global-split-worker/index.js +++ b/packages/core/integration-tests/test/integration/formats/global-split-worker/index.js @@ -1 +1 @@ -new Worker("./main-worker"); +new Worker("./main-worker", {type: 'module'}); diff --git a/packages/core/integration-tests/test/integration/hmr-css/index.html b/packages/core/integration-tests/test/integration/hmr-css/index.html index be258553b16..9c2debef441 100644 --- a/packages/core/integration-tests/test/integration/hmr-css/index.html +++ b/packages/core/integration-tests/test/integration/hmr-css/index.html @@ -6,6 +6,6 @@

Hello world

- + diff --git a/packages/core/integration-tests/test/integration/html-css-doctype/index.html b/packages/core/integration-tests/test/integration/html-css-doctype/index.html index 20089f80e97..621e1c3896c 100644 --- a/packages/core/integration-tests/test/integration/html-css-doctype/index.html +++ b/packages/core/integration-tests/test/integration/html-css-doctype/index.html @@ -1,2 +1,2 @@ - + diff --git a/packages/core/integration-tests/test/integration/html-css-head/index.html b/packages/core/integration-tests/test/integration/html-css-head/index.html index 4a75e1b2f68..73d78078aef 100644 --- a/packages/core/integration-tests/test/integration/html-css-head/index.html +++ b/packages/core/integration-tests/test/integration/html-css-head/index.html @@ -2,6 +2,6 @@

Hello world

- + diff --git a/packages/core/integration-tests/test/integration/html-css-multi/index.html b/packages/core/integration-tests/test/integration/html-css-multi/index.html index 96d3c5bc374..ffa2fe3ccf0 100644 --- a/packages/core/integration-tests/test/integration/html-css-multi/index.html +++ b/packages/core/integration-tests/test/integration/html-css-multi/index.html @@ -5,7 +5,7 @@

Hello world

- - + + diff --git a/packages/core/integration-tests/test/integration/html-css-optional-elements/index.html b/packages/core/integration-tests/test/integration/html-css-optional-elements/index.html index 5872bd0c236..daa2db4ff8c 100644 --- a/packages/core/integration-tests/test/integration/html-css-optional-elements/index.html +++ b/packages/core/integration-tests/test/integration/html-css-optional-elements/index.html @@ -1,3 +1,3 @@ - +

Hello world

- + diff --git a/packages/core/integration-tests/test/integration/html-css/index.html b/packages/core/integration-tests/test/integration/html-css/index.html index 6c89ab7a5d1..d4fe22cfc3c 100644 --- a/packages/core/integration-tests/test/integration/html-css/index.html +++ b/packages/core/integration-tests/test/integration/html-css/index.html @@ -5,6 +5,6 @@

Hello world

- + diff --git a/packages/core/integration-tests/test/integration/html-inline-js-nested/index.html b/packages/core/integration-tests/test/integration/html-inline-js-nested/index.html index 9236b58d00c..2e5bfbe1c8d 100644 --- a/packages/core/integration-tests/test/integration/html-inline-js-nested/index.html +++ b/packages/core/integration-tests/test/integration/html-inline-js-nested/index.html @@ -1,7 +1,7 @@ - diff --git a/packages/core/integration-tests/test/integration/html-inline-js-require/index.html b/packages/core/integration-tests/test/integration/html-inline-js-require/index.html index db239f85561..25491b16e20 100644 --- a/packages/core/integration-tests/test/integration/html-inline-js-require/index.html +++ b/packages/core/integration-tests/test/integration/html-inline-js-require/index.html @@ -1,7 +1,7 @@ - diff --git a/packages/core/integration-tests/test/integration/html-inline-js-script/error.html b/packages/core/integration-tests/test/integration/html-inline-js-script/error.html new file mode 100644 index 00000000000..37ba6b5d52f --- /dev/null +++ b/packages/core/integration-tests/test/integration/html-inline-js-script/error.html @@ -0,0 +1,8 @@ + + + + + + diff --git a/packages/core/integration-tests/test/integration/html-inline-js-script/globals-dependencies.html b/packages/core/integration-tests/test/integration/html-inline-js-script/globals-dependencies.html new file mode 100644 index 00000000000..5eb3d443626 --- /dev/null +++ b/packages/core/integration-tests/test/integration/html-inline-js-script/globals-dependencies.html @@ -0,0 +1,34 @@ + + + + + + + diff --git a/packages/core/integration-tests/test/integration/html-inline-js-script/globals.html b/packages/core/integration-tests/test/integration/html-inline-js-script/globals.html new file mode 100644 index 00000000000..448885b5a46 --- /dev/null +++ b/packages/core/integration-tests/test/integration/html-inline-js-script/globals.html @@ -0,0 +1,32 @@ + + + + + + + diff --git a/packages/core/integration-tests/test/integration/html-inline-js-script/module.js b/packages/core/integration-tests/test/integration/html-inline-js-script/module.js new file mode 100644 index 00000000000..e64329c055c --- /dev/null +++ b/packages/core/integration-tests/test/integration/html-inline-js-script/module.js @@ -0,0 +1 @@ +export function bar() {} diff --git a/packages/core/integration-tests/test/integration/html-js-dedup/index.html b/packages/core/integration-tests/test/integration/html-js-dedup/index.html index 9eb00fb7970..4f42abf403c 100644 --- a/packages/core/integration-tests/test/integration/html-js-dedup/index.html +++ b/packages/core/integration-tests/test/integration/html-js-dedup/index.html @@ -1,3 +1,3 @@ - - + + diff --git a/packages/core/integration-tests/test/integration/html-js-dynamic/index.html b/packages/core/integration-tests/test/integration/html-js-dynamic/index.html index 5b1eef45117..28a01ea786f 100644 --- a/packages/core/integration-tests/test/integration/html-js-dynamic/index.html +++ b/packages/core/integration-tests/test/integration/html-js-dynamic/index.html @@ -1 +1 @@ - + diff --git a/packages/core/integration-tests/test/integration/html-js-shared-dynamic-nested/index.html b/packages/core/integration-tests/test/integration/html-js-shared-dynamic-nested/index.html index 62550945d54..28a01ea786f 100644 --- a/packages/core/integration-tests/test/integration/html-js-shared-dynamic-nested/index.html +++ b/packages/core/integration-tests/test/integration/html-js-shared-dynamic-nested/index.html @@ -1 +1 @@ - + diff --git a/packages/core/integration-tests/test/integration/html-js-shared-head/index.html b/packages/core/integration-tests/test/integration/html-js-shared-head/index.html index de142808b50..574253d85c3 100644 --- a/packages/core/integration-tests/test/integration/html-js-shared-head/index.html +++ b/packages/core/integration-tests/test/integration/html-js-shared-head/index.html @@ -1,5 +1,5 @@ - + diff --git a/packages/core/integration-tests/test/integration/html-js-shared-head/index.js b/packages/core/integration-tests/test/integration/html-js-shared-head/index.js index a6c38c90611..e4634b835fe 100644 --- a/packages/core/integration-tests/test/integration/html-js-shared-head/index.js +++ b/packages/core/integration-tests/test/integration/html-js-shared-head/index.js @@ -1,3 +1,3 @@ console.log(require("lodash").add(1, 2)); import("./async.js"); -new Worker("./worker.js"); +new Worker("./worker.js", {type: 'module'}); diff --git a/packages/core/integration-tests/test/integration/html-js-shared/index.html b/packages/core/integration-tests/test/integration/html-js-shared/index.html index 62550945d54..28a01ea786f 100644 --- a/packages/core/integration-tests/test/integration/html-js-shared/index.html +++ b/packages/core/integration-tests/test/integration/html-js-shared/index.html @@ -1 +1 @@ - + diff --git a/packages/core/integration-tests/test/integration/html-js-shared/index.js b/packages/core/integration-tests/test/integration/html-js-shared/index.js index a6c38c90611..e4634b835fe 100644 --- a/packages/core/integration-tests/test/integration/html-js-shared/index.js +++ b/packages/core/integration-tests/test/integration/html-js-shared/index.js @@ -1,3 +1,3 @@ console.log(require("lodash").add(1, 2)); import("./async.js"); -new Worker("./worker.js"); +new Worker("./worker.js", {type: 'module'}); diff --git a/packages/core/integration-tests/test/integration/html-js/error.html b/packages/core/integration-tests/test/integration/html-js/error.html new file mode 100644 index 00000000000..5b1eef45117 --- /dev/null +++ b/packages/core/integration-tests/test/integration/html-js/error.html @@ -0,0 +1 @@ + diff --git a/packages/core/integration-tests/test/integration/html-js/index.html b/packages/core/integration-tests/test/integration/html-js/index.html index 5b1eef45117..28a01ea786f 100644 --- a/packages/core/integration-tests/test/integration/html-js/index.html +++ b/packages/core/integration-tests/test/integration/html-js/index.html @@ -1 +1 @@ - + diff --git a/packages/core/integration-tests/test/integration/html-multi-entry/a.html b/packages/core/integration-tests/test/integration/html-multi-entry/a.html index 3adf1b06490..cf0f457dce2 100644 --- a/packages/core/integration-tests/test/integration/html-multi-entry/a.html +++ b/packages/core/integration-tests/test/integration/html-multi-entry/a.html @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/html-multi-entry/b.html b/packages/core/integration-tests/test/integration/html-multi-entry/b.html index 3adf1b06490..cf0f457dce2 100644 --- a/packages/core/integration-tests/test/integration/html-multi-entry/b.html +++ b/packages/core/integration-tests/test/integration/html-multi-entry/b.html @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/html-root/index.html b/packages/core/integration-tests/test/integration/html-root/index.html index a060a6f8ece..8ef8c1c244b 100644 --- a/packages/core/integration-tests/test/integration/html-root/index.html +++ b/packages/core/integration-tests/test/integration/html-root/index.html @@ -5,6 +5,6 @@ goto page2 - + \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/html-root/other.html b/packages/core/integration-tests/test/integration/html-root/other.html index 98159107ce9..0a3d424c585 100644 --- a/packages/core/integration-tests/test/integration/html-root/other.html +++ b/packages/core/integration-tests/test/integration/html-root/other.html @@ -5,6 +5,6 @@ goto page1 - + \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/html-shared-worker/index.html b/packages/core/integration-tests/test/integration/html-shared-worker/index.html index 8de9044b9f0..adf50f053d1 100644 --- a/packages/core/integration-tests/test/integration/html-shared-worker/index.html +++ b/packages/core/integration-tests/test/integration/html-shared-worker/index.html @@ -2,6 +2,6 @@

Hello!

- + diff --git a/packages/core/integration-tests/test/integration/html-shared-worker/index.js b/packages/core/integration-tests/test/integration/html-shared-worker/index.js index 7cbc0d82094..b4357ed68aa 100644 --- a/packages/core/integration-tests/test/integration/html-shared-worker/index.js +++ b/packages/core/integration-tests/test/integration/html-shared-worker/index.js @@ -2,4 +2,4 @@ import _ from 'lodash'; output("main", _.add(1, 2)); -new Worker('worker.js'); +new Worker('worker.js', {type: 'module'}); diff --git a/packages/core/integration-tests/test/integration/html-shared/iframe.html b/packages/core/integration-tests/test/integration/html-shared/iframe.html index 98d8b81bdb8..82f21258c76 100644 --- a/packages/core/integration-tests/test/integration/html-shared/iframe.html +++ b/packages/core/integration-tests/test/integration/html-shared/iframe.html @@ -1,6 +1,6 @@ - + diff --git a/packages/core/integration-tests/test/integration/html-shared/index.html b/packages/core/integration-tests/test/integration/html-shared/index.html index d22e4819f68..807387c3516 100644 --- a/packages/core/integration-tests/test/integration/html-shared/index.html +++ b/packages/core/integration-tests/test/integration/html-shared/index.html @@ -3,6 +3,6 @@

Hello!

- + diff --git a/packages/core/integration-tests/test/integration/react-refresh-lazy-child/index.html b/packages/core/integration-tests/test/integration/react-refresh-lazy-child/index.html index fb38e86b2a2..4c99f276ba5 100644 --- a/packages/core/integration-tests/test/integration/react-refresh-lazy-child/index.html +++ b/packages/core/integration-tests/test/integration/react-refresh-lazy-child/index.html @@ -1,2 +1,2 @@
- + diff --git a/packages/core/integration-tests/test/integration/react-refresh/index.html b/packages/core/integration-tests/test/integration/react-refresh/index.html index fb38e86b2a2..4c99f276ba5 100644 --- a/packages/core/integration-tests/test/integration/react-refresh/index.html +++ b/packages/core/integration-tests/test/integration/react-refresh/index.html @@ -1,2 +1,2 @@
- + diff --git a/packages/core/integration-tests/test/integration/resolver-dependency-meta/.parcelrc b/packages/core/integration-tests/test/integration/resolver-dependency-meta/.parcelrc index d17352e86fe..8010d0f9604 100644 --- a/packages/core/integration-tests/test/integration/resolver-dependency-meta/.parcelrc +++ b/packages/core/integration-tests/test/integration/resolver-dependency-meta/.parcelrc @@ -1,7 +1,5 @@ { "extends": "@parcel/config-default", "resolvers": ["parcel-resolver-meta", "..."], - "runtimes": { - "browser": ["parcel-runtime-meta", "..."] - } + "runtimes": ["parcel-runtime-meta", "..."] } diff --git a/packages/core/integration-tests/test/integration/runtime-symbol-merging/.parcelrc b/packages/core/integration-tests/test/integration/runtime-symbol-merging/.parcelrc index 011e986fafe..596c8254b81 100644 --- a/packages/core/integration-tests/test/integration/runtime-symbol-merging/.parcelrc +++ b/packages/core/integration-tests/test/integration/runtime-symbol-merging/.parcelrc @@ -1,8 +1,6 @@ { "extends": "@parcel/config-default", - "runtimes": { - "browser": [ - "parcel-runtime-mock" - ] - } + "runtimes": [ + "parcel-runtime-mock" + ] } diff --git a/packages/core/integration-tests/test/integration/runtime-update/.parcelrc b/packages/core/integration-tests/test/integration/runtime-update/.parcelrc index 44f2409a9d6..2faf969746e 100644 --- a/packages/core/integration-tests/test/integration/runtime-update/.parcelrc +++ b/packages/core/integration-tests/test/integration/runtime-update/.parcelrc @@ -1,8 +1,6 @@ { "extends": "@parcel/config-default", - "runtimes": { - "browser": [ - "parcel-runtime-mock", - ], - } + "runtimes": [ + "parcel-runtime-mock", + ] } diff --git a/packages/core/integration-tests/test/integration/scope-hoisting/es6/interop-async/index.html b/packages/core/integration-tests/test/integration/scope-hoisting/es6/interop-async/index.html index f9757275016..8ef9a70b216 100644 --- a/packages/core/integration-tests/test/integration/scope-hoisting/es6/interop-async/index.html +++ b/packages/core/integration-tests/test/integration/scope-hoisting/es6/interop-async/index.html @@ -1 +1 @@ - + diff --git a/packages/core/integration-tests/test/integration/scope-hoisting/es6/live-bindings-cross-bundle/a.html b/packages/core/integration-tests/test/integration/scope-hoisting/es6/live-bindings-cross-bundle/a.html index ed52c3deec6..ee620ca3160 100644 --- a/packages/core/integration-tests/test/integration/scope-hoisting/es6/live-bindings-cross-bundle/a.html +++ b/packages/core/integration-tests/test/integration/scope-hoisting/es6/live-bindings-cross-bundle/a.html @@ -1 +1 @@ - + diff --git a/packages/core/integration-tests/test/integration/scope-hoisting/es6/live-bindings-cross-bundle/b.html b/packages/core/integration-tests/test/integration/scope-hoisting/es6/live-bindings-cross-bundle/b.html index f5c7be245a2..e1c1a4b209c 100644 --- a/packages/core/integration-tests/test/integration/scope-hoisting/es6/live-bindings-cross-bundle/b.html +++ b/packages/core/integration-tests/test/integration/scope-hoisting/es6/live-bindings-cross-bundle/b.html @@ -1 +1 @@ - + diff --git a/packages/core/integration-tests/test/integration/scope-hoisting/es6/shared-bundle-reexport/index1.html b/packages/core/integration-tests/test/integration/scope-hoisting/es6/shared-bundle-reexport/index1.html index e4a8cdb478d..befa6f91239 100644 --- a/packages/core/integration-tests/test/integration/scope-hoisting/es6/shared-bundle-reexport/index1.html +++ b/packages/core/integration-tests/test/integration/scope-hoisting/es6/shared-bundle-reexport/index1.html @@ -1 +1 @@ - + diff --git a/packages/core/integration-tests/test/integration/scope-hoisting/es6/shared-bundle-reexport/index2.html b/packages/core/integration-tests/test/integration/scope-hoisting/es6/shared-bundle-reexport/index2.html index 4dadd38abaa..edbd81997e9 100644 --- a/packages/core/integration-tests/test/integration/scope-hoisting/es6/shared-bundle-reexport/index2.html +++ b/packages/core/integration-tests/test/integration/scope-hoisting/es6/shared-bundle-reexport/index2.html @@ -1 +1 @@ - + diff --git a/packages/core/integration-tests/test/integration/scope-hoisting/es6/shared-bundle-reexport/index3.html b/packages/core/integration-tests/test/integration/scope-hoisting/es6/shared-bundle-reexport/index3.html index 4f42e2ac316..a51fc0ab954 100644 --- a/packages/core/integration-tests/test/integration/scope-hoisting/es6/shared-bundle-reexport/index3.html +++ b/packages/core/integration-tests/test/integration/scope-hoisting/es6/shared-bundle-reexport/index3.html @@ -1 +1 @@ - + diff --git a/packages/core/integration-tests/test/integration/scope-hoisting/es6/side-effects-css/index.html b/packages/core/integration-tests/test/integration/scope-hoisting/es6/side-effects-css/index.html index 0053d2e2e7b..e244c5b18eb 100644 --- a/packages/core/integration-tests/test/integration/scope-hoisting/es6/side-effects-css/index.html +++ b/packages/core/integration-tests/test/integration/scope-hoisting/es6/side-effects-css/index.html @@ -1,2 +1,2 @@
- + diff --git a/packages/core/integration-tests/test/integration/scope-hoisting/es6/side-effects-no-new-bundle/index.html b/packages/core/integration-tests/test/integration/scope-hoisting/es6/side-effects-no-new-bundle/index.html index 0053d2e2e7b..e244c5b18eb 100644 --- a/packages/core/integration-tests/test/integration/scope-hoisting/es6/side-effects-no-new-bundle/index.html +++ b/packages/core/integration-tests/test/integration/scope-hoisting/es6/side-effects-no-new-bundle/index.html @@ -1,2 +1,2 @@
- + diff --git a/packages/core/integration-tests/test/integration/scope-hoisting/es6/update-used-symbols-dependency-add-namespace/index.html b/packages/core/integration-tests/test/integration/scope-hoisting/es6/update-used-symbols-dependency-add-namespace/index.html index 0053d2e2e7b..e244c5b18eb 100644 --- a/packages/core/integration-tests/test/integration/scope-hoisting/es6/update-used-symbols-dependency-add-namespace/index.html +++ b/packages/core/integration-tests/test/integration/scope-hoisting/es6/update-used-symbols-dependency-add-namespace/index.html @@ -1,2 +1,2 @@
- + diff --git a/packages/core/integration-tests/test/integration/service-worker/error.js b/packages/core/integration-tests/test/integration/service-worker/error.js new file mode 100644 index 00000000000..1c2367a89e1 --- /dev/null +++ b/packages/core/integration-tests/test/integration/service-worker/error.js @@ -0,0 +1 @@ +navigator.serviceWorker.register('module-worker.js'); diff --git a/packages/core/integration-tests/test/integration/service-worker/module-worker.js b/packages/core/integration-tests/test/integration/service-worker/module-worker.js new file mode 100644 index 00000000000..2263b5a27c2 --- /dev/null +++ b/packages/core/integration-tests/test/integration/service-worker/module-worker.js @@ -0,0 +1 @@ +export var foo = 2; diff --git a/packages/core/integration-tests/test/integration/service-worker/module.js b/packages/core/integration-tests/test/integration/service-worker/module.js new file mode 100644 index 00000000000..d9f4432c70a --- /dev/null +++ b/packages/core/integration-tests/test/integration/service-worker/module.js @@ -0,0 +1 @@ +navigator.serviceWorker.register('module-worker.js', {type: 'module'}); diff --git a/packages/core/integration-tests/test/integration/service-worker/scope.js b/packages/core/integration-tests/test/integration/service-worker/scope.js new file mode 100644 index 00000000000..a0508f2fa4d --- /dev/null +++ b/packages/core/integration-tests/test/integration/service-worker/scope.js @@ -0,0 +1 @@ +navigator.serviceWorker.register('module-worker.js', {scope: 'foo', type: 'module'}); diff --git a/packages/core/integration-tests/test/integration/shared-many/a.html b/packages/core/integration-tests/test/integration/shared-many/a.html index cb28dbc1313..6903d403236 100644 --- a/packages/core/integration-tests/test/integration/shared-many/a.html +++ b/packages/core/integration-tests/test/integration/shared-many/a.html @@ -1,2 +1,2 @@ - + diff --git a/packages/core/integration-tests/test/integration/shared-many/b.html b/packages/core/integration-tests/test/integration/shared-many/b.html index 44f7261b512..2bc0b3c2f66 100644 --- a/packages/core/integration-tests/test/integration/shared-many/b.html +++ b/packages/core/integration-tests/test/integration/shared-many/b.html @@ -1,2 +1,2 @@ - + diff --git a/packages/core/integration-tests/test/integration/shared-many/c.html b/packages/core/integration-tests/test/integration/shared-many/c.html index ef94f9e2e62..d2a95cd1392 100644 --- a/packages/core/integration-tests/test/integration/shared-many/c.html +++ b/packages/core/integration-tests/test/integration/shared-many/c.html @@ -1,2 +1,2 @@ - + diff --git a/packages/core/integration-tests/test/integration/shared-many/d.html b/packages/core/integration-tests/test/integration/shared-many/d.html index c4e8e75143f..b5cb0558627 100644 --- a/packages/core/integration-tests/test/integration/shared-many/d.html +++ b/packages/core/integration-tests/test/integration/shared-many/d.html @@ -1,2 +1,2 @@ - + diff --git a/packages/core/integration-tests/test/integration/shared-many/e.html b/packages/core/integration-tests/test/integration/shared-many/e.html index f1294f1c7ce..2792f4f3428 100644 --- a/packages/core/integration-tests/test/integration/shared-many/e.html +++ b/packages/core/integration-tests/test/integration/shared-many/e.html @@ -1,2 +1,2 @@ - + diff --git a/packages/core/integration-tests/test/integration/shared-many/f.html b/packages/core/integration-tests/test/integration/shared-many/f.html index 967f3cdc4a3..e7d8a3a8890 100644 --- a/packages/core/integration-tests/test/integration/shared-many/f.html +++ b/packages/core/integration-tests/test/integration/shared-many/f.html @@ -1,2 +1,2 @@ - + diff --git a/packages/core/integration-tests/test/integration/shared-many/g.html b/packages/core/integration-tests/test/integration/shared-many/g.html index bc01514e1d5..aacfc6ae995 100644 --- a/packages/core/integration-tests/test/integration/shared-many/g.html +++ b/packages/core/integration-tests/test/integration/shared-many/g.html @@ -1,2 +1,2 @@ - + diff --git a/packages/core/integration-tests/test/integration/shared-sibling-duplicate/a.html b/packages/core/integration-tests/test/integration/shared-sibling-duplicate/a.html index cb28dbc1313..6903d403236 100644 --- a/packages/core/integration-tests/test/integration/shared-sibling-duplicate/a.html +++ b/packages/core/integration-tests/test/integration/shared-sibling-duplicate/a.html @@ -1,2 +1,2 @@ - + diff --git a/packages/core/integration-tests/test/integration/shared-sibling-duplicate/b.html b/packages/core/integration-tests/test/integration/shared-sibling-duplicate/b.html index 44f7261b512..2bc0b3c2f66 100644 --- a/packages/core/integration-tests/test/integration/shared-sibling-duplicate/b.html +++ b/packages/core/integration-tests/test/integration/shared-sibling-duplicate/b.html @@ -1,2 +1,2 @@ - + diff --git a/packages/core/integration-tests/test/integration/shared-sibling-duplicate/c.html b/packages/core/integration-tests/test/integration/shared-sibling-duplicate/c.html index ef94f9e2e62..d2a95cd1392 100644 --- a/packages/core/integration-tests/test/integration/shared-sibling-duplicate/c.html +++ b/packages/core/integration-tests/test/integration/shared-sibling-duplicate/c.html @@ -1,2 +1,2 @@ - + diff --git a/packages/core/integration-tests/test/integration/shared-sibling-entries-multiple/a.html b/packages/core/integration-tests/test/integration/shared-sibling-entries-multiple/a.html index b7ba0a892bf..89f54f613d6 100644 --- a/packages/core/integration-tests/test/integration/shared-sibling-entries-multiple/a.html +++ b/packages/core/integration-tests/test/integration/shared-sibling-entries-multiple/a.html @@ -2,6 +2,6 @@

a.html

- + diff --git a/packages/core/integration-tests/test/integration/shared-sibling-entries-multiple/b.html b/packages/core/integration-tests/test/integration/shared-sibling-entries-multiple/b.html index e2a24e1af0b..ff2bfebf4ac 100644 --- a/packages/core/integration-tests/test/integration/shared-sibling-entries-multiple/b.html +++ b/packages/core/integration-tests/test/integration/shared-sibling-entries-multiple/b.html @@ -2,6 +2,6 @@

b.html

- + diff --git a/packages/core/integration-tests/test/integration/worker-circular/index.js b/packages/core/integration-tests/test/integration/worker-circular/index.js index c25bcacc792..356faefd8bd 100644 --- a/packages/core/integration-tests/test/integration/worker-circular/index.js +++ b/packages/core/integration-tests/test/integration/worker-circular/index.js @@ -1 +1 @@ -new Worker('worker.js'); +new Worker('worker.js', {type: 'module'}); diff --git a/packages/core/integration-tests/test/integration/worker-shared/index.js b/packages/core/integration-tests/test/integration/worker-shared/index.js index 2be98ad89c5..1033f7abd70 100644 --- a/packages/core/integration-tests/test/integration/worker-shared/index.js +++ b/packages/core/integration-tests/test/integration/worker-shared/index.js @@ -1,3 +1,3 @@ import _ from 'lodash'; -new Worker('worker-a.js'); +new Worker('worker-a.js', {type: 'module'}); diff --git a/packages/core/integration-tests/test/integration/worker-shared/worker-a.js b/packages/core/integration-tests/test/integration/worker-shared/worker-a.js index f1e1cc07cf1..905ce5bbd0a 100644 --- a/packages/core/integration-tests/test/integration/worker-shared/worker-a.js +++ b/packages/core/integration-tests/test/integration/worker-shared/worker-a.js @@ -1,4 +1,4 @@ import _ from 'lodash' console.log(_); -new Worker('worker-b.js') +new Worker('worker-b.js', {type: 'module'}) diff --git a/packages/core/integration-tests/test/integration/workers-module/dedicated-worker.js b/packages/core/integration-tests/test/integration/workers-module/dedicated-worker.js index 52946114304..0881af7c961 100644 --- a/packages/core/integration-tests/test/integration/workers-module/dedicated-worker.js +++ b/packages/core/integration-tests/test/integration/workers-module/dedicated-worker.js @@ -1,3 +1,4 @@ import foo from "foo"; console.log("DedicatedWorker", foo); +export {foo}; diff --git a/packages/core/integration-tests/test/integration/workers-module/error.js b/packages/core/integration-tests/test/integration/workers-module/error.js new file mode 100644 index 00000000000..4d606f86efd --- /dev/null +++ b/packages/core/integration-tests/test/integration/workers-module/error.js @@ -0,0 +1 @@ +new Worker("dedicated-worker.js"); diff --git a/packages/core/integration-tests/test/integration/workers-module/named.js b/packages/core/integration-tests/test/integration/workers-module/named.js new file mode 100644 index 00000000000..3dc9f858ef4 --- /dev/null +++ b/packages/core/integration-tests/test/integration/workers-module/named.js @@ -0,0 +1,2 @@ +new Worker("dedicated-worker.js", {name: 'worker', type: 'module'}); +new SharedWorker("shared-worker.js", {name: 'shared', type: 'module'}); diff --git a/packages/core/integration-tests/test/integration/workers-module/package.json b/packages/core/integration-tests/test/integration/workers-module/package.json deleted file mode 100644 index 33859c5e19d..00000000000 --- a/packages/core/integration-tests/test/integration/workers-module/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "targets": { - "default": { - "includeNodeModules": false - } - } -} diff --git a/packages/core/integration-tests/test/integration/workers-module/shared-worker.js b/packages/core/integration-tests/test/integration/workers-module/shared-worker.js index 91f7355fdd9..becc2ed02a9 100644 --- a/packages/core/integration-tests/test/integration/workers-module/shared-worker.js +++ b/packages/core/integration-tests/test/integration/workers-module/shared-worker.js @@ -1,3 +1,4 @@ import foo from "foo"; console.log("SharedWorker", foo); +export {foo}; diff --git a/packages/core/integration-tests/test/integration/workers/worker-client.js b/packages/core/integration-tests/test/integration/workers/worker-client.js index 4c37977e839..c7b3189ebf4 100644 --- a/packages/core/integration-tests/test/integration/workers/worker-client.js +++ b/packages/core/integration-tests/test/integration/workers/worker-client.js @@ -3,12 +3,12 @@ const commonText = require('./common').commonFunction('Index'); navigator.serviceWorker.register('service-worker.js', { scope: './' }); exports.startWorker = function() { - const worker = new Worker('worker.js', {name: 'myName'}); + const worker = new Worker('worker.js', {type: 'module', name: 'myName'}); worker.postMessage(commonText); }; exports.startSharedWorker = function() { - const worker = new SharedWorker('shared-worker.js'); + const worker = new SharedWorker('shared-worker.js', {type: 'module'}); }; diff --git a/packages/core/integration-tests/test/javascript.js b/packages/core/integration-tests/test/javascript.js index bab7c97f4f5..9938959cf3b 100644 --- a/packages/core/integration-tests/test/javascript.js +++ b/packages/core/integration-tests/test/javascript.js @@ -541,7 +541,7 @@ describe('javascript', function() { assertBundles(b, [ { - assets: ['dedicated-worker.js'], + assets: ['dedicated-worker.js', 'index.js'], }, { name: 'index.js', @@ -557,7 +557,7 @@ describe('javascript', function() { ], }, { - assets: ['shared-worker.js'], + assets: ['shared-worker.js', 'index.js'], }, ]); @@ -576,10 +576,155 @@ describe('javascript', function() { assert(dedicated); assert(shared); + let main = await outputFS.readFile(b.getBundles()[0].filePath, 'utf8'); dedicated = await outputFS.readFile(dedicated.filePath, 'utf8'); shared = await outputFS.readFile(shared.filePath, 'utf8'); - assert(/import .* from ?"foo";/.test(dedicated)); - assert(/import .* from ?"foo";/.test(shared)); + assert(/new Worker(.*?, {[\n\s]+type: 'module'[\n\s]+})/.test(main)); + assert(/new SharedWorker(.*?, {[\n\s]+type: 'module'[\n\s]+})/.test(main)); + assert(/export var foo/.test(dedicated)); + assert(/export var foo/.test(shared)); + }); + + for (let scopeHoist of [true, false]) { + it(`should compile workers to non modules if ${ + scopeHoist ? 'browsers do not support it' : 'scopeHoist = false' + }`, async function() { + let b = await bundle( + path.join(__dirname, '/integration/workers-module/index.js'), + { + scopeHoist, + defaultEngines: { + browsers: '>= 0.25%', + }, + }, + ); + + assertBundles(b, [ + { + assets: ['dedicated-worker.js', 'index.js'], + }, + { + name: 'index.js', + assets: [ + 'index.js', + 'bundle-url.js', + 'JSRuntime.js', + 'JSRuntime.js', + 'JSRuntime.js', + 'get-worker-url.js', + 'bundle-manifest.js', + 'relative-path.js', + ], + }, + { + assets: ['shared-worker.js', 'index.js'], + }, + ]); + + let dedicated, shared; + b.traverseBundles((bundle, ctx, traversal) => { + if (bundle.getMainEntry().filePath.endsWith('shared-worker.js')) { + shared = bundle; + } else if ( + bundle.getMainEntry().filePath.endsWith('dedicated-worker.js') + ) { + dedicated = bundle; + } + if (dedicated && shared) traversal.stop(); + }); + + assert(dedicated); + assert(shared); + + let main = await outputFS.readFile(b.getBundles()[0].filePath, 'utf8'); + dedicated = await outputFS.readFile(dedicated.filePath, 'utf8'); + shared = await outputFS.readFile(shared.filePath, 'utf8'); + assert(/new Worker([^,]*?)/.test(main)); + assert(/new SharedWorker([^,]*?)/.test(main)); + assert(!/export var foo/.test(dedicated)); + assert(!/export var foo/.test(shared)); + }); + } + + it('should preserve the name option to workers', async function() { + let b = await bundle( + path.join(__dirname, '/integration/workers-module/named.js'), + { + scopeHoist: true, + defaultEngines: { + browsers: '>= 0.25%', + }, + }, + ); + + let main = await outputFS.readFile(b.getBundles()[0].filePath, 'utf8'); + assert(/new Worker(.*?, {[\n\s]+name: 'worker'[\n\s]+})/.test(main)); + assert(/new SharedWorker(.*?, {[\n\s]+name: 'shared'[\n\s]+})/.test(main)); + }); + + it('should error if importing in a worker without type: module', async function() { + let errored = false; + try { + await bundle( + path.join(__dirname, '/integration/workers-module/error.js'), + {scopeHoist: true}, + ); + } catch (err) { + errored = true; + assert.equal( + err.message, + 'Web workers cannot have imports or exports. Use the `type: "module"` option instead.', + ); + assert.deepEqual(err.diagnostics, [ + { + message: + 'Web workers cannot have imports or exports. Use the `type: "module"` option instead.', + filePath: path.join( + __dirname, + '/integration/workers-module/dedicated-worker.js', + ), + origin: '@parcel/transformer-js', + codeFrame: { + codeHighlights: [ + { + start: { + line: 1, + column: 1, + }, + end: { + line: 1, + column: 22, + }, + }, + ], + }, + }, + { + message: 'The environment was originally created here:', + filePath: path.join( + __dirname, + '/integration/workers-module/error.js', + ), + origin: '@parcel/transformer-js', + codeFrame: { + codeHighlights: [ + { + start: { + line: 1, + column: 1, + }, + end: { + line: 1, + column: 33, + }, + }, + ], + }, + }, + ]); + } + + assert(errored); }); it('should support bundling workers with different order', async function() { @@ -756,6 +901,136 @@ describe('javascript', function() { ]); }); + it('should support bundling service-workers with type: module', async function() { + let b = await bundle( + path.join(__dirname, '/integration/service-worker/module.js'), + {scopeHoist: true}, + ); + + assertBundles(b, [ + { + name: 'module.js', + assets: [ + 'module.js', + 'bundle-url.js', + 'JSRuntime.js', + 'JSRuntime.js', + 'bundle-manifest.js', + 'relative-path.js', + ], + }, + { + assets: ['module-worker.js'], + }, + ]); + + let bundles = b.getBundles(); + let main = bundles.find(b => !b.env.isWorker()); + let worker = bundles.find(b => b.env.isWorker()); + let mainContents = await outputFS.readFile(main.filePath, 'utf8'); + let workerContents = await outputFS.readFile(worker.filePath, 'utf8'); + assert(/navigator.serviceWorker.register\([^,]+?\)/.test(mainContents)); + assert(!/export/.test(workerContents)); + }); + + it('should preserve the scope option for service workers', async function() { + let b = await bundle( + path.join(__dirname, '/integration/service-worker/scope.js'), + {scopeHoist: true}, + ); + + assertBundles(b, [ + { + name: 'scope.js', + assets: [ + 'scope.js', + 'bundle-url.js', + 'JSRuntime.js', + 'JSRuntime.js', + 'bundle-manifest.js', + 'relative-path.js', + ], + }, + { + assets: ['module-worker.js'], + }, + ]); + + let bundles = b.getBundles(); + let main = bundles.find(b => !b.env.isWorker()); + let mainContents = await outputFS.readFile(main.filePath, 'utf8'); + assert( + /navigator.serviceWorker.register\(.*?, {[\n\s]*scope: 'foo'[\n\s]*}\)/.test( + mainContents, + ), + ); + }); + + it('should error if importing in a service worker without type: module', async function() { + let errored = false; + try { + await bundle( + path.join(__dirname, '/integration/service-worker/error.js'), + {scopeHoist: true}, + ); + } catch (err) { + errored = true; + assert.equal( + err.message, + 'Service workers cannot have imports or exports. Use the `type: "module"` option instead.', + ); + assert.deepEqual(err.diagnostics, [ + { + message: + 'Service workers cannot have imports or exports. Use the `type: "module"` option instead.', + filePath: path.join( + __dirname, + '/integration/service-worker/module-worker.js', + ), + origin: '@parcel/transformer-js', + codeFrame: { + codeHighlights: [ + { + start: { + line: 1, + column: 1, + }, + end: { + line: 1, + column: 19, + }, + }, + ], + }, + }, + { + message: 'The environment was originally created here:', + filePath: path.join( + __dirname, + '/integration/service-worker/error.js', + ), + origin: '@parcel/transformer-js', + codeFrame: { + codeHighlights: [ + { + start: { + line: 1, + column: 1, + }, + end: { + line: 1, + column: 52, + }, + }, + ], + }, + }, + ]); + } + + assert(errored); + }); + it('should support bundling workers with circular dependencies', async function() { let b = await bundle( path.join(__dirname, '/integration/worker-circular/index.js'), diff --git a/packages/core/integration-tests/test/output-formats.js b/packages/core/integration-tests/test/output-formats.js index 096540616af..747b1b5a72a 100644 --- a/packages/core/integration-tests/test/output-formats.js +++ b/packages/core/integration-tests/test/output-formats.js @@ -832,7 +832,7 @@ describe('output formats', function() { ); let workerBundle = nullthrows( - b.getBundles().find(b => b.env.context === 'web-worker'), + b.getBundles().find(b => b.env.context.has('web-worker')), ); let workerBundleContents = await outputFS.readFile( workerBundle.filePath, diff --git a/packages/core/integration-tests/test/scope-hoisting.js b/packages/core/integration-tests/test/scope-hoisting.js index f6f6420c075..2dedbfe9a30 100644 --- a/packages/core/integration-tests/test/scope-hoisting.js +++ b/packages/core/integration-tests/test/scope-hoisting.js @@ -502,6 +502,11 @@ describe('scope hoisting', function() { f, ), ), + { + defaultEngines: { + browsers: '>= 0.25%', + }, + }, ); let output = await runBundle( @@ -824,6 +829,11 @@ describe('scope hoisting', function() { __dirname, '/integration/scope-hoisting/es6/shared-bundle-reexport/*.html', ), + { + defaultEngines: { + browsers: '>= 0.25%', + }, + }, ); assertBundles(b, [ @@ -835,6 +845,10 @@ describe('scope hoisting', function() { type: 'js', assets: ['index1.js'], }, + { + type: 'js', + assets: ['index1.js'], + }, { type: 'html', assets: ['index2.html'], @@ -843,6 +857,10 @@ describe('scope hoisting', function() { type: 'js', assets: ['index2.js'], }, + { + type: 'js', + assets: ['index2.js'], + }, { type: 'html', assets: ['index3.html'], @@ -851,10 +869,22 @@ describe('scope hoisting', function() { type: 'js', assets: ['index3.js'], }, + { + type: 'js', + assets: ['index3.js'], + }, { type: 'js', assets: ['a.js'], }, + { + type: 'js', + assets: ['a.js'], + }, + { + type: 'js', + assets: ['b.js'], + }, { type: 'js', assets: ['b.js'], @@ -1681,6 +1711,11 @@ describe('scope hoisting', function() { __dirname, '/integration/scope-hoisting/es6/interop-async/index.html', ), + { + defaultEngines: { + browsers: '>= 0.25%', + }, + }, ); let output = await run(b); @@ -2033,6 +2068,9 @@ describe('scope hoisting', function() { let b = bundler(path.join(testDir, 'index.html'), { inputFS: overlayFS, outputFS: overlayFS, + defaultEngines: { + browsers: '>= 0.25%', + }, }); await overlayFS.mkdirp(testDir); @@ -2148,6 +2186,11 @@ describe('scope hoisting', function() { __dirname, '/integration/scope-hoisting/es6/side-effects-css/index.html', ), + { + defaultEngines: { + browsers: '>= 0.25%', + }, + }, ); assertBundles(b, [ @@ -2159,6 +2202,10 @@ describe('scope hoisting', function() { type: 'js', assets: ['index.js', 'a.js', 'b1.js'], }, + { + type: 'js', + assets: ['index.js', 'a.js', 'b1.js'], + }, { type: 'css', assets: ['b1.css'], @@ -2187,6 +2234,7 @@ describe('scope hoisting', function() { __dirname, '/integration/scope-hoisting/es6/side-effects-no-new-bundle/index.html', ), + {defaultEngines: {browsers: '>= 0.25%'}}, ); assertBundles(b, [ @@ -2198,6 +2246,10 @@ describe('scope hoisting', function() { type: 'js', assets: ['index.js', 'a.js', 'b1.js'], }, + { + type: 'js', + assets: ['index.js', 'a.js', 'b1.js'], + }, ]); let calls = []; @@ -4133,6 +4185,11 @@ describe('scope hoisting', function() { it('should not throw with JS included from HTML', async function() { let b = await bundle( path.join(__dirname, '/integration/html-js/index.html'), + { + defaultEngines: { + browsers: '>= 0.25%', + }, + }, ); assertBundles(b, [ @@ -4144,6 +4201,10 @@ describe('scope hoisting', function() { type: 'js', assets: ['index.js', 'other.js'], }, + { + type: 'js', + assets: ['index.js', 'other.js'], + }, ]); let asset = nullthrows(findAsset(b, 'other.js')); @@ -4162,6 +4223,11 @@ describe('scope hoisting', function() { it('should not throw with JS dynamic imports included from HTML', async function() { let b = await bundle( path.join(__dirname, '/integration/html-js-dynamic/index.html'), + { + defaultEngines: { + browsers: '>= 0.25%', + }, + }, ); assertBundles(b, [ @@ -4182,6 +4248,20 @@ describe('scope hoisting', function() { 'relative-path.js', ], }, + { + type: 'js', + assets: [ + 'bundle-url.js', + 'cacheLoader.js', + 'import-polyfill.js', + 'index.js', + 'JSRuntime.js', + ], + }, + { + type: 'js', + assets: ['local.js'], + }, { type: 'js', assets: ['local.js'], @@ -4196,6 +4276,11 @@ describe('scope hoisting', function() { it('should include the prelude in shared entry bundles', async function() { let b = await bundle( path.join(__dirname, '/integration/html-shared/index.html'), + { + defaultEngines: { + browsers: '>= 0.25%', + }, + }, ); assertBundles(b, [ @@ -4207,6 +4292,10 @@ describe('scope hoisting', function() { type: 'js', assets: ['index.js'], }, + { + type: 'js', + assets: ['index.js'], + }, { name: 'iframe.html', assets: ['iframe.html'], @@ -4215,6 +4304,14 @@ describe('scope hoisting', function() { type: 'js', assets: ['iframe.js'], }, + { + type: 'js', + assets: ['iframe.js'], + }, + { + type: 'js', + assets: ['lodash.js'], + }, { type: 'js', assets: ['lodash.js'], @@ -4241,6 +4338,11 @@ describe('scope hoisting', function() { it('should include prelude in shared worker bundles', async function() { let b = await bundle( path.join(__dirname, '/integration/worker-shared/index.js'), + { + defaultEngines: { + browsers: '>= 0.25%', + }, + }, ); let sharedBundle = b diff --git a/packages/core/test-utils/package.json b/packages/core/test-utils/package.json index cafdc5ce5e4..f23cae11ecd 100644 --- a/packages/core/test-utils/package.json +++ b/packages/core/test-utils/package.json @@ -13,6 +13,8 @@ "node": ">= 10.0.0" }, "dependencies": { + "@babel/core": "^7.12.0", + "@babel/plugin-transform-modules-commonjs": "^7.0.0", "@parcel/config-default": "2.0.0-beta.1", "@parcel/core": "2.0.0-beta.1", "@parcel/fs": "2.0.0-beta.1", diff --git a/packages/core/test-utils/src/utils.js b/packages/core/test-utils/src/utils.js index bc8ee28e03b..5b60d12aee2 100644 --- a/packages/core/test-utils/src/utils.js +++ b/packages/core/test-utils/src/utils.js @@ -29,6 +29,7 @@ import {makeDeferredWithPromise, normalizeSeparators} from '@parcel/utils'; import _chalk from 'chalk'; import resolve from 'resolve'; import {NodePackageManager} from '@parcel/package-manager'; +import {transformSync} from '@babel/core'; export const workerFarm = (createWorkerFarm(): WorkerFarm); export const inputFS: NodeFS = new NodeFS(); @@ -207,46 +208,82 @@ type RunOpts = {require?: boolean, ...}; export async function runBundles( bundleGraph: BundleGraph, parent: NamedBundle, - bundles: Array, + bundles: Array<[string, NamedBundle]>, globals: mixed, opts: RunOpts = {}, ): Promise { let entryAsset = nullthrows( bundles - .map(b => b.getMainEntry() || b.getEntryAssets()[0]) + .map(([, b]) => b.getMainEntry() || b.getEntryAssets()[0]) .filter(Boolean)[0], ); let env = entryAsset.env; - let target = entryAsset.env.context; let ctx, promises; - switch (target) { - case 'browser': { - let prepared = prepareBrowserContext(parent.filePath, globals); - ctx = prepared.ctx; - promises = prepared.promises; - break; - } - case 'node': - case 'electron-main': - ctx = prepareNodeContext(parent.filePath, globals); - break; - case 'electron-renderer': { - let browser = prepareBrowserContext(parent.filePath, globals); - ctx = { - ...browser.ctx, - ...prepareNodeContext(parent.filePath, globals), - }; - promises = browser.promises; - break; + if (entryAsset.env.isBrowser()) { + let prepared = prepareBrowserContext(parent.filePath, globals); + ctx = prepared.ctx; + promises = prepared.promises; + } + + if (entryAsset.env.isNode()) { + let prepared = prepareNodeContext(parent.filePath, globals); + if (ctx) { + Object.assign(ctx, prepared); + } else { + ctx = prepared; } - default: - throw new Error('Unknown target ' + target); } + if (!ctx) { + throw new Error( + 'Unknown context ' + [...entryAsset.env.context].join(', '), + ); + } + + let prepareCode = (code, b) => { + if (b.env.outputFormat === 'esmodule' || /\simport\(/.test(code)) { + return transformSync(code, { + babelrc: false, + configFile: false, + plugins: [ + b.env.outputFormat === 'esmodule' + ? require('@babel/plugin-transform-modules-commonjs') + : null, + ({types: t}) => ({ + visitor: { + Import(path) { + path.replaceWith(t.identifier('__import')); + }, + }, + }), + ].filter(Boolean), + }).code; + } + return code; + }; + + // $FlowFixMe + ctx.__import = specifier => { + let promise = Promise.resolve().then(() => { + let filePath = path.join(path.dirname(parent.filePath), specifier); + let b = nullthrows( + bundleGraph.getBundles().find(b => b.filePath === filePath), + ); + return runBundle(bundleGraph, b, globals, opts); + }); + + if (promises) { + promises.push(promise); + } + + return promise; + }; + vm.createContext(ctx); - for (let b of bundles) { - new vm.Script(await overlayFS.readFile(nullthrows(b.filePath), 'utf8'), { + for (let [code, b] of bundles) { + code = await prepareCode(code, b); + new vm.Script(code, { filename: b.name, }).runInContext(ctx); } @@ -295,27 +332,38 @@ export async function runBundle( lowerCaseAttributeNames: true, }); + let bundles = bundleGraph.getBundles(); let scripts = []; postHtml().walk.call(ast, node => { - if (node.tag === 'script') { + if ( + node.tag === 'script' && + node.attrs && + node.attrs.src && + node.attrs.type !== 'module' + ) { let src = url.parse(nullthrows(node.attrs).src); if (src.hostname == null) { - scripts.push(path.join(distDir, nullthrows(src.pathname))); + let p = path.join(distDir, nullthrows(src.pathname)); + let b = nullthrows(bundles.find(b => b.filePath === p)); + scripts.push([overlayFS.readFileSync(b.filePath, 'utf8'), b]); } + } else if (node.tag === 'script' && node.content && !node.attrs?.src) { + let content = node.content.join(''); + let inline = bundles.filter(b => b.isInline && b.type === 'js'); + scripts.push([content, inline[0]]); // TODO: match by content?? } return node; }); - let bundles = bundleGraph.getBundles(); + return runBundles(bundleGraph, bundle, scripts, globals, opts); + } else { return runBundles( bundleGraph, bundle, - scripts.map(p => nullthrows(bundles.find(b => b.filePath === p))), + [[overlayFS.readFileSync(bundle.filePath, 'utf8'), bundle]], globals, opts, ); - } else { - return runBundles(bundleGraph, bundle, [bundle], globals, opts); } } diff --git a/packages/core/types/index.js b/packages/core/types/index.js index 12c3b30c513..a63a543089c 100644 --- a/packages/core/types/index.js +++ b/packages/core/types/index.js @@ -57,7 +57,7 @@ export type RawParcelConfig = {| transformers?: {[Glob]: RawParcelConfigPipeline, ...}, bundler?: PackageName, namers?: RawParcelConfigPipeline, - runtimes?: {[EnvironmentContext]: RawParcelConfigPipeline, ...}, + runtimes?: RawParcelConfigPipeline, packagers?: {[Glob]: PackageName, ...}, optimizers?: {[Glob]: RawParcelConfigPipeline, ...}, reporters?: RawParcelConfigPipeline, @@ -109,7 +109,9 @@ export type EnvironmentContext = | 'service-worker' | 'node' | 'electron-main' - | 'electron-renderer'; + | 'electron-renderer' + | 'script' + | 'module'; /** The JS module format for the bundle output */ export type OutputFormat = 'esmodule' | 'commonjs' | 'global'; @@ -120,7 +122,7 @@ export type OutputFormat = 'esmodule' | 'commonjs' | 'global'; * See Environment and Target. */ export type PackageTargetDescriptor = {| - +context?: EnvironmentContext, + +context?: EnvironmentContext | Array, +engines?: Engines, +includeNodeModules?: | boolean @@ -149,7 +151,7 @@ export type TargetDescriptor = {| * This is used when creating an Environment (see that). */ export type EnvironmentOpts = {| - +context?: EnvironmentContext, + +context?: EnvironmentContext | Iterable, +engines?: Engines, +includeNodeModules?: | boolean @@ -159,7 +161,8 @@ export type EnvironmentOpts = {| +isLibrary?: boolean, +minify?: boolean, +scopeHoist?: boolean, - +sourceMap?: ?TargetSourceMapOptions + +sourceMap?: ?TargetSourceMapOptions, + +loc?: ?SourceLocation |}; /** @@ -179,11 +182,17 @@ export type VersionMap = { ..., }; +export type EnvironmentFeature = + | 'esmodules' + | 'dynamic-import' + | 'worker-type' + | 'service-worker-type'; + /** * Defines the environment in for the output bundle */ export interface Environment { - +context: EnvironmentContext; + +context: Set; +engines: Engines; /** Whether to include all/none packages \ * (true / false), an array of package names to include, or an object \ @@ -201,6 +210,7 @@ export interface Environment { /** Whether scope hoisting is enabled. */ +scopeHoist: boolean; +sourceMap: ?TargetSourceMapOptions; + +loc: ?SourceLocation; /** Whether context specifies a browser context. */ isBrowser(): boolean; @@ -213,6 +223,7 @@ export interface Environment { /** Whether context specifies an isolated context (can't access other loaded ancestor bundles). */ isIsolated(): boolean; matchesEngines(minVersions: VersionMap): boolean; + supports(feature: EnvironmentFeature): boolean; } /** @@ -1129,6 +1140,7 @@ export type RuntimeAsset = {| +code: string, +dependency?: Dependency, +isEntry?: boolean, + +env?: EnvironmentOpts, |}; /** diff --git a/packages/core/utils/src/index.js b/packages/core/utils/src/index.js index 45806d41774..81e7c10fb95 100644 --- a/packages/core/utils/src/index.js +++ b/packages/core/utils/src/index.js @@ -76,3 +76,4 @@ export { loadSourceMapUrl, loadSourceMap, } from './sourcemap'; +export {setIntersects, isSetEqual, isSubset} from './set'; diff --git a/packages/core/utils/src/set.js b/packages/core/utils/src/set.js new file mode 100644 index 00000000000..081d1f5d6f1 --- /dev/null +++ b/packages/core/utils/src/set.js @@ -0,0 +1,50 @@ +// @flow + +export function setIntersects(a: Set, b: Set): boolean { + for (let item of a) { + if (b.has(item)) { + return true; + } + } + + return false; +} + +export function isSetEqual(a: Set, b: Set): boolean { + if (a.size !== b.size) { + return false; + } + + for (let item of a) { + if (!b.has(item)) { + return false; + } + } + + return true; +} + +/** + * Returns true if either set is a subset of the other. + */ +export function isSubset(a: Set, b: Set): boolean { + let res = true; + for (let item of b) { + if (!a.has(item)) { + res = false; + break; + } + } + + if (!res) { + res = true; + for (let item of a) { + if (!b.has(item)) { + res = false; + break; + } + } + } + + return res; +} diff --git a/packages/packagers/js/src/JSPackager.js b/packages/packagers/js/src/JSPackager.js index 476f5ffcfdf..4b6344e9a98 100644 --- a/packages/packagers/js/src/JSPackager.js +++ b/packages/packagers/js/src/JSPackager.js @@ -49,6 +49,21 @@ export default (new Packager({ config, options, }) { + // If this is a non-module script, and there is only one asset with no dependencies, + // then we don't need to package at all and can pass through the original code un-wrapped. + if (bundle.env.context.has('script')) { + let entries = bundle.getEntryAssets(); + if ( + entries.length === 1 && + bundleGraph.getDependencies(entries[0]).length === 0 + ) { + return { + contents: await entries[0].getCode(), + map: await entries[0].getMap(), + }; + } + } + function replaceReferences({contents, map}) { return replaceInlineReferences({ bundle, @@ -254,9 +269,35 @@ function getPrefix( } } + let globalVars = ''; + let topLevelVars = mainEntry?.meta.topLevelVars; + if ( + topLevelVars != null && + typeof topLevelVars === 'object' && + !Array.isArray(topLevelVars) + ) { + let vars = {}; + for (let key in topLevelVars) { + let type = topLevelVars[key]; + invariant(typeof type === 'string'); + if (vars[type]) { + vars[type] += `, ${key}`; + } else { + vars[type] = `${type} ${key}`; + } + } + + for (let type in vars) { + globalVars += `${vars[type]};\n`; + } + } + return ( // If the entry asset included a hashbang, repeat it at the top of the bundle - (interpreter != null ? `#!${interpreter}\n` : '') + importScripts + PRELUDE + (interpreter != null ? `#!${interpreter}\n` : '') + + globalVars + + importScripts + + PRELUDE ); } diff --git a/packages/runtimes/js/src/JSRuntime.js b/packages/runtimes/js/src/JSRuntime.js index c2388016b19..f1ef2f8073a 100644 --- a/packages/runtimes/js/src/JSRuntime.js +++ b/packages/runtimes/js/src/JSRuntime.js @@ -10,20 +10,10 @@ import type { } from '@parcel/types'; import {Runtime} from '@parcel/plugin'; -import {flatMap, relativeBundlePath} from '@parcel/utils'; +import {flatMap, relativeBundlePath, isSubset} from '@parcel/utils'; import path from 'path'; import nullthrows from 'nullthrows'; -// List of browsers that support dynamic import natively -// https://caniuse.com/#feat=es6-module-dynamic-import -const DYNAMIC_IMPORT_BROWSERS = { - edge: '76', - firefox: '67', - chrome: '63', - safari: '11.1', - opera: '50', -}; - // Used for as="" in preload/prefetch const TYPE_TO_RESOURCE_PRIORITY = { css: 'style', @@ -110,6 +100,7 @@ export default (new Runtime({ './' + path.relative(options.projectRoot, resolved.value.filePath), )}))`, dependency, + env: createEnvironment(dependency.env), }); } else { let loaderRuntime = getLoaderRuntime({ @@ -137,6 +128,7 @@ export default (new Runtime({ filePath: path.join(__dirname, `/bundles/${referencedBundle.id}.js`), code: `module.exports = ${JSON.stringify(dependency.id)};`, dependency, + env: createEnvironment(dependency.env), }); continue; } @@ -153,6 +145,7 @@ export default (new Runtime({ dependency.moduleSpecifier, )}`, dependency, + env: createEnvironment(dependency.env), }); continue; } @@ -177,6 +170,7 @@ export default (new Runtime({ bundle, mainBundle, )})`, + env: createEnvironment(dependency.env), }); continue; } @@ -194,6 +188,7 @@ export default (new Runtime({ filePath: __filename, code: getRegisterCode(bundle, bundleGraph), isEntry: true, + env: createEnvironment(bundle.env), }); } @@ -239,12 +234,7 @@ function getLoaderRuntime({ } // Determine if we need to add a dynamic import() polyfill, or if all target browsers support it natively. - let needsDynamicImportPolyfill = false; - if (bundle.env.isBrowser() && bundle.env.outputFormat === 'esmodule') { - needsDynamicImportPolyfill = !bundle.env.matchesEngines( - DYNAMIC_IMPORT_BROWSERS, - ); - } + let needsDynamicImportPolyfill = !bundle.env.supports('dynamic-import'); let loaderModules = externalBundles .map(to => { @@ -263,7 +253,9 @@ function getLoaderRuntime({ loader = nullthrows( loaders.IMPORT_POLYFILL, - `No import() polyfill available for context '${bundle.env.context}'`, + `No import() polyfill available for context '${[ + ...bundle.env.context, + ].join(', ')}'`, ); } else if (to.type === 'js' && to.env.outputFormat === 'commonjs') { return `Promise.resolve(require("./" + ${relativePathExpr}))`; @@ -275,7 +267,7 @@ function getLoaderRuntime({ }) .filter(Boolean); - if (bundle.env.context === 'browser') { + if (bundle.env.isBrowser() && !bundle.env.isWorker()) { loaderModules.push( ...flatMap( // TODO: Allow css to preload resources as well @@ -307,20 +299,22 @@ function getLoaderRuntime({ } let loaderCode = loaderModules.join(', '); + let targetFormat = + externalBundles[externalBundles.length - 1].env.outputFormat; if ( loaderModules.length > 1 && - (bundle.env.outputFormat === 'global' || + (externalBundles.some(b => b.env.outputFormat === 'global') || !externalBundles.every(b => b.type === 'js')) ) { loaderCode = `Promise.all([${loaderCode}])`; - if (bundle.env.outputFormat !== 'global') { + if (targetFormat !== 'global') { loaderCode += `.then(r => r[r.length - 1])`; } } else { loaderCode = `(${loaderCode})`; } - if (bundle.env.outputFormat === 'global') { + if (targetFormat === 'global') { loaderCode += `.then(() => module.bundle.root('${bundleGraph.getAssetPublicId( bundleGraph.getAssetById(bundleGroup.entryAssetId), )}')${ @@ -334,6 +328,7 @@ function getLoaderRuntime({ filePath: __filename, code: `module.exports = ${loaderCode};`, dependency, + env: createEnvironment(dependency.env), }; } @@ -414,7 +409,8 @@ function isNewContext( parents.length === 0 || parents.some( parent => - parent.env.context !== bundle.env.context || parent.type !== 'js', + !isSubset(parent.env.context, bundle.env.context) || + parent.type !== 'js', ) ); } @@ -430,6 +426,7 @@ function getURLRuntime( filePath: __filename, code: `module.exports = require('./get-worker-url')(${relativePathExpr});`, dependency, + env: createEnvironment(dependency.env), }; } @@ -437,6 +434,17 @@ function getURLRuntime( filePath: __filename, code: `module.exports = require('./bundle-url').getBundleURL() + ${relativePathExpr}`, dependency, + env: createEnvironment(dependency.env), + }; +} + +function createEnvironment(env: Environment) { + // Ensure that the context does not contain "script" or dependencies won't be allowed. + let context = new Set(env.context); + context.delete('script'); + context.add('module'); + return { + context, }; } @@ -477,5 +485,10 @@ function getRelativePathExpr(from: NamedBundle, to: NamedBundle): string { function shouldUseRuntimeManifest(bundle: NamedBundle): boolean { let env = bundle.env; - return !env.isLibrary && env.outputFormat === 'global' && env.isBrowser(); + return ( + !env.isLibrary && + env.outputFormat === 'global' && + env.isBrowser() && + !bundle.isInline + ); } diff --git a/packages/shared/babel-ast-utils/src/index.js b/packages/shared/babel-ast-utils/src/index.js index 36795bf7d18..dd1a310fdf0 100644 --- a/packages/shared/babel-ast-utils/src/index.js +++ b/packages/shared/babel-ast-utils/src/index.js @@ -36,6 +36,8 @@ export async function parse({ strictMode: false, sourceType: 'module', plugins: ['exportDefaultFrom', 'exportNamespaceFrom', 'dynamicImport'], + // $FlowFixMe + startLine: asset.meta.loc?.start.line, }), }; } catch (e) { diff --git a/packages/shared/scope-hoisting/src/generate.js b/packages/shared/scope-hoisting/src/generate.js index b3f65b623b0..7fd9c2f75cf 100644 --- a/packages/shared/scope-hoisting/src/generate.js +++ b/packages/shared/scope-hoisting/src/generate.js @@ -90,6 +90,27 @@ export function generate({ : [WRAPPER_TEMPLATE({STATEMENTS: statements})]; } + let topLevelVars = mainEntry?.meta.topLevelVars; + if ( + topLevelVars && + typeof topLevelVars === 'object' && + !Array.isArray(topLevelVars) + ) { + let vars = {}; + for (let key in topLevelVars) { + let type = topLevelVars[key]; + invariant(typeof type === 'string'); + let decl = t.variableDeclarator(t.identifier(key)); + if (vars[type]) { + vars[type].declarations.push(decl); + } else { + // $FlowFixMe + vars[type] = t.variableDeclaration(type, [decl]); + statements.unshift(vars[type]); + } + } + } + ast = t.file( t.program( statements, diff --git a/packages/shared/scope-hoisting/src/utils.js b/packages/shared/scope-hoisting/src/utils.js index e01f6f5ead6..9cbe631de8d 100644 --- a/packages/shared/scope-hoisting/src/utils.js +++ b/packages/shared/scope-hoisting/src/utils.js @@ -25,6 +25,7 @@ import {isVariableDeclarator, isVariableDeclaration} from '@babel/types'; import invariant from 'assert'; import nullthrows from 'nullthrows'; import path from 'path'; +import {isSubset} from '@parcel/utils'; export function getName( asset: Asset | MutableAsset, @@ -125,7 +126,7 @@ export function hasAsyncDescendant( return; } - if (b.env.context !== bundle.env.context || b.type !== 'js') { + if (!isSubset(b.env.context, bundle.env.context) || b.type !== 'js') { actions.skipChildren(); return; } diff --git a/packages/transformers/babel/src/babel7.js b/packages/transformers/babel/src/babel7.js index dfa0c2298f1..1f9019b5cd8 100644 --- a/packages/transformers/babel/src/babel7.js +++ b/packages/transformers/babel/src/babel7.js @@ -42,6 +42,8 @@ export default async function babel7( strictMode: false, sourceType: 'module', plugins: ['dynamicImport'], + // $FlowFixMe + startLine: asset.meta.loc?.start.line, }, caller: { name: 'parcel', diff --git a/packages/transformers/html/package.json b/packages/transformers/html/package.json index 3dcf18d3bbc..89339fc2cdf 100644 --- a/packages/transformers/html/package.json +++ b/packages/transformers/html/package.json @@ -21,10 +21,10 @@ }, "dependencies": { "@parcel/plugin": "2.0.0-beta.1", + "@parcel/posthtml-parser": "^0.6.0", "@parcel/utils": "2.0.0-beta.1", "nullthrows": "^1.1.1", "posthtml": "^0.11.3", - "posthtml-parser": "^0.4.1", "posthtml-render": "^1.1.5", "semver": "^5.4.1" } diff --git a/packages/transformers/html/src/HTMLTransformer.js b/packages/transformers/html/src/HTMLTransformer.js index 13d3d9dbe43..98c634f9643 100644 --- a/packages/transformers/html/src/HTMLTransformer.js +++ b/packages/transformers/html/src/HTMLTransformer.js @@ -1,7 +1,7 @@ // @flow import {Transformer} from '@parcel/plugin'; -import parse from 'posthtml-parser'; +import parse from '@parcel/posthtml-parser'; import nullthrows from 'nullthrows'; import render from 'posthtml-render'; import semver from 'semver'; diff --git a/packages/transformers/html/src/dependencies.js b/packages/transformers/html/src/dependencies.js index ed69312d62f..17e883f0a30 100644 --- a/packages/transformers/html/src/dependencies.js +++ b/packages/transformers/html/src/dependencies.js @@ -1,6 +1,7 @@ // @flow -import type {AST, Environment, MutableAsset} from '@parcel/types'; +import type {AST, MutableAsset} from '@parcel/types'; +import type {PostHTMLNode} from 'posthtml'; import PostHTML from 'posthtml'; // A list of all attributes that may produce a dependency @@ -81,18 +82,6 @@ const OPTIONS = { }; } }, - script(attrs, env: Environment) { - return { - // Keep in the same bundle group as the HTML. - isAsync: false, - isEntry: false, - isIsolated: true, - env: { - outputFormat: - attrs.type === 'module' && env.scopeHoist ? 'esmodule' : undefined, - }, - }; - }, }; function collectSrcSetDependencies(asset, srcset, opts) { @@ -120,12 +109,15 @@ function getAttrDepHandler(attr) { export default function collectDependencies(asset: MutableAsset, ast: AST) { let isDirty = false; + let seen = new Set(); PostHTML().walk.call(ast.program, node => { let {tag, attrs} = node; - if (!attrs) { + if (!attrs || seen.has(node)) { return node; } + seen.add(node); + if (tag === 'meta') { if ( !Object.keys(attrs).some(attr => { @@ -154,6 +146,70 @@ export default function collectDependencies(asset: MutableAsset, ast: AST) { return node; } + if (tag === 'script' && attrs.src) { + let context = new Set(asset.env.context); + context.delete('module'); + context.delete('script'); + context.add(attrs.type === 'module' ? 'module' : 'script'); + + let loc = node.loc + ? { + filePath: asset.filePath, + start: node.loc.start, + end: node.loc.end, + } + : undefined; + + let outputFormat = 'global'; + if (attrs.type === 'module' && asset.env.scopeHoist) { + outputFormat = 'esmodule'; + } else { + delete attrs.type; + } + + // If this is a