From 8a14966611c4b6a39ba78e54725658b5aeb8120e Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Thu, 10 Jun 2021 20:59:40 -0700 Subject: [PATCH 1/2] API audit: Refactor dependency options (#6420) --- .../bundlers/default/src/DefaultBundler.js | 34 +++-- packages/core/core/src/AssetGraph.js | 10 +- packages/core/core/src/BundleGraph.js | 10 +- packages/core/core/src/CommittedAsset.js | 24 +-- packages/core/core/src/Dependency.js | 21 +-- packages/core/core/src/PackagerRunner.js | 6 +- packages/core/core/src/Transformation.js | 13 +- packages/core/core/src/UncommittedAsset.js | 28 +--- packages/core/core/src/applyRuntimes.js | 4 +- packages/core/core/src/assetUtils.js | 39 +---- packages/core/core/src/dumpGraphToGraphViz.js | 10 +- packages/core/core/src/public/Asset.js | 22 +-- packages/core/core/src/public/Dependency.js | 32 ++-- .../core/src/public/MutableBundleGraph.js | 2 +- .../core/src/requests/AssetGraphRequest.js | 8 +- .../core/core/src/requests/AssetRequest.js | 7 +- .../core/src/requests/BundleGraphRequest.js | 8 +- .../core/core/src/requests/DevDepRequest.js | 51 +++---- .../core/core/src/requests/PathRequest.js | 26 ++-- packages/core/core/src/types.js | 54 +++---- packages/core/core/test/AssetGraph.test.js | 48 ++++-- packages/core/core/test/BundleGraph.test.js | 6 +- packages/core/core/test/InternalAsset.test.js | 11 +- .../core/core/test/PublicDependency.test.js | 3 +- .../test/PublicMutableBundleGraph.test.js | 10 +- .../parcel-transformer-mock/index.js | 2 +- .../parcel-resolver-no-defer/index.js | 2 +- .../parcel-resolver-meta/index.js | 2 +- .../node_modules/parcel-runtime-meta/index.js | 2 +- .../package-manager/src/NodePackageManager.js | 18 +-- .../core/package-manager/src/NodeResolver.js | 9 +- .../package-manager/src/NodeResolverBase.js | 10 +- .../package-manager/src/NodeResolverSync.js | 6 +- packages/core/package-manager/src/types.js | 10 +- packages/core/register/src/register.js | 2 +- packages/core/test-utils/src/utils.js | 10 +- packages/core/types/index.js | 141 +++++++++++++----- .../core/utils/src/dependency-location.js | 6 +- .../core/utils/src/replaceBundleReferences.js | 8 +- .../test/replaceBundleReferences.test.js | 12 +- packages/packagers/css/src/CSSPackager.js | 2 +- packages/packagers/html/src/HTMLPackager.js | 21 ++- packages/packagers/js/src/DevPackager.js | 4 +- .../packagers/js/src/ScopeHoistingPackager.js | 14 +- .../reporters/dev-server/src/HMRServer.js | 2 +- .../resolvers/default/src/DefaultResolver.js | 6 +- packages/resolvers/glob/src/GlobResolver.js | 9 +- packages/runtimes/js/src/JSRuntime.js | 13 +- packages/runtimes/react-refresh/package.json | 1 + .../react-refresh/src/ReactRefreshRuntime.js | 15 +- packages/transformers/babel/src/config.js | 9 +- .../transformers/css/src/CSSTransformer.js | 17 ++- .../transformers/html/src/HTMLTransformer.js | 5 +- .../transformers/html/src/dependencies.js | 14 +- packages/transformers/html/src/inline.js | 8 +- packages/transformers/js/src/JSTransformer.js | 34 ++--- .../postcss/src/PostCSSTransformer.js | 7 +- .../transformers/postcss/src/loadConfig.js | 6 +- .../posthtml/src/PostHTMLTransformer.js | 4 +- .../src/ReactRefreshWrapTransformer.js | 5 +- .../src/WebExtensionTransformer.js | 16 +- .../typescript/src/TypeScriptValidator.js | 14 +- 62 files changed, 486 insertions(+), 467 deletions(-) diff --git a/packages/bundlers/default/src/DefaultBundler.js b/packages/bundlers/default/src/DefaultBundler.js index 43e3d163bb8..12d7056564c 100644 --- a/packages/bundlers/default/src/DefaultBundler.js +++ b/packages/bundlers/default/src/DefaultBundler.js @@ -70,24 +70,24 @@ export default (new Bundler({ let assets = bundleGraph.getDependencyAssets(dependency); let resolution = bundleGraph.getDependencyResolution(dependency); - // Create a new bundle for entries, async deps, isolated assets, and inline assets. + let bundleGroup = context?.bundleGroup; + // Create a new bundle for entries, lazy/parallel dependencies, isolated assets, and inline assets. if ( - (dependency.isEntry && resolution) || - (dependency.isAsync && resolution) || - (dependency.isIsolated && resolution) || - resolution?.isIsolated || - resolution?.isInline + resolution && + (!bundleGroup || + dependency.priority === 'lazy' || + dependency.priority === 'parallel' || + resolution.isIsolated || + resolution.isInline) ) { - let bundleGroup = context?.bundleGroup; let bundleByType: Map = context?.bundleByType ?? new Map(); - // Only create a new bundle group for entries, async dependencies, and isolated assets. + // Only create a new bundle group for entries, lazy dependencies, and isolated assets. // Otherwise, the bundle is loaded together with the parent bundle. if ( !bundleGroup || - dependency.isEntry || - dependency.isAsync || + dependency.priority === 'lazy' || resolution.isIsolated ) { bundleGroup = bundleGraph.createBundleGroup( @@ -101,7 +101,9 @@ export default (new Bundler({ for (let asset of assets) { let bundle = bundleGraph.createBundle({ entryAsset: asset, - isEntry: asset.isInline ? false : Boolean(dependency.isEntry), + isEntry: asset.isInline + ? false + : dependency.isEntry || dependency.needsStableName, isInline: asset.isInline, target: bundleGroup.target, }); @@ -132,9 +134,9 @@ export default (new Bundler({ invariant(context != null); invariant(context.parentNode.type === 'asset'); invariant(context.parentBundle != null); + invariant(bundleGroup != null); let parentAsset = context.parentNode.value; let parentBundle = context.parentBundle; - let bundleGroup = nullthrows(context.bundleGroup); let bundleByType = nullthrows(context.bundleByType); for (let asset of assets) { @@ -156,7 +158,9 @@ export default (new Bundler({ type: asset.type, target: bundleGroup.target, isEntry: - asset.isInline || dependency.isEntry === false + asset.isInline || + (dependency.priority === 'parallel' && + !dependency.needsStableName) ? false : parentBundle.isEntry, isInline: asset.isInline, @@ -254,7 +258,7 @@ export default (new Bundler({ if ( node.type !== 'dependency' || node.value.isEntry || - !node.value.isAsync + node.value.priority !== 'lazy' ) { return; } @@ -265,7 +269,7 @@ export default (new Bundler({ } let dependency = node.value; - if (dependency.isURL) { + if (dependency.specifierType === 'url') { // Don't internalize dependencies on URLs, e.g. `new Worker('foo.js')` return; } diff --git a/packages/core/core/src/AssetGraph.js b/packages/core/core/src/AssetGraph.js index f7c64619643..fe0e5eda94c 100644 --- a/packages/core/core/src/AssetGraph.js +++ b/packages/core/core/src/AssetGraph.js @@ -216,11 +216,13 @@ export default class AssetGraph extends ContentGraph { let depNodes = targets.map(target => { let node = nodeFromDep( createDependency({ - moduleSpecifier: entry.filePath, + specifier: entry.filePath, + specifierType: 'esm', // ??? pipeline: target.pipeline, target: target, env: target.env, isEntry: true, + needsStableName: true, symbols: target.env.isLibrary ? new Map([['*', {local: '*', isWeak: true, loc: null}]]) : undefined, @@ -423,9 +425,7 @@ export default class AssetGraph extends ContentGraph { let dependentAssets = []; for (let dep of asset.dependencies.values()) { - let dependentAsset = assets.find( - a => a.uniqueKey === dep.moduleSpecifier, - ); + let dependentAsset = assets.find(a => a.uniqueKey === dep.specifier); if (dependentAsset) { dependentAssetKeys.push(dependentAsset.uniqueKey); dependentAssets.push(dependentAsset); @@ -470,7 +470,7 @@ export default class AssetGraph extends ContentGraph { depNode.value.meta = existing.value.meta; } let dependentAsset = dependentAssets.find( - a => a.uniqueKey === dep.moduleSpecifier, + a => a.uniqueKey === dep.specifier, ); if (dependentAsset) { depNode.complete = true; diff --git a/packages/core/core/src/BundleGraph.js b/packages/core/core/src/BundleGraph.js index efd84a4bc5e..6ec1909c3ee 100644 --- a/packages/core/core/src/BundleGraph.js +++ b/packages/core/core/src/BundleGraph.js @@ -25,6 +25,7 @@ import invariant from 'assert'; import nullthrows from 'nullthrows'; import {objectSortedEntriesDeep} from '@parcel/utils'; import {Hash, hashString} from '@parcel/hash'; +import {Priority} from './types'; import {getBundleGroupId, getPublicId} from './utils'; import {ALL_EDGE_TYPES, mapVisitor} from './Graph'; @@ -274,7 +275,7 @@ export default class BundleGraph { } internalizeAsyncDependency(bundle: Bundle, dependency: Dependency) { - if (!dependency.isAsync) { + if (dependency.priority === Priority.sync) { throw new Error('Expected an async dependency'); } @@ -688,8 +689,11 @@ export default class BundleGraph { this._graph .getNodeIdsConnectedTo(assetNodeId, 'references') .map(id => this._graph.getNode(id)) - .filter(node => node?.type === 'dependency' && node.value.isAsync) - .length > 0 + .filter( + node => + node?.type === 'dependency' && + node.value.priority === Priority.lazy, + ).length > 0 ) { // If this asset is referenced by any async dependency, it's referenced. return true; diff --git a/packages/core/core/src/CommittedAsset.js b/packages/core/core/src/CommittedAsset.js index a78a2ac9bd4..6561b6e8958 100644 --- a/packages/core/core/src/CommittedAsset.js +++ b/packages/core/core/src/CommittedAsset.js @@ -1,18 +1,12 @@ // @flow strict-local -import type { - AST, - Blob, - ConfigResult, - FilePath, - PackageJSON, -} from '@parcel/types'; +import type {AST, Blob} from '@parcel/types'; import type {Asset, Dependency, ParcelOptions} from './types'; import {Readable} from 'stream'; import SourceMap from '@parcel/source-map'; import {bufferStream, blobToStream, streamFromPromise} from '@parcel/utils'; -import {getConfig, generateFromAST} from './assetUtils'; +import {generateFromAST} from './assetUtils'; import {deserializeRaw} from './serializer'; export default class CommittedAsset { @@ -140,18 +134,4 @@ export default class CommittedAsset { getDependencies(): Array { return Array.from(this.value.dependencies.values()); } - - async getConfig( - filePaths: Array, - options: ?{| - packageKey?: string, - parse?: boolean, - |}, - ): Promise { - return (await getConfig(this, filePaths, options))?.config; - } - - getPackage(): Promise { - return this.getConfig(['package.json']); - } } diff --git a/packages/core/core/src/Dependency.js b/packages/core/core/src/Dependency.js index 18a31909c47..cbc54150814 100644 --- a/packages/core/core/src/Dependency.js +++ b/packages/core/core/src/Dependency.js @@ -2,22 +2,23 @@ import type { SourceLocation, Meta, - ModuleSpecifier, + DependencySpecifier, Symbol, } from '@parcel/types'; import type {Dependency, Environment, Target} from './types'; import {hashString} from '@parcel/hash'; +import {SpecifierType, Priority} from './types'; type DependencyOpts = {| id?: string, sourcePath?: string, sourceAssetId?: string, - moduleSpecifier: ModuleSpecifier, - isAsync?: boolean, + specifier: DependencySpecifier, + specifierType: $Keys, + priority?: $Keys, + needsStableName?: boolean, isEntry?: boolean, isOptional?: boolean, - isURL?: boolean, - isIsolated?: boolean, loc?: SourceLocation, env: Environment, meta?: Meta, @@ -35,7 +36,7 @@ export function createDependency(opts: DependencyOpts): Dependency { opts.id || hashString( (opts.sourceAssetId ?? '') + - opts.moduleSpecifier + + opts.specifier + opts.env.id + (opts.target ? JSON.stringify(opts.target) : '') + (opts.pipeline ?? ''), @@ -44,11 +45,11 @@ export function createDependency(opts: DependencyOpts): Dependency { return { ...opts, id, - isAsync: opts.isAsync ?? false, - isEntry: opts.isEntry, + specifierType: SpecifierType[opts.specifierType], + priority: Priority[opts.priority ?? 'sync'], + needsStableName: opts.needsStableName ?? false, + isEntry: opts.isEntry ?? false, isOptional: opts.isOptional ?? false, - isURL: opts.isURL ?? false, - isIsolated: opts.isIsolated ?? false, meta: opts.meta || {}, symbols: opts.symbols, }; diff --git a/packages/core/core/src/PackagerRunner.js b/packages/core/core/src/PackagerRunner.js index d8c2133bf2b..580830fc5cc 100644 --- a/packages/core/core/src/PackagerRunner.js +++ b/packages/core/core/src/PackagerRunner.js @@ -213,7 +213,7 @@ export default class PackagerRunner { this.previousDevDeps, this.options, ); - let key = `${devDep.moduleSpecifier}:${devDep.resolveFrom}`; + let key = `${devDep.specifier}:${devDep.resolveFrom}`; this.devDepRequests.set(key, devDepRequest); } @@ -366,7 +366,7 @@ export default class PackagerRunner { // the potential for lazy require() that aren't executed until the request runs. let devDepRequest = await createDevDependency( { - moduleSpecifier: name, + specifier: name, resolveFrom, }, packager, @@ -445,7 +445,7 @@ export default class PackagerRunner { // the potential for lazy require() that aren't executed until the request runs. let devDepRequest = await createDevDependency( { - moduleSpecifier: optimizer.name, + specifier: optimizer.name, resolveFrom: optimizer.resolveFrom, }, optimizer, diff --git a/packages/core/core/src/Transformation.js b/packages/core/core/src/Transformation.js index d22086195cd..072c76c43d8 100644 --- a/packages/core/core/src/Transformation.js +++ b/packages/core/core/src/Transformation.js @@ -251,7 +251,7 @@ export default class Transformation { for (let transformer of pipeline.transformers) { await this.addDevDependency( { - moduleSpecifier: transformer.name, + specifier: transformer.name, resolveFrom: transformer.resolveFrom, range: transformer.range, }, @@ -315,7 +315,7 @@ export default class Transformation { hashes += await getConfigHash(config, transformer.name, this.options); for (let devDep of config.devDeps) { - let key = `${devDep.moduleSpecifier}:${devDep.resolveFrom}`; + let key = `${devDep.specifier}:${devDep.resolveFrom}`; hashes += nullthrows(this.devDepRequests.get(key)).hash; } } @@ -328,14 +328,14 @@ export default class Transformation { opts: DevDepOptions, transformer: LoadedPlugin | TransformerWithNameAndConfig, ): Promise { - let {moduleSpecifier, resolveFrom, range} = opts; - let key = `${moduleSpecifier}:${resolveFrom}`; + let {specifier, resolveFrom, range} = opts; + let key = `${specifier}:${resolveFrom}`; if (this.devDepRequests.has(key)) { return; } // Ensure that the package manager has an entry for this resolution. - await this.options.packageManager.resolve(moduleSpecifier, resolveFrom, { + await this.options.packageManager.resolve(specifier, resolveFrom, { range, }); @@ -633,7 +633,8 @@ export default class Transformation { await pipeline.resolverRunner.resolve( createDependency({ env: asset.value.env, - moduleSpecifier: to, + specifier: to, + specifierType: 'esm', // ??? sourcePath: from, }), ), diff --git a/packages/core/core/src/UncommittedAsset.js b/packages/core/core/src/UncommittedAsset.js index 1733e430299..bd9f0c92095 100644 --- a/packages/core/core/src/UncommittedAsset.js +++ b/packages/core/core/src/UncommittedAsset.js @@ -3,12 +3,10 @@ import type { AST, Blob, - ConfigResult, DependencyOptions, FilePath, FileCreateInvalidation, GenerateOutput, - PackageJSON, PackageName, TransformerResult, } from '@parcel/types'; @@ -38,7 +36,6 @@ import {PARCEL_VERSION} from './constants'; import { createAsset, createAssetIdFromOptions, - getConfig, getInvalidationId, getInvalidationHash, } from './assetUtils'; @@ -305,7 +302,7 @@ export default class UncommittedAsset { addDependency(opts: DependencyOptions): string { // eslint-disable-next-line no-unused-vars - let {env, target, symbols, ...rest} = opts; + let {env, symbols, ...rest} = opts; let dep = createDependency({ ...rest, // $FlowFixMe "convert" the $ReadOnlyMaps to the interal mutable one @@ -419,29 +416,6 @@ export default class UncommittedAsset { return asset; } - async getConfig( - filePaths: Array, - options: ?{| - packageKey?: string, - parse?: boolean, - |}, - ): Promise { - let conf = await getConfig(this, filePaths, options); - if (conf == null) { - return null; - } - - for (let file of conf.files) { - this.addIncludedFile(file.filePath); - } - - return conf.config; - } - - getPackage(): Promise { - return this.getConfig(['package.json']); - } - updateId() { // $FlowFixMe - this is fine this.value.id = createAssetIdFromOptions(this.value); diff --git a/packages/core/core/src/applyRuntimes.js b/packages/core/core/src/applyRuntimes.js index f985f96eaba..e1cc064750b 100644 --- a/packages/core/core/src/applyRuntimes.js +++ b/packages/core/core/src/applyRuntimes.js @@ -114,7 +114,7 @@ export default async function applyRuntimes({ for (let runtime of runtimes) { let devDepRequest = await createDevDependency( { - moduleSpecifier: runtime.name, + specifier: runtime.name, resolveFrom: runtime.resolveFrom, }, runtime, @@ -122,7 +122,7 @@ export default async function applyRuntimes({ options, ); devDepRequests.set( - `${devDepRequest.moduleSpecifier}:${devDepRequest.resolveFrom}`, + `${devDepRequest.specifier}:${devDepRequest.resolveFrom}`, devDepRequest, ); await runDevDepRequest(api, devDepRequest); diff --git a/packages/core/core/src/assetUtils.js b/packages/core/core/src/assetUtils.js index d0efd6ca03f..3bf54c2fb14 100644 --- a/packages/core/core/src/assetUtils.js +++ b/packages/core/core/src/assetUtils.js @@ -20,7 +20,6 @@ import type { ParcelOptions, } from './types'; import {objectSortedEntries} from '@parcel/utils'; -import type {ConfigOutput} from '@parcel/utils'; import {Readable} from 'stream'; import {PluginLogger} from '@parcel/logger'; @@ -30,7 +29,7 @@ import UncommittedAsset from './UncommittedAsset'; import loadPlugin from './loadParcelPlugin'; import {Asset as PublicAsset} from './public/Asset'; import PluginOptions from './public/PluginOptions'; -import {blobToStream, loadConfig, hashFile} from '@parcel/utils'; +import {blobToStream, hashFile} from '@parcel/utils'; import {hashFromOption} from './utils'; import {createBuildCache} from './buildCache'; import {hashString} from '@parcel/hash'; @@ -173,42 +172,6 @@ async function _generateFromAST(asset: CommittedAsset | UncommittedAsset) { }; } -export async function getConfig( - asset: CommittedAsset | UncommittedAsset, - filePaths: Array, - options: ?{| - packageKey?: string, - parse?: boolean, - |}, -): Promise { - let packageKey = options?.packageKey; - let parse = options && options.parse; - - if (packageKey != null) { - let pkg = await asset.getPackage(); - if (pkg && pkg[packageKey]) { - return { - config: pkg[packageKey], - // The package.json file was already registered by asset.getPackage() -> asset.getConfig() - files: [], - }; - } - } - - let conf = await loadConfig( - asset.options.inputFS, - asset.value.filePath, - filePaths, - asset.options.projectRoot, - parse == null ? null : {parse}, - ); - if (!conf) { - return null; - } - - return conf; -} - export function getInvalidationId(invalidation: RequestInvalidation): string { switch (invalidation.type) { case 'file': diff --git a/packages/core/core/src/dumpGraphToGraphViz.js b/packages/core/core/src/dumpGraphToGraphViz.js index d990fe15cd7..b79f8c92ac7 100644 --- a/packages/core/core/src/dumpGraphToGraphViz.js +++ b/packages/core/core/src/dumpGraphToGraphViz.js @@ -4,6 +4,7 @@ import type {Environment} from './types'; import type Graph from './Graph'; import type {AssetGraphNode, BundleGraphNode} from './types'; +import {SpecifierType, Priority} from './types'; import path from 'path'; @@ -54,13 +55,12 @@ export default async function dumpGraphToGraphViz( n.set('style', 'filled'); let label = `${node.type || 'No Type'}: [${node.id}]: `; if (node.type === 'dependency') { - label += node.value.moduleSpecifier; + label += node.value.specifier; let parts = []; - if (node.value.isEntry) parts.push('entry'); - if (node.value.isAsync) parts.push('async'); + if (node.value.priority !== Priority.sync) + parts.push(node.value.priority); if (node.value.isOptional) parts.push('optional'); - if (node.value.isIsolated) parts.push('isolated'); - if (node.value.isURL) parts.push('url'); + if (node.value.specifierType === SpecifierType.url) parts.push('url'); if (node.hasDeferred) parts.push('deferred'); if (node.excluded) parts.push('excluded'); if (parts.length) label += ' (' + parts.join(', ') + ')'; diff --git a/packages/core/core/src/public/Asset.js b/packages/core/core/src/public/Asset.js index 528a74c48a9..c7adc45ec0a 100644 --- a/packages/core/core/src/public/Asset.js +++ b/packages/core/core/src/public/Asset.js @@ -8,7 +8,6 @@ import type { Asset as IAsset, AST, ASTGenerator, - ConfigResult, Dependency as IDependency, DependencyOptions, Environment as IEnvironment, @@ -17,7 +16,6 @@ import type { FilePath, Meta, MutableAsset as IMutableAsset, - PackageJSON, Stats, MutableAssetSymbols as IMutableAssetSymbols, AssetSymbols as IAssetSymbols, @@ -153,24 +151,10 @@ class BaseAsset { return this.#asset.value.pipeline; } - getConfig( - filePaths: Array, - options: ?{| - packageKey?: string, - parse?: boolean, - |}, - ): Promise { - return this.#asset.getConfig(filePaths, options); - } - getDependencies(): $ReadOnlyArray { return this.#asset.getDependencies().map(dep => new Dependency(dep)); } - getPackage(): Promise { - return this.#asset.getPackage(); - } - getCode(): Promise { return this.#asset.getCode(); } @@ -316,9 +300,9 @@ export class MutableAsset extends BaseAsset implements IMutableAsset { addURLDependency(url: string, opts: $Shape): string { return this.addDependency({ - moduleSpecifier: url, - isURL: true, - isAsync: true, // The browser has native loaders for url dependencies + specifier: url, + specifierType: 'url', + priority: 'lazy', ...opts, }); } diff --git a/packages/core/core/src/public/Dependency.js b/packages/core/core/src/public/Dependency.js index 35c80efce59..97f64142252 100644 --- a/packages/core/core/src/public/Dependency.js +++ b/packages/core/core/src/public/Dependency.js @@ -5,6 +5,8 @@ import type { SourceLocation, Meta, MutableDependencySymbols as IMutableDependencySymbols, + SpecifierType, + DependencyPriority, } from '@parcel/types'; import type {Dependency as InternalDependency} from '../types'; @@ -12,6 +14,10 @@ import Environment from './Environment'; import Target from './Target'; import {MutableDependencySymbols} from './Symbols'; import nullthrows from 'nullthrows'; +import {SpecifierType as SpecifierTypeMap, Priority} from '../types'; + +const SpecifierTypeNames = Object.keys(SpecifierTypeMap); +const PriorityNames = Object.keys(Priority); const inspect = Symbol.for('nodejs.util.inspect.custom'); @@ -46,35 +52,35 @@ export default class Dependency implements IDependency { // $FlowFixMe [inspect](): string { - return `Dependency(${String(this.sourcePath)} -> ${this.moduleSpecifier})`; + return `Dependency(${String(this.sourcePath)} -> ${this.specifier})`; } get id(): string { return this.#dep.id; } - get moduleSpecifier(): string { - return this.#dep.moduleSpecifier; + get specifier(): string { + return this.#dep.specifier; } - get isAsync(): boolean { - return !!this.#dep.isAsync; + get specifierType(): SpecifierType { + return SpecifierTypeNames[this.#dep.specifierType]; } - get isEntry(): ?boolean { - return this.#dep.isEntry; + get priority(): DependencyPriority { + return PriorityNames[this.#dep.priority]; } - get isOptional(): boolean { - return !!this.#dep.isOptional; + get needsStableName(): boolean { + return this.#dep.needsStableName; } - get isURL(): boolean { - return !!this.#dep.isURL; + get isEntry(): boolean { + return this.#dep.isEntry; } - get isIsolated(): boolean { - return !!this.#dep.isIsolated; + get isOptional(): boolean { + return this.#dep.isOptional; } get loc(): ?SourceLocation { diff --git a/packages/core/core/src/public/MutableBundleGraph.js b/packages/core/core/src/public/MutableBundleGraph.js index 240fd454dbc..2a8686e9a4e 100644 --- a/packages/core/core/src/public/MutableBundleGraph.js +++ b/packages/core/core/src/public/MutableBundleGraph.js @@ -107,7 +107,7 @@ export default class MutableBundleGraph extends BundleGraph this.#graph._graph.addEdge(dependencyNodeId, resolvedNodeId, 'references'); this.#graph._graph.removeEdge(dependencyNodeId, resolvedNodeId); - if (dependency.isEntry) { + if (dependency.isEntry || resolved.isIsolated) { this.#graph._graph.addEdge( nullthrows(this.#graph._graph.rootNodeId), bundleGroupNodeId, diff --git a/packages/core/core/src/requests/AssetGraphRequest.js b/packages/core/core/src/requests/AssetGraphRequest.js index f9bb255fb11..656fbda2fe5 100644 --- a/packages/core/core/src/requests/AssetGraphRequest.js +++ b/packages/core/core/src/requests/AssetGraphRequest.js @@ -3,7 +3,7 @@ import type { Async, FilePath, - ModuleSpecifier, + DependencySpecifier, Symbol, SourceLocation, Meta, @@ -25,12 +25,14 @@ import type { import type {StaticRunOpts, RunAPI} from '../RequestTracker'; import type {EntryResult} from './EntryRequest'; import type {PathRequestInput} from './PathRequest'; + import invariant from 'assert'; import nullthrows from 'nullthrows'; import path from 'path'; import {PromiseQueue} from '@parcel/utils'; import {hashString} from '@parcel/hash'; import ThrowableDiagnostic, {md} from '@parcel/diagnostic'; +import {Priority} from '../types'; import AssetGraph from '../AssetGraph'; import {PARCEL_VERSION} from '../constants'; import createEntryRequest from './EntryRequest'; @@ -230,7 +232,7 @@ export class AssetGraphBuilder { } else if (!node.requested) { let isAsyncChild = this.assetGraph .getIncomingDependencies(node.value) - .every(dep => dep.isEntry || dep.isAsync); + .every(dep => dep.isEntry || dep.priority !== Priority.sync); if (isAsyncChild) { node.requested = false; } else { @@ -775,7 +777,7 @@ export class AssetGraphBuilder { ); } - async runEntryRequest(input: ModuleSpecifier) { + async runEntryRequest(input: DependencySpecifier) { let request = createEntryRequest(input); let result = await this.api.runRequest(request, { force: true, diff --git a/packages/core/core/src/requests/AssetRequest.js b/packages/core/core/src/requests/AssetRequest.js index d486f8e4826..5b251117ef4 100644 --- a/packages/core/core/src/requests/AssetRequest.js +++ b/packages/core/core/src/requests/AssetRequest.js @@ -102,10 +102,7 @@ async function run({input, api, farm, invalidateReason}: RunInput) { devDeps: new Map( [...previousDevDepRequests.entries()] .filter(([id]) => api.canSkipSubrequest(id)) - .map(([, req]) => [ - `${req.moduleSpecifier}:${req.resolveFrom}`, - req.hash, - ]), + .map(([, req]) => [`${req.specifier}:${req.resolveFrom}`, req.hash]), ), invalidDevDeps: await Promise.all( [...previousDevDepRequests.entries()] @@ -113,7 +110,7 @@ async function run({input, api, farm, invalidateReason}: RunInput) { .flatMap(([, req]) => { return [ { - moduleSpecifier: req.moduleSpecifier, + specifier: req.specifier, resolveFrom: req.resolveFrom, }, ...(req.additionalInvalidations ?? []), diff --git a/packages/core/core/src/requests/BundleGraphRequest.js b/packages/core/core/src/requests/BundleGraphRequest.js index 15182709934..a73fc4580da 100644 --- a/packages/core/core/src/requests/BundleGraphRequest.js +++ b/packages/core/core/src/requests/BundleGraphRequest.js @@ -155,8 +155,8 @@ class BundlerRunner { } async runDevDepRequest(devDepRequest: DevDepRequest) { - let {moduleSpecifier, resolveFrom} = devDepRequest; - let key = `${moduleSpecifier}:${resolveFrom}`; + let {specifier, resolveFrom} = devDepRequest; + let key = `${specifier}:${resolveFrom}`; this.devDepRequests.set(key, devDepRequest); await runDevDepRequest(this.api, devDepRequest); } @@ -248,7 +248,7 @@ class BundlerRunner { // the potential for lazy require() that aren't executed until the request runs. let devDepRequest = await createDevDependency( { - moduleSpecifier: name, + specifier: name, resolveFrom, }, plugin, @@ -320,7 +320,7 @@ class BundlerRunner { for (let namer of namers) { let devDepRequest = await createDevDependency( { - moduleSpecifier: namer.name, + specifier: namer.name, resolveFrom: namer.resolveFrom, }, namer, diff --git a/packages/core/core/src/requests/DevDepRequest.js b/packages/core/core/src/requests/DevDepRequest.js index cf7dac0a4b6..db9793dcec0 100644 --- a/packages/core/core/src/requests/DevDepRequest.js +++ b/packages/core/core/src/requests/DevDepRequest.js @@ -1,5 +1,5 @@ // @flow -import type {DevDepOptions, ModuleSpecifier, FilePath} from '@parcel/types'; +import type {DevDepOptions, DependencySpecifier, FilePath} from '@parcel/types'; import type ParcelConfig from '../ParcelConfig'; import type {DevDepRequest, ParcelOptions} from '../types'; import type {RunAPI} from '../RequestTracker'; @@ -10,12 +10,12 @@ import {createBuildCache} from '../buildCache'; export async function createDevDependency( opts: DevDepOptions, - plugin: {name: ModuleSpecifier, resolveFrom: FilePath, ...}, + plugin: {name: DependencySpecifier, resolveFrom: FilePath, ...}, requestDevDeps: Map, options: ParcelOptions, ): Promise { - let {moduleSpecifier, resolveFrom, invalidateParcelPlugin} = opts; - let key = `${moduleSpecifier}:${resolveFrom}`; + let {specifier, resolveFrom, invalidateParcelPlugin} = opts; + let key = `${specifier}:${resolveFrom}`; // If the request sent us a hash, we know the dev dep and all of its dependencies didn't change. // Reuse the same hash in the response. No need to send back invalidations as the request won't @@ -23,16 +23,16 @@ export async function createDevDependency( let hash = requestDevDeps.get(key); if (hash != null) { return { - moduleSpecifier, + specifier, resolveFrom, hash, }; } // Ensure that the package manager has an entry for this resolution. - await options.packageManager.resolve(moduleSpecifier, resolveFrom); + await options.packageManager.resolve(specifier, resolveFrom); let invalidations = options.packageManager.getInvalidations( - moduleSpecifier, + specifier, resolveFrom, ); @@ -49,7 +49,7 @@ export async function createDevDependency( ); let devDepRequest: DevDepRequest = { - moduleSpecifier, + specifier, resolveFrom, hash, invalidateOnFileCreate: invalidations.invalidateOnFileCreate, @@ -61,7 +61,7 @@ export async function createDevDependency( if (invalidateParcelPlugin) { devDepRequest.additionalInvalidations = [ { - moduleSpecifier: plugin.name, + specifier: plugin.name, resolveFrom: plugin.resolveFrom, }, ]; @@ -71,7 +71,7 @@ export async function createDevDependency( } export type DevDepSpecifier = {| - moduleSpecifier: ModuleSpecifier, + specifier: DependencySpecifier, resolveFrom: FilePath, |}; @@ -97,10 +97,7 @@ export async function getDevDepRequests(api: RunAPI): Promise { devDeps: new Map( [...previousDevDepRequests.entries()] .filter(([id]) => api.canSkipSubrequest(id)) - .map(([, req]) => [ - `${req.moduleSpecifier}:${req.resolveFrom}`, - req.hash, - ]), + .map(([, req]) => [`${req.specifier}:${req.resolveFrom}`, req.hash]), ), invalidDevDeps: await Promise.all( [...previousDevDepRequests.entries()] @@ -108,7 +105,7 @@ export async function getDevDepRequests(api: RunAPI): Promise { .flatMap(([, req]) => { return [ { - moduleSpecifier: req.moduleSpecifier, + specifier: req.specifier, resolveFrom: req.resolveFrom, }, ...(req.additionalInvalidations ?? []), @@ -127,11 +124,11 @@ export function invalidateDevDeps( options: ParcelOptions, config: ParcelConfig, ) { - for (let {moduleSpecifier, resolveFrom} of invalidDevDeps) { - let key = `${moduleSpecifier}:${resolveFrom}`; + for (let {specifier, resolveFrom} of invalidDevDeps) { + let key = `${specifier}:${resolveFrom}`; if (!invalidatedDevDeps.has(key)) { - config.invalidatePlugin(moduleSpecifier); - options.packageManager.invalidate(moduleSpecifier, resolveFrom); + config.invalidatePlugin(specifier); + options.packageManager.invalidate(specifier, resolveFrom); invalidatedDevDeps.set(key, true); } } @@ -142,11 +139,7 @@ export async function runDevDepRequest( devDepRequest: DevDepRequest, ) { await api.runRequest({ - id: - 'dev_dep_request:' + - devDepRequest.moduleSpecifier + - ':' + - devDepRequest.hash, + id: 'dev_dep_request:' + devDepRequest.specifier + ':' + devDepRequest.hash, type: 'dev_dep_request', run: ({api}) => { for (let filePath of nullthrows(devDepRequest.invalidateOnFileChange)) { @@ -161,7 +154,7 @@ export async function runDevDepRequest( } api.storeResult({ - moduleSpecifier: devDepRequest.moduleSpecifier, + specifier: devDepRequest.specifier, resolveFrom: devDepRequest.resolveFrom, hash: devDepRequest.hash, additionalInvalidations: devDepRequest.additionalInvalidations, @@ -181,11 +174,11 @@ export function getWorkerDevDepRequests( return devDepRequests.map(devDepRequest => { // If we've already sent a matching transformer + hash to the main thread during this build, // there's no need to repeat ourselves. - let {moduleSpecifier, resolveFrom, hash} = devDepRequest; - if (hash === pluginCache.get(moduleSpecifier)) { - return {moduleSpecifier, resolveFrom, hash}; + let {specifier, resolveFrom, hash} = devDepRequest; + if (hash === pluginCache.get(specifier)) { + return {specifier, resolveFrom, hash}; } else { - pluginCache.set(moduleSpecifier, hash); + pluginCache.set(specifier, hash); return devDepRequest; } }); diff --git a/packages/core/core/src/requests/PathRequest.js b/packages/core/core/src/requests/PathRequest.js index 07121e74ad3..2cf2af2b74d 100644 --- a/packages/core/core/src/requests/PathRequest.js +++ b/packages/core/core/src/requests/PathRequest.js @@ -24,6 +24,7 @@ import ParcelConfig from '../ParcelConfig'; import createParcelConfigRequest, { getCachedParcelConfig, } from './ParcelConfigRequest'; +import {Priority} from '../types'; export type PathRequest = {| id: string, @@ -150,12 +151,12 @@ export class ResolverRunner { if ( // Don't consider absolute paths. Absolute paths are only supported for entries, // and include e.g. `C:\` on Windows, conflicting with pipelines. - !path.isAbsolute(dependency.moduleSpecifier) && - dependency.moduleSpecifier.includes(':') + !path.isAbsolute(dependency.specifier) && + dependency.specifier.includes(':') ) { - [pipeline, filePath] = dependency.moduleSpecifier.split(':'); + [pipeline, filePath] = dependency.specifier.split(':'); if (!validPipelines.has(pipeline)) { - if (dep.isURL) { + if (dep.specifierType === 'url') { // This may be a url protocol or scheme rather than a pipeline, such as // `url('http://example.com/foo.png')` return null; @@ -167,15 +168,18 @@ export class ResolverRunner { } } } else { - if (dependency.isURL && dependency.moduleSpecifier.startsWith('//')) { + if ( + dep.specifierType === 'url' && + dependency.specifier.startsWith('//') + ) { // A protocol-relative URL, e.g `url('//example.com/foo.png')` return null; } - filePath = dependency.moduleSpecifier; + filePath = dependency.specifier; } let queryPart = null; - if (dependency.isURL) { + if (dep.specifierType === 'url') { let parsed = URL.parse(filePath); if (typeof parsed.pathname !== 'string') { throw await this.getThrowableDiagnostic( @@ -217,8 +221,8 @@ export class ResolverRunner { }; } - if (result.isAsync != null) { - dependency.isAsync = result.isAsync; + if (result.priority != null) { + dependency.priority = Priority[result.priority]; } if (result.isExcluded) { @@ -238,7 +242,7 @@ export class ResolverRunner { result.pipeline === undefined ? pipeline ?? dependency.pipeline : result.pipeline, - isURL: dependency.isURL, + isURL: dep.specifierType === 'url', }, invalidateOnFileCreate: result.invalidateOnFileCreate, invalidateOnFileChange: result.invalidateOnFileChange, @@ -285,7 +289,7 @@ export class ResolverRunner { // $FlowFixMe because of the err.code assignment let err = await this.getThrowableDiagnostic( dependency, - md`Failed to resolve '${dependency.moduleSpecifier}' ${ + md`Failed to resolve '${dependency.specifier}' ${ dir ? `from '${dir}'` : '' }`, ); diff --git a/packages/core/core/src/types.js b/packages/core/core/src/types.js index 6432ea96726..3ac827518d4 100644 --- a/packages/core/core/src/types.js +++ b/packages/core/core/src/types.js @@ -12,10 +12,9 @@ import type { Glob, LogLevel, Meta, - ModuleSpecifier, + DependencySpecifier, PackageName, ReporterEvent, - Semver, ServerOptions, SourceLocation, Stats, @@ -86,14 +85,27 @@ export type Target = {| source?: FilePath | Array, |}; +export const SpecifierType = { + esm: 0, + commonjs: 1, + url: 2, + custom: 3, +}; + +export const Priority = { + sync: 0, + parallel: 1, + lazy: 2, +}; + export type Dependency = {| id: string, - moduleSpecifier: ModuleSpecifier, - isAsync: boolean, - isEntry: ?boolean, + specifier: DependencySpecifier, + specifierType: $Values, + priority: $Values, + needsStableName: boolean, + isEntry: boolean, isOptional: boolean, - isURL: boolean, - isIsolated: boolean, loc: ?SourceLocation, env: Environment, meta: Meta, @@ -159,13 +171,13 @@ export type RequestInvalidation = | OptionInvalidation; export type DevDepRequest = {| - moduleSpecifier: ModuleSpecifier, + specifier: DependencySpecifier, resolveFrom: FilePath, hash: string, invalidateOnFileCreate?: Array, invalidateOnFileChange?: Set, additionalInvalidations?: Array<{| - moduleSpecifier: ModuleSpecifier, + specifier: DependencySpecifier, resolveFrom: FilePath, |}>, |}; @@ -173,8 +185,8 @@ export type DevDepRequest = {| export type ParcelOptions = {| entries: Array, entryRoot: FilePath, - config?: ModuleSpecifier, - defaultConfig?: ModuleSpecifier, + config?: DependencySpecifier, + defaultConfig?: DependencySpecifier, env: EnvMap, targets: ?(Array | {+[string]: TargetDescriptor, ...}), @@ -198,7 +210,7 @@ export type ParcelOptions = {| cache: Cache, packageManager: PackageManager, additionalReporters: Array<{| - packageName: ModuleSpecifier, + packageName: DependencySpecifier, resolveFrom: FilePath, |}>, @@ -308,7 +320,7 @@ export type TransformationRequest = {| invalidateReason: number, devDeps: Map, invalidDevDeps: Array<{| - moduleSpecifier: ModuleSpecifier, + specifier: DependencySpecifier, resolveFrom: FilePath, |}>, |}; @@ -328,7 +340,7 @@ export type AssetRequestNode = {| export type EntrySpecifierNode = {| id: ContentKey, +type: 'entry_specifier', - value: ModuleSpecifier, + value: DependencySpecifier, correspondingRequest?: string, |}; @@ -376,20 +388,8 @@ export type Config = {| shouldInvalidateOnStartup: boolean, |}; -export type DepVersionRequestNode = {| - id: ContentKey, - +type: 'dep_version_request', - value: DepVersionRequestDesc, -|}; - -export type DepVersionRequestDesc = {| - moduleSpecifier: PackageName, - resolveFrom: FilePath, - result?: Semver, -|}; - export type EntryRequest = {| - specifier: ModuleSpecifier, + specifier: DependencySpecifier, result?: FilePath, |}; diff --git a/packages/core/core/test/AssetGraph.test.js b/packages/core/core/test/AssetGraph.test.js index 0c62fe6b034..c70f158f04d 100644 --- a/packages/core/core/test/AssetGraph.test.js +++ b/packages/core/core/test/AssetGraph.test.js @@ -105,7 +105,8 @@ describe('AssetGraph', () => { assert( graph.hasContentKey( createDependency({ - moduleSpecifier: '/path/to/index1/src/main.js', + specifier: '/path/to/index1/src/main.js', + specifierType: 'esm', target: DEFAULT_TARGETS[0], env: DEFAULT_ENV, }).id, @@ -114,7 +115,8 @@ describe('AssetGraph', () => { assert( graph.hasContentKey( createDependency({ - moduleSpecifier: '/path/to/index2/src/main.js', + specifier: '/path/to/index2/src/main.js', + specifierType: 'esm', target: DEFAULT_TARGETS[0], env: DEFAULT_ENV, }).id, @@ -160,7 +162,8 @@ describe('AssetGraph', () => { ), to: graph.getNodeIdByContentKey( createDependency({ - moduleSpecifier: '/path/to/index1/src/main.js', + specifier: '/path/to/index1/src/main.js', + specifierType: 'esm', target: DEFAULT_TARGETS[0], env: DEFAULT_ENV, }).id, @@ -176,7 +179,8 @@ describe('AssetGraph', () => { ), to: graph.getNodeIdByContentKey( createDependency({ - moduleSpecifier: '/path/to/index2/src/main.js', + specifier: '/path/to/index2/src/main.js', + specifierType: 'esm', target: DEFAULT_TARGETS[0], env: DEFAULT_ENV, }).id, @@ -205,7 +209,8 @@ describe('AssetGraph', () => { ); let dep = createDependency({ - moduleSpecifier: '/path/to/index/src/main.js', + specifier: '/path/to/index/src/main.js', + specifierType: 'esm', target: DEFAULT_TARGETS[0], env: DEFAULT_ENV, }); @@ -254,7 +259,8 @@ describe('AssetGraph', () => { ); let dep = createDependency({ - moduleSpecifier: '/path/to/index/src/main.js', + specifier: '/path/to/index/src/main.js', + specifierType: 'esm', target: DEFAULT_TARGETS[0], env: DEFAULT_ENV, sourcePath: '', @@ -275,7 +281,8 @@ describe('AssetGraph', () => { [ 'utils', createDependency({ - moduleSpecifier: './utils', + specifier: './utils', + specifierType: 'esm', env: DEFAULT_ENV, sourcePath, }), @@ -294,7 +301,8 @@ describe('AssetGraph', () => { [ 'styles', createDependency({ - moduleSpecifier: './styles', + specifier: './styles', + specifierType: 'esm', env: DEFAULT_ENV, sourcePath, }), @@ -354,7 +362,8 @@ describe('AssetGraph', () => { [ 'utils', createDependency({ - moduleSpecifier: './utils', + specifier: './utils', + specifierType: 'esm', env: DEFAULT_ENV, sourcePath, }), @@ -407,7 +416,8 @@ describe('AssetGraph', () => { ); let dep = createDependency({ - moduleSpecifier: '/path/to/index/src/main.js', + specifier: '/path/to/index/src/main.js', + specifierType: 'esm', env: DEFAULT_ENV, target: DEFAULT_TARGETS[0], }); @@ -416,12 +426,14 @@ describe('AssetGraph', () => { graph.resolveDependency(dep, req, '123'); let sourcePath = filePath; let dep1 = createDependency({ - moduleSpecifier: 'dependent-asset-1', + specifier: 'dependent-asset-1', + specifierType: 'esm', env: DEFAULT_ENV, sourcePath, }); let dep2 = createDependency({ - moduleSpecifier: 'dependent-asset-2', + specifier: 'dependent-asset-2', + specifierType: 'esm', env: DEFAULT_ENV, sourcePath, }); @@ -491,12 +503,14 @@ describe('AssetGraph', () => { let indexAssetGroup = {filePath: '/index.js', env: DEFAULT_ENV, query: {}}; graph.setRootConnections({assetGroups: [indexAssetGroup]}); let indexFooDep = createDependency({ - moduleSpecifier: './foo', + specifier: './foo', + specifierType: 'esm', env: DEFAULT_ENV, sourcePath: '/index.js', }); let indexBarDep = createDependency({ - moduleSpecifier: './bar', + specifier: './bar', + specifierType: 'esm', env: DEFAULT_ENV, sourcePath: '/index.js', }); @@ -520,7 +534,8 @@ describe('AssetGraph', () => { graph.resolveDependency(indexFooDep, fooAssetGroup, '0'); let fooAssetGroupNode = nodeFromAssetGroup(fooAssetGroup); let fooUtilsDep = createDependency({ - moduleSpecifier: './utils', + specifier: './utils', + specifierType: 'esm', env: DEFAULT_ENV, sourcePath: '/foo.js', }); @@ -557,7 +572,8 @@ describe('AssetGraph', () => { graph.resolveDependency(indexBarDep, barAssetGroup, '0'); let barAssetGroupNode = nodeFromAssetGroup(barAssetGroup); let barUtilsDep = createDependency({ - moduleSpecifier: './utils', + specifier: './utils', + specifierType: 'esm', env: DEFAULT_ENV, sourcePath: '/bar.js', }); diff --git a/packages/core/core/test/BundleGraph.test.js b/packages/core/core/test/BundleGraph.test.js index ba9e2c65f8b..af38cdc3100 100644 --- a/packages/core/core/test/BundleGraph.test.js +++ b/packages/core/core/test/BundleGraph.test.js @@ -59,7 +59,8 @@ function createMockAssetGraph(ids: [string, string]) { ); let dep = createDependency({ - moduleSpecifier: '/path/to/index/src/main.js', + specifier: '/path/to/index/src/main.js', + specifierType: 'esm', env: DEFAULT_ENV, target: DEFAULT_TARGETS[0], }); @@ -68,7 +69,8 @@ function createMockAssetGraph(ids: [string, string]) { graph.resolveDependency(dep, nodeFromAssetGroup(req).value, '3'); let dep1 = createDependency({ - moduleSpecifier: 'dependent-asset-1', + specifier: 'dependent-asset-1', + specifierType: 'esm', env: DEFAULT_ENV, sourcePath: filePath, }); diff --git a/packages/core/core/test/InternalAsset.test.js b/packages/core/core/test/InternalAsset.test.js index ba55b7a4405..822571f0f99 100644 --- a/packages/core/core/test/InternalAsset.test.js +++ b/packages/core/core/test/InternalAsset.test.js @@ -42,11 +42,11 @@ describe('InternalAsset', () => { options: DEFAULT_OPTIONS, }); - asset.addDependency({moduleSpecifier: './foo'}); - asset.addDependency({moduleSpecifier: './foo'}); + asset.addDependency({specifier: './foo', specifierType: 'esm'}); + asset.addDependency({specifier: './foo', specifierType: 'esm'}); let dependencies = asset.getDependencies(); assert(dependencies.length === 1); - assert(dependencies[0].moduleSpecifier === './foo'); + assert(dependencies[0].specifier === './foo'); }); it('includes different dependencies if their id differs', () => { @@ -61,9 +61,10 @@ describe('InternalAsset', () => { options: DEFAULT_OPTIONS, }); - asset.addDependency({moduleSpecifier: './foo'}); + asset.addDependency({specifier: './foo', specifierType: 'esm'}); asset.addDependency({ - moduleSpecifier: './foo', + specifier: './foo', + specifierType: 'esm', env: {context: 'web-worker', engines: {}}, }); let dependencies = asset.getDependencies(); diff --git a/packages/core/core/test/PublicDependency.test.js b/packages/core/core/test/PublicDependency.test.js index aa32a3c7b34..c5fd688af4c 100644 --- a/packages/core/core/test/PublicDependency.test.js +++ b/packages/core/core/test/PublicDependency.test.js @@ -8,7 +8,8 @@ import Dependency from '../src/public/Dependency'; describe('Public Dependency', () => { it('returns the same public Dependency given an internal dependency', () => { let internalDependency = createDependency({ - moduleSpecifier: 'foo', + specifier: 'foo', + specifierType: 'esm', env: createEnvironment({}), }); diff --git a/packages/core/core/test/PublicMutableBundleGraph.test.js b/packages/core/core/test/PublicMutableBundleGraph.test.js index d37b3aa5895..e5f9b017209 100644 --- a/packages/core/core/test/PublicMutableBundleGraph.test.js +++ b/packages/core/core/test/PublicMutableBundleGraph.test.js @@ -113,14 +113,16 @@ function createMockAssetGraph() { ); let dep1 = createDependency({ - moduleSpecifier: '/path/to/index/src/main.js', - isEntry: true, + specifier: '/path/to/index/src/main.js', + specifierType: 'esm', + needsStableName: true, env: DEFAULT_ENV, target: DEFAULT_TARGETS[0], }); let dep2 = createDependency({ - moduleSpecifier: '/path/to/index/src/main2.js', - isEntry: true, + specifier: '/path/to/index/src/main2.js', + specifierType: 'esm', + needsStableName: true, env: DEFAULT_ENV, target: DEFAULT_TARGETS[0], }); diff --git a/packages/core/integration-tests/test/integration/cache/node_modules/parcel-transformer-mock/index.js b/packages/core/integration-tests/test/integration/cache/node_modules/parcel-transformer-mock/index.js index 0083740b73b..9aa8b706deb 100644 --- a/packages/core/integration-tests/test/integration/cache/node_modules/parcel-transformer-mock/index.js +++ b/packages/core/integration-tests/test/integration/cache/node_modules/parcel-transformer-mock/index.js @@ -4,7 +4,7 @@ module.exports = new Transformer({ transform({asset}) { if (asset.isSource) { asset.addDependency({ - moduleSpecifier: 'foo' + specifier: 'foo' }); return [asset]; } diff --git a/packages/core/integration-tests/test/integration/resolver-canDefer/node_modules/parcel-resolver-no-defer/index.js b/packages/core/integration-tests/test/integration/resolver-canDefer/node_modules/parcel-resolver-no-defer/index.js index 14e0508a3b0..fb640ccf4a6 100644 --- a/packages/core/integration-tests/test/integration/resolver-canDefer/node_modules/parcel-resolver-no-defer/index.js +++ b/packages/core/integration-tests/test/integration/resolver-canDefer/node_modules/parcel-resolver-no-defer/index.js @@ -16,7 +16,7 @@ module.exports = new Resolver({ }); let result = await resolver.resolve({ filename: filePath, - isURL: dependency.isURL, + isURL: dependency.specifierType === 'url', parent: dependency.sourcePath, env: dependency.env, }); diff --git a/packages/core/integration-tests/test/integration/resolver-dependency-meta/node_modules/parcel-resolver-meta/index.js b/packages/core/integration-tests/test/integration/resolver-dependency-meta/node_modules/parcel-resolver-meta/index.js index 560e75ffdbd..1a8ed6f2923 100644 --- a/packages/core/integration-tests/test/integration/resolver-dependency-meta/node_modules/parcel-resolver-meta/index.js +++ b/packages/core/integration-tests/test/integration/resolver-dependency-meta/node_modules/parcel-resolver-meta/index.js @@ -2,7 +2,7 @@ const {Resolver} = require('@parcel/plugin'); module.exports = new Resolver({ resolve({dependency, options, filePath}) { - if(dependency.moduleSpecifier === "foo"){ + if(dependency.specifier === "foo"){ return {isExcluded: true, meta: {customValue: 1234}}; } } diff --git a/packages/core/integration-tests/test/integration/resolver-dependency-meta/node_modules/parcel-runtime-meta/index.js b/packages/core/integration-tests/test/integration/resolver-dependency-meta/node_modules/parcel-runtime-meta/index.js index 8a565d8310f..da1a30d35b6 100644 --- a/packages/core/integration-tests/test/integration/resolver-dependency-meta/node_modules/parcel-runtime-meta/index.js +++ b/packages/core/integration-tests/test/integration/resolver-dependency-meta/node_modules/parcel-runtime-meta/index.js @@ -4,7 +4,7 @@ module.exports = new Runtime({ apply({bundle}) { let dep; bundle.traverse((node, _, actions) => { - if (node.type === "dependency" && node.value.moduleSpecifier === "foo") { + if (node.type === "dependency" && node.value.specifier === "foo") { dep = node.value; actions.stop(); } diff --git a/packages/core/package-manager/src/NodePackageManager.js b/packages/core/package-manager/src/NodePackageManager.js index 8497ef48198..96a2531ec88 100644 --- a/packages/core/package-manager/src/NodePackageManager.js +++ b/packages/core/package-manager/src/NodePackageManager.js @@ -1,5 +1,5 @@ // @flow -import type {FilePath, ModuleSpecifier, SemverRange} from '@parcel/types'; +import type {FilePath, DependencySpecifier, SemverRange} from '@parcel/types'; import type {FileSystem} from '@parcel/fs'; import type { ModuleRequest, @@ -31,8 +31,8 @@ import {NodeResolverSync} from './NodeResolverSync'; // There can be more than one instance of NodePackageManager, but node has only a single module cache. // Therefore, the resolution cache and the map of parent to child modules should also be global. -const cache = new Map(); -const children = new Map>(); +const cache = new Map(); +const children = new Map>(); // This implements a package manager for Node by monkey patching the Node require // algorithm so that it uses the specified FileSystem instead of the native one. @@ -77,7 +77,7 @@ export class NodePackageManager implements PackageManager { } async require( - name: ModuleSpecifier, + name: DependencySpecifier, from: FilePath, opts: ?{| range?: ?SemverRange, @@ -89,7 +89,7 @@ export class NodePackageManager implements PackageManager { return this.load(resolved, from); } - requireSync(name: ModuleSpecifier, from: FilePath): any { + requireSync(name: DependencySpecifier, from: FilePath): any { let {resolved} = this.resolveSync(name, from); return this.load(resolved, from); } @@ -134,7 +134,7 @@ export class NodePackageManager implements PackageManager { } async resolve( - name: ModuleSpecifier, + name: DependencySpecifier, from: FilePath, options?: ?{| range?: ?SemverRange, @@ -286,7 +286,7 @@ export class NodePackageManager implements PackageManager { return resolved; } - resolveSync(name: ModuleSpecifier, from: FilePath): ResolveResult { + resolveSync(name: DependencySpecifier, from: FilePath): ResolveResult { let basedir = path.dirname(from); let key = basedir + ':' + name; let resolved = cache.get(key); @@ -319,7 +319,7 @@ export class NodePackageManager implements PackageManager { }); } - getInvalidations(name: ModuleSpecifier, from: FilePath): Invalidations { + getInvalidations(name: DependencySpecifier, from: FilePath): Invalidations { let res = { invalidateOnFileCreate: [], invalidateOnFileChange: new Set(), @@ -358,7 +358,7 @@ export class NodePackageManager implements PackageManager { return res; } - invalidate(name: ModuleSpecifier, from: FilePath) { + invalidate(name: DependencySpecifier, from: FilePath) { let seen = new Set(); let invalidate = (name, from) => { diff --git a/packages/core/package-manager/src/NodeResolver.js b/packages/core/package-manager/src/NodeResolver.js index bf4b59b564c..5940eccec5a 100644 --- a/packages/core/package-manager/src/NodeResolver.js +++ b/packages/core/package-manager/src/NodeResolver.js @@ -1,12 +1,15 @@ // @flow -import type {FilePath, ModuleSpecifier, PackageJSON} from '@parcel/types'; +import type {FilePath, DependencySpecifier, PackageJSON} from '@parcel/types'; import type {ResolveResult, ResolverContext} from './NodeResolverBase'; import path from 'path'; import {NodeResolverBase} from './NodeResolverBase'; export class NodeResolver extends NodeResolverBase> { - async resolve(id: ModuleSpecifier, from: FilePath): Promise { + async resolve( + id: DependencySpecifier, + from: FilePath, + ): Promise { let ctx = { invalidateOnFileCreate: [], invalidateOnFileChange: new Set(), @@ -166,7 +169,7 @@ export class NodeResolver extends NodeResolverBase> { } async loadNodeModules( - id: ModuleSpecifier, + id: DependencySpecifier, from: FilePath, ctx: ResolverContext, ): Promise { diff --git a/packages/core/package-manager/src/NodeResolverBase.js b/packages/core/package-manager/src/NodeResolverBase.js index 6784f0d1c71..6c871db8eed 100644 --- a/packages/core/package-manager/src/NodeResolverBase.js +++ b/packages/core/package-manager/src/NodeResolverBase.js @@ -4,7 +4,7 @@ import type { PackageJSON, FileCreateInvalidation, FilePath, - ModuleSpecifier, + DependencySpecifier, } from '@parcel/types'; import type {FileSystem} from '@parcel/fs'; // $FlowFixMe @@ -19,7 +19,7 @@ for (let builtin of Module.builtinModules) { } export type ResolveResult = {| - resolved: FilePath | ModuleSpecifier, + resolved: FilePath | DependencySpecifier, pkg?: ?PackageJSON, invalidateOnFileCreate: Array, invalidateOnFileChange: Set, @@ -57,7 +57,7 @@ export class NodeResolverBase { this.packageCache = new Map(); } - resolve(id: ModuleSpecifier, from: FilePath): T { + resolve(id: DependencySpecifier, from: FilePath): T { throw new Error(`Could not resolve "${id}" from "${from}"`); } @@ -118,12 +118,12 @@ export class NodeResolverBase { } } - isBuiltin(name: ModuleSpecifier): boolean { + isBuiltin(name: DependencySpecifier): boolean { return !!builtins[name]; } findNodeModulePath( - id: ModuleSpecifier, + id: DependencySpecifier, sourceFile: FilePath, ctx: ResolverContext, ): ?ResolveResult | ?ModuleInfo { diff --git a/packages/core/package-manager/src/NodeResolverSync.js b/packages/core/package-manager/src/NodeResolverSync.js index 06fc5120f7b..01fb058aa7a 100644 --- a/packages/core/package-manager/src/NodeResolverSync.js +++ b/packages/core/package-manager/src/NodeResolverSync.js @@ -1,12 +1,12 @@ // @flow -import type {FilePath, ModuleSpecifier, PackageJSON} from '@parcel/types'; +import type {FilePath, DependencySpecifier, PackageJSON} from '@parcel/types'; import type {ResolveResult, ResolverContext} from './NodeResolverBase'; import path from 'path'; import {NodeResolverBase} from './NodeResolverBase'; export class NodeResolverSync extends NodeResolverBase { - resolve(id: ModuleSpecifier, from: FilePath): ResolveResult { + resolve(id: DependencySpecifier, from: FilePath): ResolveResult { let ctx = { invalidateOnFileCreate: [], invalidateOnFileChange: new Set(), @@ -148,7 +148,7 @@ export class NodeResolverSync extends NodeResolverBase { } loadNodeModules( - id: ModuleSpecifier, + id: DependencySpecifier, from: FilePath, ctx: ResolverContext, ): ?ResolveResult { diff --git a/packages/core/package-manager/src/types.js b/packages/core/package-manager/src/types.js index 048de942277..005c109a685 100644 --- a/packages/core/package-manager/src/types.js +++ b/packages/core/package-manager/src/types.js @@ -4,7 +4,7 @@ import type { FilePath, FileCreateInvalidation, SemverRange, - ModuleSpecifier, + DependencySpecifier, } from '@parcel/types'; import type {FileSystem} from '@parcel/fs'; import type {ResolveResult} from './NodeResolverBase'; @@ -35,17 +35,17 @@ export type Invalidations = {| export interface PackageManager { require( - id: ModuleSpecifier, + id: DependencySpecifier, from: FilePath, ?{|range?: ?SemverRange, shouldAutoInstall?: boolean, saveDev?: boolean|}, ): Promise; resolve( - id: ModuleSpecifier, + id: DependencySpecifier, from: FilePath, ?{|range?: ?SemverRange, shouldAutoInstall?: boolean, saveDev?: boolean|}, ): Promise; - getInvalidations(id: ModuleSpecifier, from: FilePath): Invalidations; - invalidate(id: ModuleSpecifier, from: FilePath): void; + getInvalidations(id: DependencySpecifier, from: FilePath): Invalidations; + invalidate(id: DependencySpecifier, from: FilePath): void; } export type ModuleRequest = {| diff --git a/packages/core/register/src/register.js b/packages/core/register/src/register.js index 245e185ed2a..de4054a00f3 100644 --- a/packages/core/register/src/register.js +++ b/packages/core/register/src/register.js @@ -93,7 +93,7 @@ function register(inputOpts?: InitialParcelOptions): IDisposable { let resolved = syncPromise( // $FlowFixMe parcel[INTERNAL_RESOLVE]({ - moduleSpecifier: targetFile, + specifier: targetFile, sourcePath: currFile, env, }), diff --git a/packages/core/test-utils/src/utils.js b/packages/core/test-utils/src/utils.js index f993b02fdb6..37456e803ac 100644 --- a/packages/core/test-utils/src/utils.js +++ b/packages/core/test-utils/src/utils.js @@ -149,7 +149,7 @@ export function findAsset( export function findDependency( bundleGraph: BundleGraph, assetFileName: string, - moduleSpecifier: string, + specifier: string, ): Dependency { let asset = nullthrows( findAsset(bundleGraph, assetFileName), @@ -158,10 +158,10 @@ export function findDependency( let dependency = bundleGraph .getDependencies(asset) - .find(d => d.moduleSpecifier === moduleSpecifier); + .find(d => d.specifier === specifier); invariant( dependency != null, - `Couldn't find dependency ${assetFileName} -> ${moduleSpecifier}`, + `Couldn't find dependency ${assetFileName} -> ${specifier}`, ); return dependency; } @@ -189,9 +189,9 @@ export function mergeParcelOptions( export function assertDependencyWasDeferred( bundleGraph: BundleGraph, assetFileName: string, - moduleSpecifier: string, + specifier: string, ): void { - let dep = findDependency(bundleGraph, assetFileName, moduleSpecifier); + let dep = findDependency(bundleGraph, assetFileName, specifier); invariant( bundleGraph.isDependencySkipped(dep), util.inspect(dep) + " wasn't deferred", diff --git a/packages/core/types/index.js b/packages/core/types/index.js index 9f166e7f0ba..1e680c9dc74 100644 --- a/packages/core/types/index.js +++ b/packages/core/types/index.js @@ -42,7 +42,7 @@ export type Glob = string; export type Semver = string; export type SemverRange = string; /** See Dependency */ -export type ModuleSpecifier = string; +export type DependencySpecifier = string; /** A pipeline as specified in the config mapping to T */ export type GlobMap = {[Glob]: T, ...}; @@ -258,8 +258,8 @@ export type DetailedReportOptions = {| export type InitialParcelOptions = {| +entries?: FilePath | Array, +entryRoot?: FilePath, - +config?: ModuleSpecifier, - +defaultConfig?: ModuleSpecifier, + +config?: DependencySpecifier, + +defaultConfig?: DependencySpecifier, +env?: EnvMap, +targets?: ?(Array | {+[string]: TargetDescriptor, ...}), @@ -292,7 +292,7 @@ export type InitialParcelOptions = {| |}, +additionalReporters?: Array<{| - packageName: ModuleSpecifier, + packageName: DependencySpecifier, resolveFrom: FilePath, |}>, @@ -384,6 +384,7 @@ export interface AssetSymbols // eslint-disable-next-line no-undef hasLocalSymbol(local: Symbol): boolean; exportSymbols(): Iterable; } + export interface MutableAssetSymbols extends AssetSymbols { /** * Initilizes the map, sets isCleared to false. @@ -397,6 +398,7 @@ export interface MutableAssetSymbols extends AssetSymbols { ): void; delete(exportSymbol: Symbol): void; } + /** * isWeak means: the symbol is not used by the parent asset itself and is merely reexported */ @@ -431,24 +433,58 @@ export interface MutableDependencySymbols // eslint-disable-next-line no-undef delete(exportSymbol: Symbol): void; } +export type DependencyPriority = 'sync' | 'parallel' | 'lazy'; +export type SpecifierType = 'commonjs' | 'esm' | 'url' | 'custom'; + /** * Usen when creating a Dependency, see that. * @section transformer */ export type DependencyOptions = {| - +moduleSpecifier: ModuleSpecifier, - +isAsync?: boolean, - /** Is merged with the environment of the importer */ - +isEntry?: boolean, + /** The specifier used to resolve the dependency. */ + +specifier: DependencySpecifier, + /** + * How the specifier should be interpreted. + * - esm: An ES module specifier. It is parsed as a URL, but bare specifiers are treated as node_modules. + * - commonjs: A CommonJS specifier. It is not parsed as a URL. + * - url: A URL that works as in a browser. Bare specifiers are treated as relative URLs. + * - custom: A custom specifier. Must be handled by a custom resolver plugin. + */ + +specifierType: SpecifierType, + /** + * When the dependency should be loaded. + * - sync: The dependency should be resolvable synchronously. The resolved asset will be placed + * in the same bundle as the parent, or another bundle that's already on the page. + * - parallel: The dependency should be placed in a separate bundle that's loaded in parallel + * with the current bundle. + * - lazy: The dependency should be placed in a separate bundle that's loaded later. + * @default 'sync' + */ + +priority?: DependencyPriority, + /** + * When the dependency is a bundle entry (priority is "parallel" or "lazy"), this controls the naming + * of that bundle. `needsStableName` indicates that the name should be stable over time, even when the + * content of the bundle changes. This is useful for entries that a user would manually enter the URL + * for, as well as for things like service workers or RSS feeds, where the URL must remain consistent + * over time. + */ + +needsStableName?: boolean, + /** Whether the dependency is optional. If the dependency cannot be resolved, this will not fail the build. */ +isOptional?: boolean, - +isURL?: boolean, - +isIsolated?: boolean, + /** The location within the source file where the dependency was found. */ +loc?: SourceLocation, + /** The environment of the dependency. */ +env?: EnvironmentOptions, + /** Plugin-specific metadata for the dependency. */ +meta?: Meta, + /** The pipeline defined in .parcelrc that the dependency should be processed with. */ +pipeline?: string, + /** + * The file path where the dependency should be resolved from. + * By default, this is the path of the source file where the dependency was specified. + */ +resolveFrom?: FilePath, - +target?: Target, + /** The symbols within the resolved module that the source file depends on. */ +symbols?: $ReadOnlyMap< Symbol, {|local: Symbol, loc: ?SourceLocation, isWeak: boolean|}, @@ -462,34 +498,64 @@ export type DependencyOptions = {| * @section transformer */ export interface Dependency { + /** The id of the dependency. */ +id: string; - /** E.g. "lodash" in import {add} from "lodash"; */ - +moduleSpecifier: ModuleSpecifier; - +isAsync: boolean; - /** Whether this should become a entry in a bundle. */ - +isEntry: ?boolean; - /** Whether a failed resolution should not cause a build error. */ + /** The specifier used to resolve the dependency. */ + +specifier: DependencySpecifier; + /** + * How the specifier should be interpreted. + * - esm: An ES module specifier. It is parsed as a URL, but bare specifiers are treated as node_modules. + * - commonjs: A CommonJS specifier. It is not parsed as a URL. + * - url: A URL that works as in a browser. Bare specifiers are treated as relative URLs. + * - custom: A custom specifier. Must be handled by a custom resolver plugin. + */ + +specifierType: SpecifierType; + /** + * When the dependency should be loaded. + * - sync: The dependency should be resolvable synchronously. The resolved asset will be placed + * in the same bundle as the parent, or another bundle that's already on the page. + * - parallel: The dependency should be placed in a separate bundle that's loaded in parallel + * with the current bundle. + * - lazy: The dependency should be placed in a separate bundle that's loaded later. + * @default 'sync' + */ + +priority: DependencyPriority; + /** + * When the dependency is a bundle entry (priority is "parallel" or "lazy"), this controls the naming + * of that bundle. `needsStableName` indicates that the name should be stable over time, even when the + * content of the bundle changes. This is useful for entries that a user would manually enter the URL + * for, as well as for things like service workers or RSS feeds, where the URL must remain consistent + * over time. + */ + +needsStableName: boolean; + /** Whether the dependency is optional. If the dependency cannot be resolved, this will not fail the build. */ +isOptional: boolean; - /** Whether an URL is expected (rather than the language-specific behaviour). */ - +isURL: boolean; - +isIsolated: boolean; - /** Used for error messages, the code location that caused this dependency. */ + /** Whether the dependency is an entry. */ + +isEntry: boolean; + /** The location within the source file where the dependency was found. */ +loc: ?SourceLocation; + /** The environment of the dependency. */ +env: Environment; + /** Plugin-specific metadata for the dependency. */ +meta: Meta; + /** If this is an entry, this is the target that is associated with that entry. */ +target: ?Target; - /** Used for error messages, the importer. */ + /** The id of the asset with this dependency. */ +sourceAssetId: ?string; - /** Used for error messages, the importer. */ - +sourcePath: ?string; + /** The file path of the asset with this dependency. */ + +sourcePath: ?FilePath; /** The type of the asset that referenced this dependency. */ +sourceAssetType: ?string; - +resolveFrom: ?string; - /** a named pipeline (if the moduleSpecifier didn't specify one). */ + /** + * The file path where the dependency should be resolved from. + * By default, this is the path of the source file where the dependency was specified. + */ + +resolveFrom: ?FilePath; + /** The pipeline defined in .parcelrc that the dependency should be processed with. */ +pipeline: ?string; // TODO make immutable - /** a Map<export name of importee, placeholder in importer>. */ + /** The symbols within the resolved module that the source file depends on. */ +symbols: MutableDependencySymbols; } @@ -554,18 +620,6 @@ export interface BaseAsset { /** A buffer representation of the sourcemap (if existent). */ getMapBuffer(): Promise; getDependencies(): $ReadOnlyArray; - /** Used to load config files, (looks in every parent folder until a module root) \ - * for the specified filenames. packageKey can be used to also check pkg#[packageKey]. - */ - getConfig( - filePaths: Array, - options: ?{| - packageKey?: string, - parse?: boolean, - |}, - ): Promise; - /** Returns the package.json this file belongs to. */ - getPackage(): Promise; } /** @@ -606,7 +660,7 @@ export interface Asset extends BaseAsset { } export type DevDepOptions = {| - moduleSpecifier: ModuleSpecifier, + specifier: DependencySpecifier, resolveFrom: FilePath, range?: ?SemverRange, /** @@ -702,11 +756,13 @@ export type ResolveFn = (from: FilePath, to: string) => Promise; /** * @section validator + * @experimental */ type ResolveConfigFn = (configNames: Array) => Promise; /** * @section validator + * @experimental */ type ResolveConfigWithPathFn = ( configNames: Array, @@ -715,6 +771,7 @@ type ResolveConfigWithPathFn = ( /** * @section validator + * @experimental */ export type ValidateResult = {| warnings: Array, @@ -723,6 +780,7 @@ export type ValidateResult = {| /** * @section validator + * @experimental */ export type DedicatedThreadValidator = {| validateAll: ({| @@ -735,6 +793,7 @@ export type DedicatedThreadValidator = {| /** * @section validator + * @experimental */ export type MultiThreadValidator = {| validate: ({| @@ -1107,7 +1166,7 @@ export type ResolveResult = {| +filePath?: FilePath, +pipeline?: ?string, +isExcluded?: boolean, - +isAsync?: boolean, + +priority?: DependencyPriority, /** Corresponds to BaseAsset's sideEffects. */ +sideEffects?: boolean, /** A resolver might want to resolve to a dummy, in this case filePath is rather "resolve from". */ diff --git a/packages/core/utils/src/dependency-location.js b/packages/core/utils/src/dependency-location.js index 44c91192e6f..dc914204044 100644 --- a/packages/core/utils/src/dependency-location.js +++ b/packages/core/utils/src/dependency-location.js @@ -5,7 +5,7 @@ export default function createDependencyLocation( column: number, ... }, - moduleSpecifier: string, + specifier: string, lineOffset: number = 0, columnOffset: number = 0, // Imports are usually wrapped in quotes @@ -16,7 +16,7 @@ export default function createDependencyLocation( start: {|column: number, line: number|}, |} { return { - filePath: moduleSpecifier, + filePath: specifier, start: { line: start.line + lineOffset, column: start.column + columnOffset, @@ -25,7 +25,7 @@ export default function createDependencyLocation( line: start.line + lineOffset, column: start.column + - moduleSpecifier.length - + specifier.length - 1 + importWrapperLength + columnOffset, diff --git a/packages/core/utils/src/replaceBundleReferences.js b/packages/core/utils/src/replaceBundleReferences.js index 8842e3a225a..2491dcb4a2e 100644 --- a/packages/core/utils/src/replaceBundleReferences.js +++ b/packages/core/utils/src/replaceBundleReferences.js @@ -22,7 +22,7 @@ type ReplacementMap = Map< /* * Replaces references to dependency ids for URL dependencies with: - * - in the case of an unresolvable url dependency, the original moduleSpecifier. + * - in the case of an unresolvable url dependency, the original specifier. * These are external requests that Parcel did not bundle. * - in the case of a reference to another bundle, the relative url to that * bundle from the current bundle. @@ -43,13 +43,13 @@ export function replaceURLReferences({ let replacements = new Map(); let urlDependencies = []; bundle.traverse(node => { - if (node.type === 'dependency' && node.value.isURL) { + if (node.type === 'dependency' && node.value.specifierType === 'url') { urlDependencies.push(node.value); } }); for (let dependency of urlDependencies) { - if (!dependency.isURL) { + if (dependency.specifierType !== 'url') { continue; } @@ -57,7 +57,7 @@ export function replaceURLReferences({ if (resolved == null) { replacements.set(dependency.id, { from: dependency.id, - to: dependency.moduleSpecifier, + to: dependency.specifier, }); continue; } diff --git a/packages/core/utils/test/replaceBundleReferences.test.js b/packages/core/utils/test/replaceBundleReferences.test.js index ccd5a35179c..e6610b2f282 100644 --- a/packages/core/utils/test/replaceBundleReferences.test.js +++ b/packages/core/utils/test/replaceBundleReferences.test.js @@ -33,7 +33,8 @@ describe('replace bundle references', () => { // $FlowFixMe let dependency: Dependency = { id: '074b36596e3147e900a8ad17ceb5c90b', - moduleSpecifier: 'url:./image.jpg?as=webp', + specifier: 'url:./image.jpg?as=webp', + specifierType: 'esm', }; let result = getURLReplacement({ @@ -77,7 +78,8 @@ describe('replace bundle references', () => { // $FlowFixMe let dependency: Dependency = { id: '074b36596e3147e900a8ad17ceb5c90b', - moduleSpecifier: 'url:./image.jpg?as=webp', + specifier: 'url:./image.jpg?as=webp', + specifierType: 'esm', }; let result = getURLReplacement({ @@ -121,7 +123,8 @@ describe('replace bundle references', () => { // $FlowFixMe let dependency: Dependency = { id: '074b36596e314797845a8ad17ceb5c9b', - moduleSpecifier: './image.jpg', + specifier: './image.jpg', + specifierType: 'esm', }; let result = getURLReplacement({ @@ -165,7 +168,8 @@ describe('replace bundle references', () => { // $FlowFixMe let dependency: Dependency = { id: '074b36596e3147e900a8ad17ceb5c90b', - moduleSpecifier: 'url:./image.jpg?as=webp', + specifier: 'url:./image.jpg?as=webp', + specifierType: 'esm', }; let result = getURLReplacement({ diff --git a/packages/packagers/css/src/CSSPackager.js b/packages/packagers/css/src/CSSPackager.js index 55e131988af..8ecde7672db 100644 --- a/packages/packagers/css/src/CSSPackager.js +++ b/packages/packagers/css/src/CSSPackager.js @@ -153,7 +153,7 @@ async function processCSSModule( }, }), hints: [ - `Instead do: import * as style from "${defaultImport.moduleSpecifier}";`, + `Instead do: import * as style from "${defaultImport.specifier}";`, ], }); } diff --git a/packages/packagers/html/src/HTMLPackager.js b/packages/packagers/html/src/HTMLPackager.js index 4bf32f57c36..e22470a7239 100644 --- a/packages/packagers/html/src/HTMLPackager.js +++ b/packages/packagers/html/src/HTMLPackager.js @@ -27,7 +27,18 @@ const metadataContent = new Set([ ]); export default (new Packager({ - async package({bundle, bundleGraph, getInlineBundleContents}) { + async loadConfig({config}) { + let posthtmlConfig = await config.getConfig( + ['.posthtmlrc', '.posthtmlrc.js', 'posthtml.config.js'], + { + packageKey: 'posthtml', + }, + ); + config.setResult({ + render: posthtmlConfig?.contents?.render, + }); + }, + async package({bundle, bundleGraph, getInlineBundleContents, config}) { let assets = []; bundle.traverseAssets(asset => { assets.push(asset); @@ -46,13 +57,7 @@ export default (new Packager({ new Set(bundleGraph.getReferencedBundles(bundle, {recursive: false})), ), ].filter(b => !b.isInline); - let posthtmlConfig = await asset.getConfig( - ['.posthtmlrc', '.posthtmlrc.js', 'posthtml.config.js'], - { - packageKey: 'posthtml', - }, - ); - let renderConfig = posthtmlConfig?.render; + let renderConfig = config?.render; let {html} = await posthtml([ insertBundleReferences.bind(this, referencedBundles), diff --git a/packages/packagers/js/src/DevPackager.js b/packages/packagers/js/src/DevPackager.js index 2b5f3abab66..d3d3ef05834 100644 --- a/packages/packagers/js/src/DevPackager.js +++ b/packages/packagers/js/src/DevPackager.js @@ -90,9 +90,7 @@ export class DevPackager { this.bundle, ); if (resolved) { - deps[dep.moduleSpecifier] = this.bundleGraph.getAssetPublicId( - resolved, - ); + deps[dep.specifier] = this.bundleGraph.getAssetPublicId(resolved); } } diff --git a/packages/packagers/js/src/ScopeHoistingPackager.js b/packages/packagers/js/src/ScopeHoistingPackager.js index 1b1b17847b5..e019ae7f823 100644 --- a/packages/packagers/js/src/ScopeHoistingPackager.js +++ b/packages/packagers/js/src/ScopeHoistingPackager.js @@ -498,7 +498,7 @@ ${code} let depMap = new Map(); let replacements = new Map(); for (let dep of deps) { - depMap.set(`${assetId}:${dep.moduleSpecifier}`, dep); + depMap.set(`${assetId}:${dep.specifier}`, dep); let asyncResolution = this.bundleGraph.resolveAsyncDependency( dep, @@ -531,7 +531,7 @@ ${code} renamed = local; } else if (imported === 'default' || imported === '*') { renamed = this.getTopLevelName( - `$${this.bundle.publicId}$${dep.moduleSpecifier}`, + `$${this.bundle.publicId}$${dep.specifier}`, ); } else { renamed = this.getTopLevelName( @@ -568,7 +568,7 @@ ${code} // Async dependencies need a namespace object even if all used symbols were statically analyzed. // This is recorded in the promiseSymbol meta property set by the transformer rather than in // symbols so that we don't mark all symbols as used. - if (dep.isAsync && dep.meta.promiseSymbol) { + if (dep.priority === 'lazy' && dep.meta.promiseSymbol) { let promiseSymbol = dep.meta.promiseSymbol; invariant(typeof promiseSymbol === 'string'); let symbol = this.resolveSymbol(asset, resolved, '*', dep); @@ -616,11 +616,11 @@ ${code} }); } - // Map of ModuleSpecifier -> Map> - let external = this.externals.get(dep.moduleSpecifier); + // Map of DependencySpecifier -> Map> + let external = this.externals.get(dep.specifier); if (!external) { external = new Map(); - this.externals.set(dep.moduleSpecifier, external); + this.externals.set(dep.specifier, external); } return external; @@ -893,7 +893,7 @@ ${code} if (!resolved) { // Re-exporting an external module. This should have already been handled in buildReplacements. let external = nullthrows( - nullthrows(this.externals.get(dep.moduleSpecifier)).get('*'), + nullthrows(this.externals.get(dep.specifier)).get('*'), ); append += `$parcel$exportWildcard($${assetId}$exports, ${external});\n`; this.usedHelpers.add('$parcel$exportWildcard'); diff --git a/packages/reporters/dev-server/src/HMRServer.js b/packages/reporters/dev-server/src/HMRServer.js index a5cfec870ba..7aaeb129425 100644 --- a/packages/reporters/dev-server/src/HMRServer.js +++ b/packages/reporters/dev-server/src/HMRServer.js @@ -110,7 +110,7 @@ export default class HMRServer { bundle, ); if (resolved) { - deps[dep.moduleSpecifier] = event.bundleGraph.getAssetPublicId( + deps[dep.specifier] = event.bundleGraph.getAssetPublicId( resolved, ); } diff --git a/packages/resolvers/default/src/DefaultResolver.js b/packages/resolvers/default/src/DefaultResolver.js index eeaaf7c0eea..a2b85d95220 100644 --- a/packages/resolvers/default/src/DefaultResolver.js +++ b/packages/resolvers/default/src/DefaultResolver.js @@ -9,9 +9,9 @@ const WEBPACK_IMPORT_REGEX = /\S+-loader\S*!\S+/g; export default (new Resolver({ resolve({dependency, options, filePath}) { - if (WEBPACK_IMPORT_REGEX.test(dependency.moduleSpecifier)) { + if (WEBPACK_IMPORT_REGEX.test(dependency.specifier)) { throw new Error( - `The import path: ${dependency.moduleSpecifier} is using webpack specific loader import syntax, which isn't supported by Parcel.`, + `The import path: ${dependency.specifier} is using webpack specific loader import syntax, which isn't supported by Parcel.`, ); } @@ -34,7 +34,7 @@ export default (new Resolver({ return resolver.resolve({ filename: filePath, - isURL: dependency.isURL, + isURL: dependency.specifierType === 'url', parent: dependency.resolveFrom, env: dependency.env, }); diff --git a/packages/resolvers/glob/src/GlobResolver.js b/packages/resolvers/glob/src/GlobResolver.js index 4700168d1aa..7c1af42e37d 100644 --- a/packages/resolvers/glob/src/GlobResolver.js +++ b/packages/resolvers/glob/src/GlobResolver.js @@ -20,7 +20,10 @@ export default (new Resolver({ let error; if (sourceAssetType !== 'js' && sourceAssetType !== 'css') { error = `Glob imports are not supported in ${sourceAssetType} files.`; - } else if (dependency.isURL) { + } else if ( + dependency.specifierType === 'url' && + !dependency.meta?.isCSSImport + ) { error = 'Glob imports are not supported in URL dependencies.'; } @@ -72,7 +75,7 @@ export default (new Resolver({ set(matches, parts, relative); } - let {value, imports} = generate(matches, dependency.isAsync); + let {value, imports} = generate(matches, dependency.priority === 'lazy'); code = imports + 'module.exports = ' + value; } else if (sourceAssetType === 'css') { for (let [, relative] of results) { @@ -88,7 +91,7 @@ export default (new Resolver({ code, invalidateOnFileCreate: [{glob: normalized}], pipeline: null, - isAsync: false, + priority: 'sync', }; }, }): Resolver); diff --git a/packages/runtimes/js/src/JSRuntime.js b/packages/runtimes/js/src/JSRuntime.js index a80ece51939..3d3f2702e4c 100644 --- a/packages/runtimes/js/src/JSRuntime.js +++ b/packages/runtimes/js/src/JSRuntime.js @@ -144,14 +144,12 @@ export default (new Runtime({ // Otherwise, try to resolve the dependency to an external bundle group // and insert a URL to that bundle. let resolved = bundleGraph.resolveAsyncDependency(dependency, bundle); - if (dependency.isURL && resolved == null) { + if (dependency.specifierType === 'url' && resolved == null) { // If a URL dependency was not able to be resolved, add a runtime that - // exports the original moduleSpecifier. + // exports the original specifier. assets.push({ filePath: __filename, - code: `module.exports = ${JSON.stringify( - dependency.moduleSpecifier, - )}`, + code: `module.exports = ${JSON.stringify(dependency.specifier)}`, dependency, }); continue; @@ -255,7 +253,10 @@ function getDependencies( } let dependency = node.value; - if (dependency.isAsync && !dependency.isURL) { + if ( + dependency.priority === 'lazy' && + dependency.specifierType !== 'url' + ) { asyncDependencies.push(dependency); } else { otherDependencies.push(dependency); diff --git a/packages/runtimes/react-refresh/package.json b/packages/runtimes/react-refresh/package.json index 2bddee46b7c..574a9c7d767 100644 --- a/packages/runtimes/react-refresh/package.json +++ b/packages/runtimes/react-refresh/package.json @@ -21,6 +21,7 @@ }, "dependencies": { "@parcel/plugin": "2.0.0-beta.3.1", + "@parcel/utils": "2.0.0-beta.3.1", "react-refresh": "^0.9.0" } } diff --git a/packages/runtimes/react-refresh/src/ReactRefreshRuntime.js b/packages/runtimes/react-refresh/src/ReactRefreshRuntime.js index 56c717618a0..1f223542600 100644 --- a/packages/runtimes/react-refresh/src/ReactRefreshRuntime.js +++ b/packages/runtimes/react-refresh/src/ReactRefreshRuntime.js @@ -1,6 +1,7 @@ // @flow strict-local import {Runtime} from '@parcel/plugin'; +import {loadConfig} from '@parcel/utils'; const CODE = ` var Refresh = require('react-refresh/runtime'); @@ -27,11 +28,17 @@ export default (new Runtime({ let entries = bundle.getEntryAssets(); for (let entry of entries) { - let pkg = await entry.getPackage(); + // TODO: do this in loadConfig - but it doesn't have access to the bundle... + let pkg = await loadConfig( + options.inputFS, + entry.filePath, + ['package.json'], + options.projectRoot, + ); if ( - pkg?.dependencies?.react || - pkg?.devDependencies?.react || - pkg?.peerDependencies?.react + pkg?.config?.dependencies?.react || + pkg?.config?.devDependencies?.react || + pkg?.config?.peerDependencies?.react ) { return { filePath: __filename, diff --git a/packages/transformers/babel/src/config.js b/packages/transformers/babel/src/config.js index f96f182ec58..efc4560954c 100644 --- a/packages/transformers/babel/src/config.js +++ b/packages/transformers/babel/src/config.js @@ -72,7 +72,7 @@ export async function load( }, ); config.addDevDependency({ - moduleSpecifier: '@babel/core', + specifier: '@babel/core', resolveFrom: config.searchPath, range: BABEL_CORE_RANGE, }); @@ -108,7 +108,7 @@ export async function load( // But also add the config as a dev dependency so we can at least attempt invalidation in watch mode. config.addDevDependency({ - moduleSpecifier: relativePath(options.projectRoot, file), + specifier: relativePath(options.projectRoot, file), resolveFrom: path.join(options.projectRoot, 'index'), // Also invalidate @parcel/transformer-babel when the config or a dependency updates. // This ensures that the caches in @babel/core are also invalidated. @@ -252,10 +252,7 @@ function definePluginDependencies(config, options) { // from the config location because configItem.file.request can be a shorthand // rather than a full package name. config.addDevDependency({ - moduleSpecifier: relativePath( - options.projectRoot, - configItem.file.resolved, - ), + specifier: relativePath(options.projectRoot, configItem.file.resolved), resolveFrom: path.join(options.projectRoot, 'index'), // Also invalidate @parcel/transformer-babel when the plugin or a dependency updates. // This ensures that the caches in @babel/core are also invalidated. diff --git a/packages/transformers/css/src/CSSTransformer.js b/packages/transformers/css/src/CSSTransformer.js index 16ee55bc5d7..ab463c89807 100644 --- a/packages/transformers/css/src/CSSTransformer.js +++ b/packages/transformers/css/src/CSSTransformer.js @@ -99,7 +99,7 @@ export default (new Transformer({ program.walkAtRules('import', rule => { let params = valueParser(rule.params); let [name, ...media] = params.nodes; - let moduleSpecifier; + let specifier; if ( name.type === 'function' && name.value === 'url' && @@ -108,14 +108,14 @@ export default (new Transformer({ name = name.nodes[0]; } - moduleSpecifier = name.value; + specifier = name.value; - if (!moduleSpecifier) { + if (!specifier) { throw new Error('Could not find import name for ' + String(rule)); } - if (isURL(moduleSpecifier)) { - name.value = asset.addURLDependency(moduleSpecifier, { + if (isURL(specifier)) { + name.value = asset.addURLDependency(specifier, { loc: createLoc(nullthrows(rule.source.start), asset.filePath, 0, 8), }); } else { @@ -129,10 +129,13 @@ export default (new Transformer({ // } else { media = valueParser.stringify(media).trim(); let dep = { - moduleSpecifier, + specifier, + specifierType: 'url', // Offset by 8 as it does not include `@import ` - loc: createLoc(nullthrows(rule.source.start), moduleSpecifier, 0, 8), + loc: createLoc(nullthrows(rule.source.start), specifier, 0, 8), meta: { + // For the glob resolver to distinguish between `@import` and other URL dependencies. + isCSSImport: true, media, }, }; diff --git a/packages/transformers/html/src/HTMLTransformer.js b/packages/transformers/html/src/HTMLTransformer.js index e8a2e2166bd..f5fb450b287 100644 --- a/packages/transformers/html/src/HTMLTransformer.js +++ b/packages/transformers/html/src/HTMLTransformer.js @@ -26,6 +26,7 @@ export default (new Transformer({ async transform({asset, options}) { // Handle .htm asset.type = 'html'; + asset.isIsolated = true; let ast = nullthrows(await asset.getAST()); let hasScripts = collectDependencies(asset, ast); @@ -44,9 +45,7 @@ export default (new Transformer({ tag: 'script', attrs: { src: asset.addURLDependency('hmr.js', { - isAsync: false, - isEntry: false, - isIsolated: true, + priority: 'parallel', }), }, content: [], diff --git a/packages/transformers/html/src/dependencies.js b/packages/transformers/html/src/dependencies.js index 023d9e4a7d2..8450753c9cb 100644 --- a/packages/transformers/html/src/dependencies.js +++ b/packages/transformers/html/src/dependencies.js @@ -67,27 +67,23 @@ const META = { // Options to be passed to `addDependency` for certain tags + attributes const OPTIONS = { a: { - href: {isEntry: true}, + href: {needsStableName: true}, }, iframe: { - src: {isEntry: true}, + src: {needsStableName: true}, }, link(attrs) { if (attrs.rel === 'stylesheet') { return { // Keep in the same bundle group as the HTML. - isAsync: false, - isEntry: false, - isIsolated: true, + priority: 'parallel', }; } }, script(attrs, env: Environment) { return { // Keep in the same bundle group as the HTML. - isAsync: false, - isEntry: false, - isIsolated: true, + priority: 'parallel', env: { outputFormat: attrs.type === 'module' && env.shouldScopeHoist @@ -155,7 +151,7 @@ export default function collectDependencies( attrs.href ) { attrs.href = asset.addURLDependency(attrs.href, { - isEntry: true, + needsStableName: true, }); isDirty = true; return node; diff --git a/packages/transformers/html/src/inline.js b/packages/transformers/html/src/inline.js index f4e55f4e40c..844ef4c7a64 100644 --- a/packages/transformers/html/src/inline.js +++ b/packages/transformers/html/src/inline.js @@ -92,7 +92,8 @@ export default function extractInlineAssets( asset.setAST(ast); // mark dirty asset.addDependency({ - moduleSpecifier: parcelKey, + specifier: parcelKey, + specifierType: 'esm', }); parts.push({ @@ -100,6 +101,7 @@ export default function extractInlineAssets( content: value, uniqueKey: parcelKey, isInline: true, + isIsolated: false, env, meta: { type: 'tag', @@ -119,7 +121,8 @@ export default function extractInlineAssets( let style = attrs?.style; if (attrs != null && style != null) { attrs.style = asset.addDependency({ - moduleSpecifier: parcelKey, + specifier: parcelKey, + specifierType: 'esm', }); asset.setAST(ast); // mark dirty @@ -128,6 +131,7 @@ export default function extractInlineAssets( content: style, uniqueKey: parcelKey, isInline: true, + isIsolated: false, meta: { type: 'attr', // $FlowFixMe diff --git a/packages/transformers/js/src/JSTransformer.js b/packages/transformers/js/src/JSTransformer.js index d3a52a5a309..0fc0c109cf6 100644 --- a/packages/transformers/js/src/JSTransformer.js +++ b/packages/transformers/js/src/JSTransformer.js @@ -324,7 +324,7 @@ export default (new Transformer({ } else if (dep.kind === 'ServiceWorker') { asset.addURLDependency(dep.specifier, { loc: convertLoc(dep.loc), - isEntry: true, + needsStableName: true, env: {context: 'service-worker'}, }); } else if (dep.kind === 'ImportScripts') { @@ -350,9 +350,10 @@ export default (new Transformer({ } asset.addDependency({ - moduleSpecifier: dep.specifier, + specifier: dep.specifier, + specifierType: dep.kind === 'Require' ? 'commonjs' : 'esm', loc: convertLoc(dep.loc), - isAsync: dep.kind === 'DynamicImport', + priority: dep.kind === 'DynamicImport' ? 'lazy' : 'sync', isOptional: dep.is_optional, meta, resolveFrom: dep.is_helper ? __filename : undefined, @@ -368,28 +369,21 @@ export default (new Transformer({ } let deps = new Map( - asset.getDependencies().map(dep => [dep.moduleSpecifier, dep]), + asset.getDependencies().map(dep => [dep.specifier, dep]), ); for (let dep of deps.values()) { dep.symbols.ensure(); } for (let name in hoist_result.imported_symbols) { - let [moduleSpecifier, exported, loc] = hoist_result.imported_symbols[ - name - ]; - let dep = deps.get(moduleSpecifier); + let [specifier, exported, loc] = hoist_result.imported_symbols[name]; + let dep = deps.get(specifier); if (!dep) continue; dep.symbols.set(exported, name, convertLoc(loc)); } - for (let [ - name, - moduleSpecifier, - exported, - loc, - ] of hoist_result.re_exports) { - let dep = deps.get(moduleSpecifier); + for (let [name, specifier, exported, loc] of hoist_result.re_exports) { + let dep = deps.get(specifier); if (!dep) continue; if (name === '*' && exported === '*') { @@ -403,8 +397,8 @@ export default (new Transformer({ } } - for (let moduleSpecifier of hoist_result.wrapped_requires) { - let dep = deps.get(moduleSpecifier); + for (let specifier of hoist_result.wrapped_requires) { + let dep = deps.get(specifier); if (!dep) continue; dep.meta.shouldWrap = true; } @@ -435,7 +429,8 @@ export default (new Transformer({ } asset.addDependency({ - moduleSpecifier: `./${path.basename(asset.filePath)}`, + specifier: `./${path.basename(asset.filePath)}`, + specifierType: 'esm', symbols, }); } @@ -458,7 +453,8 @@ export default (new Transformer({ asset.meta.id = asset.id; } else if (needs_esm_helpers) { asset.addDependency({ - moduleSpecifier: '@parcel/transformer-js/src/esmodule-helpers.js', + specifier: '@parcel/transformer-js/src/esmodule-helpers.js', + specifierType: 'esm', resolveFrom: __filename, env: { includeNodeModules: { diff --git a/packages/transformers/postcss/src/PostCSSTransformer.js b/packages/transformers/postcss/src/PostCSSTransformer.js index 92e78de0866..fb2d5efd414 100644 --- a/packages/transformers/postcss/src/PostCSSTransformer.js +++ b/packages/transformers/postcss/src/PostCSSTransformer.js @@ -84,7 +84,8 @@ export default (new Transformer({ parsed.walk(node => { if (node.type === 'string') { asset.addDependency({ - moduleSpecifier: importPath, + specifier: importPath, + specifierType: 'url', loc: { filePath: asset.filePath, start: decl.source.start, @@ -129,12 +130,12 @@ export default (new Transformer({ let cssModulesList = (Object.entries(cssModules): Array< [string, string], >); - let deps = asset.getDependencies().filter(dep => !dep.isURL); + let deps = asset.getDependencies().filter(dep => dep.priority === 'sync'); let code: string; if (deps.length > 0) { code = ` module.exports = Object.assign({}, ${deps - .map(dep => `require(${JSON.stringify(dep.moduleSpecifier)})`) + .map(dep => `require(${JSON.stringify(dep.specifier)})`) .join(', ')}, ${JSON.stringify(cssModules, null, 2)}); `; } else { diff --git a/packages/transformers/postcss/src/loadConfig.js b/packages/transformers/postcss/src/loadConfig.js index 9947769fb23..1a529ccbbcf 100644 --- a/packages/transformers/postcss/src/loadConfig.js +++ b/packages/transformers/postcss/src/loadConfig.js @@ -64,7 +64,7 @@ async function configHydrator( for (let p of pluginArray) { if (typeof p === 'string') { config.addDevDependency({ - moduleSpecifier: p, + specifier: p, resolveFrom: nullthrows(resolveFrom), }); } @@ -98,7 +98,7 @@ export async function load({ let contents = null; if (configFile) { config.addDevDependency({ - moduleSpecifier: 'postcss', + specifier: 'postcss', resolveFrom: config.searchPath, range: POSTCSS_RANGE, }); @@ -117,7 +117,7 @@ export async function load({ // Also add the config as a dev dependency so we attempt to reload in watch mode. config.addDevDependency({ - moduleSpecifier: relativePath( + specifier: relativePath( path.dirname(config.searchPath), configFile.filePath, ), diff --git a/packages/transformers/posthtml/src/PostHTMLTransformer.js b/packages/transformers/posthtml/src/PostHTMLTransformer.js index c2fd9055a38..52bacbc4a72 100644 --- a/packages/transformers/posthtml/src/PostHTMLTransformer.js +++ b/packages/transformers/posthtml/src/PostHTMLTransformer.js @@ -34,7 +34,7 @@ export default (new Transformer({ // Also add the config as a dev dependency so we attempt to reload in watch mode. config.addDevDependency({ - moduleSpecifier: relativePath( + specifier: relativePath( path.dirname(config.searchPath), configFile.filePath, ), @@ -56,7 +56,7 @@ export default (new Transformer({ for (let p of pluginArray) { if (typeof p === 'string') { config.addDevDependency({ - moduleSpecifier: p, + specifier: p, resolveFrom: configFile.filePath, }); } diff --git a/packages/transformers/react-refresh-wrap/src/ReactRefreshWrapTransformer.js b/packages/transformers/react-refresh-wrap/src/ReactRefreshWrapTransformer.js index 4b1511869ea..ef62cec6914 100644 --- a/packages/transformers/react-refresh-wrap/src/ReactRefreshWrapTransformer.js +++ b/packages/transformers/react-refresh-wrap/src/ReactRefreshWrapTransformer.js @@ -13,7 +13,7 @@ function shouldExclude(asset, options) { !asset.env.isBrowser() || asset.env.isWorker() || options.mode !== 'development' || - !asset.getDependencies().find(v => v.moduleSpecifier === 'react') + !asset.getDependencies().find(v => v.specifier === 'react') ); } @@ -52,7 +52,8 @@ ${code} // The JSTransformer has already run, do it manually asset.addDependency({ - moduleSpecifier: wrapperPath, + specifier: wrapperPath, + specifierType: 'esm', }); return [asset]; diff --git a/packages/transformers/webextension/src/WebExtensionTransformer.js b/packages/transformers/webextension/src/WebExtensionTransformer.js index ce3456883a2..20c6ad9594f 100644 --- a/packages/transformers/webextension/src/WebExtensionTransformer.js +++ b/packages/transformers/webextension/src/WebExtensionTransformer.js @@ -74,7 +74,7 @@ async function collectDependencies( } for (const locale of await fs.readdir(locales)) { asset.addURLDependency(`_locales/${locale}/messages.json`, { - isEntry: true, + needsStableName: true, pipeline: 'url', }); } @@ -87,7 +87,7 @@ async function collectDependencies( const assets = sc[k] || []; for (let j = 0; j < assets.length; ++j) { assets[j] = asset.addURLDependency(assets[j], { - isEntry: true, + needsStableName: true, loc: { filePath, ...getJSONSourceLocation( @@ -139,11 +139,11 @@ async function collectDependencies( }); } program.dictionaries[dict] = asset.addURLDependency(dictFile, { - isEntry: true, + needsStableName: true, loc, }); asset.addURLDependency(dictFile.slice(0, -4) + '.aff', { - isEntry: true, + needsStableName: true, loc, }); } @@ -157,7 +157,7 @@ async function collectDependencies( 'value', ); themeIcon[k] = asset.addURLDependency(themeIcon[k], { - isEntry: true, + needsStableName: true, loc: { ...loc, filePath, @@ -181,7 +181,7 @@ async function collectDependencies( ) ).map(fp => asset.addURLDependency(path.relative(path.dirname(filePath), fp), { - isEntry: true, + needsStableName: true, loc: { filePath, ...getJSONSourceLocation(ptrs[`/web_accessible_resources/${i}`]), @@ -203,7 +203,7 @@ async function collectDependencies( const obj = parent[lastLoc]; if (typeof obj == 'string') parent[lastLoc] = asset.addURLDependency(obj, { - isEntry: true, + needsStableName: true, loc: { filePath, ...getJSONSourceLocation(ptrs[location], 'value'), @@ -213,7 +213,7 @@ async function collectDependencies( else { for (const k of Object.keys(obj)) { obj[k] = asset.addURLDependency(obj[k], { - isEntry: true, + needsStableName: true, loc: { filePath, ...getJSONSourceLocation(ptrs[location + '/' + k], 'value'), diff --git a/packages/validators/typescript/src/TypeScriptValidator.js b/packages/validators/typescript/src/TypeScriptValidator.js index 0a1b3e4f997..1c6274dff43 100644 --- a/packages/validators/typescript/src/TypeScriptValidator.js +++ b/packages/validators/typescript/src/TypeScriptValidator.js @@ -10,7 +10,7 @@ import type {LanguageService, Diagnostic} from 'typescript'; // eslint-disable-l import path from 'path'; import ts from 'typescript'; import {type DiagnosticCodeFrame, escapeMarkdown} from '@parcel/diagnostic'; -import {hashObject} from '@parcel/utils'; +import {hashObject, loadConfig} from '@parcel/utils'; import {Validator} from '@parcel/plugin'; import {LanguageServiceHost, ParseConfigHost} from '@parcel/ts-utils'; @@ -84,19 +84,25 @@ async function getConfig( resolveConfigWithPath, ): Promise { let configNames = ['tsconfig.json']; - let tsconfig = await asset.getConfig(configNames); + let tsconfig = await loadConfig( + asset.fs, + asset.filePath, + configNames, + options.projectRoot, + ); let configPath: ?string = await resolveConfigWithPath( configNames, asset.filePath, ); let baseDir = configPath ? path.dirname(configPath) : options.projectRoot; - let configHash = (tsconfig ? hashObject(tsconfig) : '') + '-' + baseDir; + let configHash = + (tsconfig ? hashObject(tsconfig.config) : '') + '-' + baseDir; return { filepath: configPath, baseDir, configHash, - tsconfig, + tsconfig: tsconfig?.config, }; } From 9c2a96fcbb2075fafeb65dd5b61cd3acbf72f361 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Thu, 10 Jun 2021 23:43:24 -0700 Subject: [PATCH 2/2] API audit: Refactor Asset API (#6421) --- .../bundlers/default/src/DefaultBundler.js | 23 +- packages/core/core/src/InternalConfig.js | 6 +- packages/core/core/src/UncommittedAsset.js | 16 +- packages/core/core/src/assetUtils.js | 14 +- packages/core/core/src/public/Asset.js | 49 +++-- packages/core/core/src/public/Config.js | 10 +- .../core/src/public/MutableBundleGraph.js | 8 +- .../core/core/src/requests/ConfigRequest.js | 16 +- packages/core/core/src/types.js | 16 +- packages/core/core/test/InternalAsset.test.js | 4 +- .../parcel-transformer-included/index.js | 2 +- packages/core/types/index.js | 196 +++++++++++++----- packages/packagers/js/src/DevPackager.js | 2 +- .../packagers/js/src/ScopeHoistingPackager.js | 4 +- packages/transformers/babel/src/config.js | 2 +- .../transformers/css/src/CSSTransformer.js | 6 - .../transformers/elm/src/ElmTransformer.js | 2 +- .../transformers/glsl/src/GLSLTransformer.js | 2 +- .../graphql/src/GraphQLTransformer.js | 2 +- .../transformers/html/src/HTMLTransformer.js | 2 +- packages/transformers/html/src/inline.js | 6 +- .../image/src/ImageTransformer.js | 2 +- .../src/InlineStringTransformer.js | 2 +- .../inline/src/InlineTransformer.js | 2 +- packages/transformers/js/src/JSTransformer.js | 8 +- .../transformers/less/src/LessTransformer.js | 2 +- .../postcss/src/PostCSSTransformer.js | 5 +- .../posthtml/src/PostHTMLTransformer.js | 2 +- .../transformers/pug/src/PugTransformer.js | 2 +- .../transformers/raw/src/RawTransformer.js | 2 +- .../transformers/sass/src/SassTransformer.js | 2 +- .../stylus/src/StylusTransformer.js | 2 +- .../src/TSTypesTransformer.js | 27 +-- packages/utils/ts-utils/src/loadTSConfig.js | 2 +- 34 files changed, 265 insertions(+), 183 deletions(-) diff --git a/packages/bundlers/default/src/DefaultBundler.js b/packages/bundlers/default/src/DefaultBundler.js index 12d7056564c..1b7f6598d00 100644 --- a/packages/bundlers/default/src/DefaultBundler.js +++ b/packages/bundlers/default/src/DefaultBundler.js @@ -71,14 +71,14 @@ export default (new Bundler({ let assets = bundleGraph.getDependencyAssets(dependency); let resolution = bundleGraph.getDependencyResolution(dependency); let bundleGroup = context?.bundleGroup; - // Create a new bundle for entries, lazy/parallel dependencies, isolated assets, and inline assets. + // Create a new bundle for entries, lazy/parallel dependencies, isolated/inline assets. if ( resolution && (!bundleGroup || dependency.priority === 'lazy' || dependency.priority === 'parallel' || - resolution.isIsolated || - resolution.isInline) + resolution.bundleBehavior === 'isolated' || + resolution.bundleBehavior === 'inline') ) { let bundleByType: Map = context?.bundleByType ?? new Map(); @@ -88,7 +88,7 @@ export default (new Bundler({ if ( !bundleGroup || dependency.priority === 'lazy' || - resolution.isIsolated + resolution.bundleBehavior === 'isolated' ) { bundleGroup = bundleGraph.createBundleGroup( dependency, @@ -101,10 +101,11 @@ export default (new Bundler({ for (let asset of assets) { let bundle = bundleGraph.createBundle({ entryAsset: asset, - isEntry: asset.isInline - ? false - : dependency.isEntry || dependency.needsStableName, - isInline: asset.isInline, + isEntry: + asset.bundleBehavior === 'inline' + ? false + : dependency.isEntry || dependency.needsStableName, + isInline: asset.bundleBehavior === 'inline', target: bundleGroup.target, }); bundleByType.set(bundle.type, bundle); @@ -158,13 +159,13 @@ export default (new Bundler({ type: asset.type, target: bundleGroup.target, isEntry: - asset.isInline || + asset.bundleBehavior === 'inline' || (dependency.priority === 'parallel' && !dependency.needsStableName) ? false : parentBundle.isEntry, - isInline: asset.isInline, - isSplittable: asset.isSplittable ?? true, + isInline: asset.bundleBehavior === 'inline', + isSplittable: asset.isBundleSplittable ?? true, pipeline: asset.pipeline, }); bundleByType.set(bundle.type, bundle); diff --git a/packages/core/core/src/InternalConfig.js b/packages/core/core/src/InternalConfig.js index b41be68b6a5..51056db5eca 100644 --- a/packages/core/core/src/InternalConfig.js +++ b/packages/core/core/src/InternalConfig.js @@ -17,7 +17,7 @@ type ConfigOpts = {| isSource?: boolean, env?: Environment, result?: ConfigResult, - includedFiles?: Set, + invalidateOnFileChange?: Set, invalidateOnFileCreate?: Array, invalidateOnOptionChange?: Set, devDeps?: Array, @@ -30,7 +30,7 @@ export function createConfig({ searchPath, env, result, - includedFiles, + invalidateOnFileChange, invalidateOnFileCreate, invalidateOnOptionChange, devDeps, @@ -44,7 +44,7 @@ export function createConfig({ env: environment, result: result ?? null, resultHash: null, - includedFiles: includedFiles ?? new Set(), + invalidateOnFileChange: invalidateOnFileChange ?? new Set(), invalidateOnFileCreate: invalidateOnFileCreate ?? [], invalidateOnOptionChange: invalidateOnOptionChange ?? new Set(), devDeps: devDeps ?? [], diff --git a/packages/core/core/src/UncommittedAsset.js b/packages/core/core/src/UncommittedAsset.js index bd9f0c92095..e11cb706afe 100644 --- a/packages/core/core/src/UncommittedAsset.js +++ b/packages/core/core/src/UncommittedAsset.js @@ -39,6 +39,7 @@ import { getInvalidationId, getInvalidationHash, } from './assetUtils'; +import {BundleBehaviorNames} from './types'; type UncommittedAssetOptions = {| value: Asset, @@ -320,7 +321,7 @@ export default class UncommittedAsset { return dep.id; } - addIncludedFile(filePath: FilePath) { + invalidateOnFileChange(filePath: FilePath) { let invalidation: RequestInvalidation = { type: 'file', filePath, @@ -364,11 +365,14 @@ export default class UncommittedAsset { hash: this.value.hash, filePath: this.value.filePath, type: result.type, - query: result.query, - isIsolated: result.isIsolated ?? this.value.isIsolated, - isInline: result.isInline ?? this.value.isInline, - isSplittable: result.isSplittable ?? this.value.isSplittable, - isSource: result.isSource ?? this.value.isSource, + bundleBehavior: + result.bundleBehavior ?? + (this.value.bundleBehavior == null + ? null + : BundleBehaviorNames[this.value.bundleBehavior]), + isBundleSplittable: + result.isBundleSplittable ?? this.value.isBundleSplittable, + isSource: this.value.isSource, env: mergeEnvironments(this.value.env, result.env), dependencies: this.value.type === result.type diff --git a/packages/core/core/src/assetUtils.js b/packages/core/core/src/assetUtils.js index 3bf54c2fb14..dd6b681d42e 100644 --- a/packages/core/core/src/assetUtils.js +++ b/packages/core/core/src/assetUtils.js @@ -2,6 +2,7 @@ import type { ASTGenerator, + BundleBehavior, FilePath, GenerateOutput, Meta, @@ -33,6 +34,7 @@ import {blobToStream, hashFile} from '@parcel/utils'; import {hashFromOption} from './utils'; import {createBuildCache} from './buildCache'; import {hashString} from '@parcel/hash'; +import {BundleBehavior as BundleBehaviorMap} from './types'; type AssetOptions = {| id?: string, @@ -47,9 +49,8 @@ type AssetOptions = {| astKey?: ?string, astGenerator?: ?ASTGenerator, dependencies?: Map, - isIsolated?: boolean, - isInline?: boolean, - isSplittable?: ?boolean, + bundleBehavior?: ?BundleBehavior, + isBundleSplittable?: ?boolean, isSource: boolean, env: Environment, meta?: Meta, @@ -90,9 +91,10 @@ export function createAsset(options: AssetOptions): Asset { hash: options.hash, filePath: options.filePath, query: options.query, - isIsolated: options.isIsolated ?? false, - isInline: options.isInline ?? false, - isSplittable: options.isSplittable, + bundleBehavior: options.bundleBehavior + ? BundleBehaviorMap[options.bundleBehavior] + : null, + isBundleSplittable: options.isBundleSplittable ?? true, type: options.type, contentKey: options.contentKey, mapKey: options.mapKey, diff --git a/packages/core/core/src/public/Asset.js b/packages/core/core/src/public/Asset.js index c7adc45ec0a..9c9dbda23dc 100644 --- a/packages/core/core/src/public/Asset.js +++ b/packages/core/core/src/public/Asset.js @@ -20,6 +20,7 @@ import type { MutableAssetSymbols as IMutableAssetSymbols, AssetSymbols as IAssetSymbols, QueryParameters, + BundleBehavior, } from '@parcel/types'; import type {Asset as AssetValue, ParcelOptions} from '../types'; @@ -30,6 +31,10 @@ import {AssetSymbols, MutableAssetSymbols} from './Symbols'; import UncommittedAsset from '../UncommittedAsset'; import CommittedAsset from '../CommittedAsset'; import {createEnvironment} from '../Environment'; +import { + BundleBehavior as BundleBehaviorMap, + BundleBehaviorNames, +} from '../types'; const inspect = Symbol.for('nodejs.util.inspect.custom'); @@ -115,16 +120,13 @@ class BaseAsset { return this.#asset.value.meta; } - get isIsolated(): boolean { - return this.#asset.value.isIsolated; + get bundleBehavior(): ?BundleBehavior { + let bundleBehavior = this.#asset.value.bundleBehavior; + return bundleBehavior == null ? null : BundleBehaviorNames[bundleBehavior]; } - get isInline(): boolean { - return this.#asset.value.isInline; - } - - get isSplittable(): ?boolean { - return this.#asset.value.isSplittable; + get isBundleSplittable(): boolean { + return this.#asset.value.isBundleSplittable; } get isSource(): boolean { @@ -234,28 +236,31 @@ export class MutableAsset extends BaseAsset implements IMutableAsset { } } - get isIsolated(): boolean { - return this.#asset.value.isIsolated; + get bundleBehavior(): ?BundleBehavior { + let bundleBehavior = this.#asset.value.bundleBehavior; + return bundleBehavior == null ? null : BundleBehaviorNames[bundleBehavior]; } - set isIsolated(isIsolated: boolean): void { - this.#asset.value.isIsolated = isIsolated; + set bundleBehavior(bundleBehavior: ?BundleBehavior): void { + this.#asset.value.bundleBehavior = bundleBehavior + ? BundleBehaviorMap[bundleBehavior] + : null; } - get isInline(): boolean { - return this.#asset.value.isInline; + get isBundleSplittable(): boolean { + return this.#asset.value.isBundleSplittable; } - set isInline(isInline: boolean): void { - this.#asset.value.isInline = isInline; + set isBundleSplittable(isBundleSplittable: boolean): void { + this.#asset.value.isBundleSplittable = isBundleSplittable; } - get isSplittable(): ?boolean { - return this.#asset.value.isSplittable; + get sideEffects(): boolean { + return this.#asset.value.sideEffects; } - set isSplittable(isSplittable: ?boolean): void { - this.#asset.value.isSplittable = isSplittable; + set sideEffects(sideEffects: boolean): void { + this.#asset.value.sideEffects = sideEffects; } get symbols(): IMutableAssetSymbols { @@ -266,8 +271,8 @@ export class MutableAsset extends BaseAsset implements IMutableAsset { return this.#asset.addDependency(dep); } - addIncludedFile(filePath: FilePath): void { - this.#asset.addIncludedFile(filePath); + invalidateOnFileChange(filePath: FilePath): void { + this.#asset.invalidateOnFileChange(filePath); } invalidateOnFileCreate(invalidation: FileCreateInvalidation): void { diff --git a/packages/core/core/src/public/Config.js b/packages/core/core/src/public/Config.js index 73fcede3797..0ece1e6fc2c 100644 --- a/packages/core/core/src/public/Config.js +++ b/packages/core/core/src/public/Config.js @@ -52,10 +52,6 @@ export default class PublicConfig implements IConfig { return this.#config.isSource; } - get includedFiles(): Set { - return this.#config.includedFiles; - } - // $FlowFixMe setResult(result: any): void { this.#config.result = result; @@ -65,8 +61,8 @@ export default class PublicConfig implements IConfig { this.#config.resultHash = resultHash; } - addIncludedFile(filePath: FilePath) { - this.#config.includedFiles.add(filePath); + invalidateOnFileChange(filePath: FilePath) { + this.#config.invalidateOnFileChange.add(filePath); } addDevDependency(devDep: DevDepOptions) { @@ -127,7 +123,7 @@ export default class PublicConfig implements IConfig { let configFilePath = conf.files[0].filePath; if (!options || !options.exclude) { - this.addIncludedFile(configFilePath); + this.invalidateOnFileChange(configFilePath); } return { diff --git a/packages/core/core/src/public/MutableBundleGraph.js b/packages/core/core/src/public/MutableBundleGraph.js index 2a8686e9a4e..fb6442ea2cf 100644 --- a/packages/core/core/src/public/MutableBundleGraph.js +++ b/packages/core/core/src/public/MutableBundleGraph.js @@ -24,6 +24,7 @@ import Dependency, {dependencyToInternalDependency} from './Dependency'; import {environmentToInternalEnvironment} from './Environment'; import {targetToInternalTarget} from './Target'; import {HASH_REF_PREFIX} from '../constants'; +import {BundleBehavior} from '../types'; export default class MutableBundleGraph extends BundleGraph implements IMutableBundleGraph { @@ -107,7 +108,10 @@ export default class MutableBundleGraph extends BundleGraph this.#graph._graph.addEdge(dependencyNodeId, resolvedNodeId, 'references'); this.#graph._graph.removeEdge(dependencyNodeId, resolvedNodeId); - if (dependency.isEntry || resolved.isIsolated) { + if ( + dependency.isEntry || + resolved.bundleBehavior === BundleBehavior.isolated + ) { this.#graph._graph.addEdge( nullthrows(this.#graph._graph.rootNodeId), bundleGroupNodeId, @@ -191,7 +195,7 @@ export default class MutableBundleGraph extends BundleGraph pipeline: opts.pipeline ?? entryAsset?.pipeline, isEntry: opts.isEntry, isInline: opts.isInline, - isSplittable: opts.isSplittable ?? entryAsset?.isSplittable, + isSplittable: opts.isSplittable ?? entryAsset?.isBundleSplittable, isPlaceholder, target, name: null, diff --git a/packages/core/core/src/requests/ConfigRequest.js b/packages/core/core/src/requests/ConfigRequest.js index 23c42c383bf..eadf0ab0650 100644 --- a/packages/core/core/src/requests/ConfigRequest.js +++ b/packages/core/core/src/requests/ConfigRequest.js @@ -30,7 +30,7 @@ export type PluginWithLoadConfig = { export type ConfigRequest = { id: string, - includedFiles: Set, + invalidateOnFileChange: Set, invalidateOnFileCreate: Array, invalidateOnOptionChange: Set, shouldInvalidateOnStartup: boolean, @@ -71,7 +71,7 @@ export async function runConfigRequest( configRequest: ConfigRequest, ) { let { - includedFiles, + invalidateOnFileChange, invalidateOnFileCreate, invalidateOnOptionChange, shouldInvalidateOnStartup, @@ -79,7 +79,7 @@ export async function runConfigRequest( // If there are no invalidations, then no need to create a node. if ( - includedFiles.size === 0 && + invalidateOnFileChange.size === 0 && invalidateOnFileCreate.length === 0 && invalidateOnOptionChange.size === 0 && !shouldInvalidateOnStartup @@ -91,7 +91,7 @@ export async function runConfigRequest( id: 'config_request:' + configRequest.id, type: 'config_request', run: ({api}) => { - for (let filePath of includedFiles) { + for (let filePath of invalidateOnFileChange) { api.invalidateOnFileUpdate(filePath); api.invalidateOnFileDelete(filePath); } @@ -127,10 +127,10 @@ export async function getConfigHash( // If there is no result hash set by the transformer, default to hashing the included // files if any, otherwise try to hash the config result itself. if (config.resultHash == null) { - if (config.includedFiles.size > 0) { + if (config.invalidateOnFileChange.size > 0) { hash.writeString( await getInvalidationHash( - [...config.includedFiles].map(filePath => ({ + [...config.invalidateOnFileChange].map(filePath => ({ type: 'file', filePath, })), @@ -164,7 +164,7 @@ export function getConfigRequests( .filter(config => { // No need to send to the graph if there are no invalidations. return ( - config.includedFiles.size > 0 || + config.invalidateOnFileChange.size > 0 || config.invalidateOnFileCreate.length > 0 || config.invalidateOnOptionChange.size > 0 || config.shouldInvalidateOnStartup @@ -172,7 +172,7 @@ export function getConfigRequests( }) .map(config => ({ id: config.id, - includedFiles: config.includedFiles, + invalidateOnFileChange: config.invalidateOnFileChange, invalidateOnFileCreate: config.invalidateOnFileCreate, invalidateOnOptionChange: config.invalidateOnOptionChange, shouldInvalidateOnStartup: config.shouldInvalidateOnStartup, diff --git a/packages/core/core/src/types.js b/packages/core/core/src/types.js index 3ac827518d4..fc2b9d1eabe 100644 --- a/packages/core/core/src/types.js +++ b/packages/core/core/src/types.js @@ -121,6 +121,15 @@ export type Dependency = {| pipeline?: ?string, |}; +export const BundleBehavior = { + inline: 0, + isolated: 1, +}; + +export const BundleBehaviorNames: Array< + $Keys, +> = Object.keys(BundleBehavior); + export type Asset = {| id: ContentKey, committed: boolean, @@ -129,9 +138,8 @@ export type Asset = {| query: ?QueryParameters, type: string, dependencies: Map, - isIsolated: boolean, - isInline: boolean, - isSplittable: ?boolean, + bundleBehavior: ?$Values, + isBundleSplittable: boolean, isSource: boolean, env: Environment, meta: Meta, @@ -381,7 +389,7 @@ export type Config = {| env: Environment, resultHash: ?string, result: ConfigResult, - includedFiles: Set, + invalidateOnFileChange: Set, invalidateOnFileCreate: Array, invalidateOnOptionChange: Set, devDeps: Array, diff --git a/packages/core/core/test/InternalAsset.test.js b/packages/core/core/test/InternalAsset.test.js index 822571f0f99..1dbb732b393 100644 --- a/packages/core/core/test/InternalAsset.test.js +++ b/packages/core/core/test/InternalAsset.test.js @@ -20,8 +20,8 @@ describe('InternalAsset', () => { }), options: DEFAULT_OPTIONS, }); - asset.addIncludedFile('/foo/file'); - asset.addIncludedFile('/foo/file'); + asset.invalidateOnFileChange('/foo/file'); + asset.invalidateOnFileChange('/foo/file'); assert.deepEqual(asset.getInvalidations(), [ { type: 'file', diff --git a/packages/core/integration-tests/test/integration/included-file/node_modules/parcel-transformer-included/index.js b/packages/core/integration-tests/test/integration/included-file/node_modules/parcel-transformer-included/index.js index 65195c12c33..e7f12e743cb 100644 --- a/packages/core/integration-tests/test/integration/included-file/node_modules/parcel-transformer-included/index.js +++ b/packages/core/integration-tests/test/integration/included-file/node_modules/parcel-transformer-included/index.js @@ -4,7 +4,7 @@ const path = require("path"); module.exports = new Transformer({ async transform({ asset, options }) { let file = path.join(path.dirname(asset.filePath), "included.txt"); - asset.addIncludedFile(file); + asset.invalidateOnFileChange(file); let content = await options.inputFS.readFile(file, "utf8"); asset.setCode(content); return [asset]; diff --git a/packages/core/types/index.js b/packages/core/types/index.js index 1e680c9dc74..890ab9ba2aa 100644 --- a/packages/core/types/index.js +++ b/packages/core/types/index.js @@ -569,93 +569,150 @@ export type File = {| */ export type ASTGenerator = {| type: string, - version: string, + version: Semver, |}; +export type BundleBehavior = 'inline' | 'isolated'; + /** - * An asset (usually represents one source file). + * An asset represents a file or part of a file. It may represent any data type, including source code, + * binary data, etc. Assets may exist in the file system or may be virtual. * * @section transformer */ export interface BaseAsset { - +env: Environment; + /** The id of the asset. */ + +id: string; /** The file system where the source is located. */ +fs: FileSystem; + /** The file path of the asset. */ +filePath: FilePath; + /** + * The asset's type. This initially corresponds to the source file extension, + * but it may be changed during transformation. + */ + +type: string; + /** The transformer options for the asset from the dependency query string. */ +query: QueryParameters; - +id: string; - +meta: Meta; - +isIsolated: boolean; - /** Whether this asset will/should later be inserted back into the importer. */ - +isInline: boolean; - +isSplittable: ?boolean; - /** Whether this is asset is part of the users project (and not of an external dependencies) and should be transpiled. */ + /** The environment of the asset. */ + +env: Environment; + /** + * Whether this asset is part of the project, and not an external dependency (e.g. in node_modules). + * This indicates that transformation using the project's configuration should be applied. + */ +isSource: boolean; - /** Usually corresponds to the file extension */ - +type: string; - /** Whether this asset can be omitted if none of its exports are being used (set by ResolveResult) */ + /** Plugin-specific metadata for the asset. */ + +meta: Meta; + /** + * Controls which bundle the asset is placed into. + * - inline: The asset will be placed into a new inline bundle. Inline bundles are not written + * to a separate file, but embedded into the parent bundle. + * - isolated: The asset will be placed into a separate bundle. + */ + +bundleBehavior: ?BundleBehavior; + /** + * If the asset is used as a bundle entry, this controls whether that bundle can be split + * into multiple, or whether all of the dependencies must be placed in a single bundle. + */ + +isBundleSplittable: boolean; + /** + * Whether this asset can be omitted if none of its exports are being used. + * This is initially set by the resolver, but can be overridden by transformers. + */ +sideEffects: boolean; /** - * Inline assets inheirit the parent's id, making it not be enough for a unique identification - * (this could be a counter that is unique per asset) + * When a transformer returns multiple assets, it can give them unique keys to identify them. + * This can be used to find assets during packaging, or to create dependencies between multiple + * assets returned by a transformer by using the unique key as the dependency specifier. */ +uniqueKey: ?string; /** The type of the AST. */ +astGenerator: ?ASTGenerator; + /** The pipeline defined in .parcelrc that the asset should be processed with. */ +pipeline: ?string; - - /** a Map<export name, name of binding> */ + /** The symbols that the asset exports. */ +symbols: AssetSymbols; - - /** Returns to current AST. See notes in subclasses (Asset, MutableAsset).*/ + /** Returns the current AST. */ getAST(): Promise; - /** Returns to current source code. See notes in MutableAsset. */ + /** Returns the asset contents as a string. */ getCode(): Promise; - /** Returns the contents as a buffer. */ + /** Returns the asset contents as a buffer. */ getBuffer(): Promise; - /** Returns the contents as a stream. */ + /** Returns the asset contents as a stream. */ getStream(): Readable; - /** Returns the sourcemap (if existent). */ + /** Returns the source map for the asset, if available. */ getMap(): Promise; - /** A buffer representation of the sourcemap (if existent). */ + /** Returns a buffer representation of the source map, if available. */ getMapBuffer(): Promise; + /** Returns a list of dependencies for the asset. */ getDependencies(): $ReadOnlyArray; } /** - * A somewhat modifiable version of BaseAsset (for transformers) + * A mutable Asset, available during transformation. * @section transformer */ export interface MutableAsset extends BaseAsset { - isIsolated: boolean; - isInline: boolean; - isSplittable: ?boolean; + /** + * The asset's type. This initially corresponds to the source file extension, + * but it may be changed during transformation. + */ type: string; - - addDependency(dep: DependencyOptions): string; - addIncludedFile(filePath: FilePath): void; - invalidateOnFileCreate(invalidation: FileCreateInvalidation): void; - addURLDependency(url: string, opts: $Shape): string; - invalidateOnEnvChange(env: string): void; - + /** + * Controls which bundle the asset is placed into. + * - inline: The asset will be placed into a new inline bundle. Inline bundles are not written + * to a separate file, but embedded into the parent bundle. + * - isolated: The asset will be placed into a separate bundle. + */ + bundleBehavior: ?BundleBehavior; + /** + * If the asset is used as a bundle entry, this controls whether that bundle can be split + * into multiple, or whether all of the dependencies must be placed in a single bundle. + * @default true + */ + isBundleSplittable: boolean; + /** + * Whether this asset can be omitted if none of its exports are being used. + * This is initially set by the resolver, but can be overridden by transformers. + */ + sideEffects: boolean; + /** The symbols that the asset exports. */ +symbols: MutableAssetSymbols; - isASTDirty(): boolean; - getAST(): Promise; - setAST(AST): void; - setBuffer(Buffer): void; + /** Adds a dependency to the asset. */ + addDependency(DependencyOptions): string; + /** + * Adds a url dependency to the asset. + * This is a shortcut for addDependency that sets the specifierType to 'url' and priority to 'lazy'. + */ + addURLDependency(url: string, opts: $Shape): string; + /** Invalidates the transformation when the given file is modified or deleted. */ + invalidateOnFileChange(FilePath): void; + /** Invalidates the transformation when matched files are created. */ + invalidateOnFileCreate(FileCreateInvalidation): void; + /** Invalidates the transformation when the given environment variable changes. */ + invalidateOnEnvChange(string): void; + /** Sets the asset contents as a string. */ setCode(string): void; - /** Throws if the AST is dirty (meaning: this won't implicity stringify the AST). */ - getCode(): Promise; - setEnvironment(opts: EnvironmentOptions): void; - setMap(?SourceMap): void; + /** Sets the asset contents as a buffer. */ + setBuffer(Buffer): void; + /** Sets the asset contents as a stream. */ setStream(Readable): void; + /** Returns whether the AST has been modified. */ + setAST(AST): void; + /** Sets the asset's AST. */ + isASTDirty(): boolean; + /** Sets the asset's source map. */ + setMap(?SourceMap): void; + setEnvironment(opts: EnvironmentOptions): void; } /** + * An immutable Asset, available after transformation. * @section transformer */ export interface Asset extends BaseAsset { + /** Statistics about the asset. */ +stats: Stats; } @@ -679,13 +736,12 @@ export interface Config { +searchPath: FilePath; +result: ConfigResult; +env: Environment; - +includedFiles: Set; setResult(result: ConfigResult): void; // TODO: fix setResultHash(resultHash: string): void; - addIncludedFile(filePath: FilePath): void; - addDevDependency(devDep: DevDepOptions): void; + invalidateOnFileChange(filePath: FilePath): void; invalidateOnFileCreate(invalidation: FileCreateInvalidation): void; + addDevDependency(devDep: DevDepOptions): void; getConfigFrom( searchPath: FilePath, filePaths: Array, @@ -723,27 +779,53 @@ export type GenerateOutput = {| export type Blob = string | Buffer | Readable; /** - * Will be used to generate a new BaseAsset, see that. + * Transformers can return multiple result objects to create new assets. + * For example, a file may contain multiple parts of different types, + * which should be processed by their respective transformation pipelines. + * * @section transformer */ export type TransformerResult = {| - +ast?: ?AST, + /** The asset's type. */ + +type: string, + /** The content of the asset. Either content or an AST is required. */ +content?: ?Blob, + /** The asset's AST. Either content or an AST is required. */ + +ast?: ?AST, + /** The source map for the asset. */ + +map?: ?SourceMap, + /** The dependencies of the asset. */ +dependencies?: $ReadOnlyArray, + /** The environment of the asset. The options are merged with the input asset's environment. */ +env?: EnvironmentOptions, - +filePath?: FilePath, - +query?: ?QueryParameters, - +includedFiles?: $ReadOnlyArray, - +isInline?: boolean, - +isIsolated?: boolean, - +isSource?: boolean, - +isSplittable?: boolean, - +map?: ?SourceMap, + /** + * Controls which bundle the asset is placed into. + * - inline: The asset will be placed into a new inline bundle. Inline bundles are not written + * to a separate file, but embedded into the parent bundle. + * - isolated: The asset will be placed into a separate bundle. + */ + +bundleBehavior?: ?BundleBehavior, + /** + * If the asset is used as a bundle entry, this controls whether that bundle can be split + * into multiple, or whether all of the dependencies must be placed in a single bundle. + */ + +isBundleSplittable?: boolean, + /** Plugin-specific metadata for the asset. */ +meta?: Meta, + /** The pipeline defined in .parcelrc that the asset should be processed with. */ +pipeline?: ?string, + /** + * Whether this asset can be omitted if none of its exports are being used. + * This is initially set by the resolver, but can be overridden by transformers. + */ +sideEffects?: boolean, + /** The symbols that the asset exports. */ +symbols?: $ReadOnlyMap, - +type: string, + /** + * When a transformer returns multiple assets, it can give them unique keys to identify them. + * This can be used to find assets during packaging, or to create dependencies between multiple + * assets returned by a transformer by using the unique key as the dependency specifier. + */ +uniqueKey?: ?string, |}; diff --git a/packages/packagers/js/src/DevPackager.js b/packages/packagers/js/src/DevPackager.js index d3d3ef05834..9f0c2115eb0 100644 --- a/packages/packagers/js/src/DevPackager.js +++ b/packages/packagers/js/src/DevPackager.js @@ -190,7 +190,7 @@ export class DevPackager { return ( !this.bundleGraph.hasParentBundleOfType(this.bundle, 'js') || this.bundle.env.isIsolated() || - !!this.bundle.getMainEntry()?.isIsolated + !!this.bundle.getMainEntry()?.bundleBehavior === 'isolated' ); } } diff --git a/packages/packagers/js/src/ScopeHoistingPackager.js b/packages/packagers/js/src/ScopeHoistingPackager.js index e019ae7f823..8ae97ee3ef0 100644 --- a/packages/packagers/js/src/ScopeHoistingPackager.js +++ b/packages/packagers/js/src/ScopeHoistingPackager.js @@ -95,7 +95,7 @@ export class ScopeHoistingPackager { this.isAsyncBundle = this.bundleGraph.hasParentBundleOfType(this.bundle, 'js') && !this.bundle.env.isIsolated() && - !this.bundle.getMainEntry()?.isIsolated; + this.bundle.getMainEntry()?.bundleBehavior !== 'isolated'; this.globalNames = GLOBALS_BY_CONTEXT[bundle.env.context]; } @@ -987,7 +987,7 @@ ${code} .getBundleGroupsContainingBundle(this.bundle) .some(g => this.bundleGraph.isEntryBundleGroup(g)) || this.bundle.env.isIsolated() || - !!this.bundle.getMainEntry()?.isIsolated; + this.bundle.getMainEntry()?.bundleBehavior === 'isolated'; if (mightBeFirstJS) { let preludeCode = prelude(this.parcelRequireName); diff --git a/packages/transformers/babel/src/config.js b/packages/transformers/babel/src/config.js index efc4560954c..d1513280f8f 100644 --- a/packages/transformers/babel/src/config.js +++ b/packages/transformers/babel/src/config.js @@ -115,7 +115,7 @@ export async function load( invalidateParcelPlugin: true, }); } else { - config.addIncludedFile(file); + config.invalidateOnFileChange(file); } }; diff --git a/packages/transformers/css/src/CSSTransformer.js b/packages/transformers/css/src/CSSTransformer.js index ab463c89807..c7fbe10c1df 100644 --- a/packages/transformers/css/src/CSSTransformer.js +++ b/packages/transformers/css/src/CSSTransformer.js @@ -66,12 +66,6 @@ export default (new Transformer({ sourceMap: asset.env.sourceMap, }); - // When this asset is an bundle entry, allow that bundle to be split to load shared assets separately. - // Only set here if it is null to allow previous transformers to override this behavior. - if (asset.isSplittable == null) { - asset.isSplittable = true; - } - // Check for `hasDependencies` being false here as well, as it's possible // another transformer (such as PostCSSTransformer) has already parsed an // ast and CSSTransformer's parse was never called. diff --git a/packages/transformers/elm/src/ElmTransformer.js b/packages/transformers/elm/src/ElmTransformer.js index ece440cd689..b836b575efc 100644 --- a/packages/transformers/elm/src/ElmTransformer.js +++ b/packages/transformers/elm/src/ElmTransformer.js @@ -49,7 +49,7 @@ export default (new Transformer({ }; asset.invalidateOnEnvChange('PARCEL_ELM_NO_DEBUG'); for (const filePath of await elm.findAllDependencies(asset.filePath)) { - asset.addIncludedFile(filePath); + asset.invalidateOnFileChange(filePath); } // Workaround for `chdir` not working in workers diff --git a/packages/transformers/glsl/src/GLSLTransformer.js b/packages/transformers/glsl/src/GLSLTransformer.js index c2f24e1b6c3..e8c504bfa27 100644 --- a/packages/transformers/glsl/src/GLSLTransformer.js +++ b/packages/transformers/glsl/src/GLSLTransformer.js @@ -44,7 +44,7 @@ export default (new Transformer({ function collectDependencies(asset, ast) { for (let dep of ast) { if (!dep.entry) { - asset.addIncludedFile(dep.file); + asset.invalidateOnFileChange(dep.file); } } } diff --git a/packages/transformers/graphql/src/GraphQLTransformer.js b/packages/transformers/graphql/src/GraphQLTransformer.js index 176905133d3..be5b1eb2798 100644 --- a/packages/transformers/graphql/src/GraphQLTransformer.js +++ b/packages/transformers/graphql/src/GraphQLTransformer.js @@ -11,7 +11,7 @@ export default (new Transformer({ async function loadImport(to, from) { const filePath = await resolve(to, from); - asset.addIncludedFile(filePath); + asset.invalidateOnFileChange(filePath); return parse( new Source(await options.inputFS.readFile(filePath, 'utf-8'), filePath), diff --git a/packages/transformers/html/src/HTMLTransformer.js b/packages/transformers/html/src/HTMLTransformer.js index f5fb450b287..571a1ce0e30 100644 --- a/packages/transformers/html/src/HTMLTransformer.js +++ b/packages/transformers/html/src/HTMLTransformer.js @@ -26,7 +26,7 @@ export default (new Transformer({ async transform({asset, options}) { // Handle .htm asset.type = 'html'; - asset.isIsolated = true; + asset.bundleBehavior = 'isolated'; let ast = nullthrows(await asset.getAST()); let hasScripts = collectDependencies(asset, ast); diff --git a/packages/transformers/html/src/inline.js b/packages/transformers/html/src/inline.js index 844ef4c7a64..159bc25ecee 100644 --- a/packages/transformers/html/src/inline.js +++ b/packages/transformers/html/src/inline.js @@ -100,8 +100,7 @@ export default function extractInlineAssets( type, content: value, uniqueKey: parcelKey, - isInline: true, - isIsolated: false, + bundleBehavior: 'inline', env, meta: { type: 'tag', @@ -130,8 +129,7 @@ export default function extractInlineAssets( type: 'css', content: style, uniqueKey: parcelKey, - isInline: true, - isIsolated: false, + bundleBehavior: 'inline', meta: { type: 'attr', // $FlowFixMe diff --git a/packages/transformers/image/src/ImageTransformer.js b/packages/transformers/image/src/ImageTransformer.js index 12a9a79ea17..a15b24661d6 100644 --- a/packages/transformers/image/src/ImageTransformer.js +++ b/packages/transformers/image/src/ImageTransformer.js @@ -18,7 +18,7 @@ const FORMATS = new Map([ export default (new Transformer({ async transform({asset}) { - asset.isIsolated = true; + asset.bundleBehavior = 'isolated'; let width = asset.query.width ? parseInt(asset.query.width, 10) : null; let height = asset.query.height ? parseInt(asset.query.height, 10) : null; diff --git a/packages/transformers/inline-string/src/InlineStringTransformer.js b/packages/transformers/inline-string/src/InlineStringTransformer.js index c3a5f6afb43..07c8ec2bb04 100644 --- a/packages/transformers/inline-string/src/InlineStringTransformer.js +++ b/packages/transformers/inline-string/src/InlineStringTransformer.js @@ -4,7 +4,7 @@ import {Transformer} from '@parcel/plugin'; export default (new Transformer({ transform({asset}) { - asset.isInline = true; + asset.bundleBehavior = 'inline'; asset.meta.inlineType = 'string'; return [asset]; }, diff --git a/packages/transformers/inline/src/InlineTransformer.js b/packages/transformers/inline/src/InlineTransformer.js index a2a666a379a..7e23488bcc2 100644 --- a/packages/transformers/inline/src/InlineTransformer.js +++ b/packages/transformers/inline/src/InlineTransformer.js @@ -4,7 +4,7 @@ import {Transformer} from '@parcel/plugin'; export default (new Transformer({ transform({asset}) { - asset.isInline = true; + asset.bundleBehavior = 'inline'; return [asset]; }, }): Transformer); diff --git a/packages/transformers/js/src/JSTransformer.js b/packages/transformers/js/src/JSTransformer.js index 0fc0c109cf6..557e03cccbe 100644 --- a/packages/transformers/js/src/JSTransformer.js +++ b/packages/transformers/js/src/JSTransformer.js @@ -153,12 +153,6 @@ export default (new Transformer({ }); }, async transform({asset, config, options}) { - // When this asset is an bundle entry, allow that bundle to be split to load shared assets separately. - // Only set here if it is null to allow previous transformers to override this behavior. - if (asset.isSplittable == null) { - asset.isSplittable = true; - } - let [code, originalMap] = await Promise.all([ asset.getBuffer(), asset.getMap(), @@ -338,7 +332,7 @@ export default (new Transformer({ loc: convertLoc(dep.loc), }); } else if (dep.kind === 'File') { - asset.addIncludedFile(dep.specifier); + asset.invalidateOnFileChange(dep.specifier); } else { if (dep.kind === 'DynamicImport' && isURL(dep.specifier)) { continue; diff --git a/packages/transformers/less/src/LessTransformer.js b/packages/transformers/less/src/LessTransformer.js index d6b36940a38..f28a282d63a 100644 --- a/packages/transformers/less/src/LessTransformer.js +++ b/packages/transformers/less/src/LessTransformer.js @@ -156,7 +156,7 @@ function resolvePathPlugin({asset, resolve}) { } if (filePath) { - asset.addIncludedFile(filePath); + asset.invalidateOnFileChange(filePath); } return { diff --git a/packages/transformers/postcss/src/PostCSSTransformer.js b/packages/transformers/postcss/src/PostCSSTransformer.js index fb2d5efd414..00d27009627 100644 --- a/packages/transformers/postcss/src/PostCSSTransformer.js +++ b/packages/transformers/postcss/src/PostCSSTransformer.js @@ -113,12 +113,12 @@ export default (new Transformer({ }); for (let msg of messages) { if (msg.type === 'dependency') { - asset.addIncludedFile(msg.file); + asset.invalidateOnFileChange(msg.file); } else if (msg.type === 'dir-dependency') { let pattern = `${msg.dir}/${msg.glob ?? '**/*'}`; let files = await glob(pattern, asset.fs, {onlyFiles: true}); for (let file of files) { - asset.addIncludedFile(path.normalize(file)); + asset.invalidateOnFileChange(path.normalize(file)); } asset.invalidateOnFileCreate({glob: pattern}); } @@ -158,7 +158,6 @@ export default (new Transformer({ assets.push({ type: 'js', - filePath: asset.filePath + '.js', content: code, }); } diff --git a/packages/transformers/posthtml/src/PostHTMLTransformer.js b/packages/transformers/posthtml/src/PostHTMLTransformer.js index 52bacbc4a72..14773820aba 100644 --- a/packages/transformers/posthtml/src/PostHTMLTransformer.js +++ b/packages/transformers/posthtml/src/PostHTMLTransformer.js @@ -106,7 +106,7 @@ export default (new Transformer({ await Promise.all( res.messages.map(({type, file: filePath}) => { if (type === 'dependency') { - return asset.addIncludedFile(filePath); + return asset.invalidateOnFileChange(filePath); } return Promise.resolve(); }), diff --git a/packages/transformers/pug/src/PugTransformer.js b/packages/transformers/pug/src/PugTransformer.js index bc7366c8b53..a01f48c71e2 100644 --- a/packages/transformers/pug/src/PugTransformer.js +++ b/packages/transformers/pug/src/PugTransformer.js @@ -34,7 +34,7 @@ export default (new Transformer({ }); for (let filePath of render.dependencies) { - await asset.addIncludedFile(filePath); + await asset.invalidateOnFileChange(filePath); } asset.type = 'html'; diff --git a/packages/transformers/raw/src/RawTransformer.js b/packages/transformers/raw/src/RawTransformer.js index 99a091fc209..cf010820f11 100644 --- a/packages/transformers/raw/src/RawTransformer.js +++ b/packages/transformers/raw/src/RawTransformer.js @@ -4,7 +4,7 @@ import {Transformer} from '@parcel/plugin'; export default (new Transformer({ transform({asset}) { - asset.isIsolated = true; + asset.bundleBehavior = 'isolated'; return [asset]; }, }): Transformer); diff --git a/packages/transformers/sass/src/SassTransformer.js b/packages/transformers/sass/src/SassTransformer.js index 88c90146521..bdbaf431e28 100644 --- a/packages/transformers/sass/src/SassTransformer.js +++ b/packages/transformers/sass/src/SassTransformer.js @@ -76,7 +76,7 @@ export default (new Transformer({ css = result.css; for (let included of result.stats.includedFiles) { if (included !== asset.filePath) { - asset.addIncludedFile(included); + asset.invalidateOnFileChange(included); } } diff --git a/packages/transformers/stylus/src/StylusTransformer.js b/packages/transformers/stylus/src/StylusTransformer.js index 203d5b280bb..d9db062cb64 100644 --- a/packages/transformers/stylus/src/StylusTransformer.js +++ b/packages/transformers/stylus/src/StylusTransformer.js @@ -180,7 +180,7 @@ async function getDependencies( // Recursively process resolved files as well to get nested deps for (let resolved of found) { if (!seen.has(resolved)) { - await asset.addIncludedFile(resolved); + await asset.invalidateOnFileChange(resolved); let code = await asset.fs.readFile(resolved, 'utf8'); for (let [path, resolvedPath] of await getDependencies( diff --git a/packages/transformers/typescript-types/src/TSTypesTransformer.js b/packages/transformers/typescript-types/src/TSTypesTransformer.js index 15fed35cf03..cd186c5a63f 100644 --- a/packages/transformers/typescript-types/src/TSTypesTransformer.js +++ b/packages/transformers/typescript-types/src/TSTypesTransformer.js @@ -42,12 +42,13 @@ export default (new Transformer({ // $FlowFixMe let program = ts.createProgram([asset.filePath], opts, host); - let includedFiles = program - .getSourceFiles() - .filter(file => path.normalize(file.fileName) !== asset.filePath) - .map(file => ({ - filePath: host.redirectTypes.get(file.fileName) ?? file.fileName, - })); + for (let file of program.getSourceFiles()) { + if (path.normalize(file.fileName) !== asset.filePath) { + asset.invalidateOnFileChange( + host.redirectTypes.get(file.fileName) ?? file.fileName, + ); + } + } let mainModuleName = path .relative(program.getCommonSourceDirectory(), asset.filePath) @@ -149,15 +150,9 @@ export default (new Transformer({ sourceMap.addVLQMap(map); } - return [ - { - type: 'ts', - // Stay on the types pipeline, even if the type changes - pipeline: asset.pipeline, - content: code, - map: sourceMap, - includedFiles, - }, - ]; + asset.type = 'ts'; + asset.setCode(code); + asset.setMap(sourceMap); + return [asset]; }, }): Transformer); diff --git a/packages/utils/ts-utils/src/loadTSConfig.js b/packages/utils/ts-utils/src/loadTSConfig.js index 486ac0a6374..129c678501f 100644 --- a/packages/utils/ts-utils/src/loadTSConfig.js +++ b/packages/utils/ts-utils/src/loadTSConfig.js @@ -20,7 +20,7 @@ export async function loadTSConfig(config: Config, options: PluginOptions) { // Add all of the extended config files to be watched for (let file of host.filesRead) { - config.addIncludedFile(path.resolve(file)); + config.invalidateOnFileChange(path.resolve(file)); } config.setResult(parsedConfig.options);