Skip to content

Commit

Permalink
Fix dev dep request missing 'invalidateOnCreate'
Browse files Browse the repository at this point in the history
Fixes #8375

Ported from Atlaspack: atlassian-labs/atlaspack#185

Co-authored-by: Pedro Yamada <tacla.yamada@gmail.com>
  • Loading branch information
devongovett and yamadapc committed Feb 3, 2025
1 parent b50bc79 commit d6a4df3
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 18 deletions.
5 changes: 3 additions & 2 deletions packages/core/core/src/PackagerRunner.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type {
Bundle as InternalBundle,
Config,
DevDepRequest,
DevDepRequestRef,
ParcelOptions,
ReportFn,
RequestInvalidation,
Expand Down Expand Up @@ -74,7 +75,7 @@ type Opts = {|
export type RunPackagerRunnerResult = {|
bundleInfo: BundleInfo[],
configRequests: Array<ConfigRequest>,
devDepRequests: Array<DevDepRequest>,
devDepRequests: Array<DevDepRequest | DevDepRequestRef>,
invalidations: Array<RequestInvalidation>,
|};

Expand Down Expand Up @@ -107,7 +108,7 @@ export default class PackagerRunner {
distExists: Set<FilePath>;
report: ReportFn;
previousDevDeps: Map<string, string>;
devDepRequests: Map<string, DevDepRequest>;
devDepRequests: Map<string, DevDepRequest | DevDepRequestRef>;
invalidations: Map<string, RequestInvalidation>;
previousInvalidations: Array<RequestInvalidation>;

Expand Down
5 changes: 3 additions & 2 deletions packages/core/core/src/Transformation.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import type {
TransformationRequest,
Config,
DevDepRequest,
DevDepRequestRef,
ParcelOptions,
InternalDevDepOptions,
Invalidations,
Expand Down Expand Up @@ -89,13 +90,13 @@ export type TransformationResult = {|
error?: Array<Diagnostic>,
configRequests: Array<ConfigRequest>,
invalidations: Invalidations,
devDepRequests: Array<DevDepRequest>,
devDepRequests: Array<DevDepRequest | DevDepRequestRef>,
|};

export default class Transformation {
request: TransformationRequest;
configs: Map<string, Config>;
devDepRequests: Map<string, DevDepRequest>;
devDepRequests: Map<string, DevDepRequest | DevDepRequestRef>;
pluginDevDeps: Array<InternalDevDepOptions>;
options: ParcelOptions;
pluginOptions: PluginOptions;
Expand Down
3 changes: 2 additions & 1 deletion packages/core/core/src/applyRuntimes.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {
Bundle as InternalBundle,
Config,
DevDepRequest,
DevDepRequestRef,
ParcelOptions,
} from './types';
import type ParcelConfig from './ParcelConfig';
Expand Down Expand Up @@ -59,7 +60,7 @@ export default async function applyRuntimes<TResult: RequestResult>({
pluginOptions: PluginOptions,
api: RunAPI<TResult>,
previousDevDeps: Map<string, string>,
devDepRequests: Map<string, DevDepRequest>,
devDepRequests: Map<string, DevDepRequest | DevDepRequestRef>,
configs: Map<string, Config>,
|}): Promise<Map<string, Asset>> {
let runtimes = await config.getRuntimes();
Expand Down
5 changes: 3 additions & 2 deletions packages/core/core/src/requests/BundleGraphRequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {
Bundle as InternalBundle,
Config,
DevDepRequest,
DevDepRequestRef,
ParcelOptions,
} from '../types';
import type {ConfigAndCachePath} from './ParcelConfigRequest';
Expand Down Expand Up @@ -173,7 +174,7 @@ class BundlerRunner {
pluginOptions: PluginOptions;
api: RunAPI<BundleGraphResult>;
previousDevDeps: Map<string, string>;
devDepRequests: Map<string, DevDepRequest>;
devDepRequests: Map<string, DevDepRequest | DevDepRequestRef>;
configs: Map<string, Config>;
cacheKey: string;

Expand Down Expand Up @@ -236,7 +237,7 @@ class BundlerRunner {
this.configs.set(plugin.name, config);
}

async runDevDepRequest(devDepRequest: DevDepRequest) {
async runDevDepRequest(devDepRequest: DevDepRequest | DevDepRequestRef) {
let {specifier, resolveFrom} = devDepRequest;
let key = `${specifier}:${fromProjectPathRelative(resolveFrom)}`;
this.devDepRequests.set(key, devDepRequest);
Expand Down
43 changes: 37 additions & 6 deletions packages/core/core/src/requests/DevDepRequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
import type ParcelConfig from '../ParcelConfig';
import type {
DevDepRequest,
DevDepRequestRef,
ParcelOptions,
InternalDevDepOptions,
} from '../types';
Expand Down Expand Up @@ -34,7 +35,7 @@ export async function createDevDependency(
opts: InternalDevDepOptions,
requestDevDeps: Map<string, string>,
options: ParcelOptions,
): Promise<DevDepRequest> {
): Promise<DevDepRequest | DevDepRequestRef> {
let {specifier, resolveFrom, additionalInvalidations} = opts;
let key = `${specifier}:${fromProjectPathRelative(resolveFrom)}`;

Expand All @@ -44,6 +45,7 @@ export async function createDevDependency(
let hash = requestDevDeps.get(key);
if (hash != null) {
return {
type: 'ref',
specifier,
resolveFrom,
hash,
Expand Down Expand Up @@ -189,12 +191,17 @@ export type DevDepRequestResult = {|

export async function runDevDepRequest<TResult: RequestResult>(
api: RunAPI<TResult>,
devDepRequest: DevDepRequest,
devDepRequestRef: DevDepRequest | DevDepRequestRef,
) {
await api.runRequest<null, DevDepRequestResult | void>({
id: 'dev_dep_request:' + devDepRequest.specifier + ':' + devDepRequest.hash,
id:
'dev_dep_request:' +
devDepRequestRef.specifier +
':' +
devDepRequestRef.hash,
type: requestTypes.dev_dep_request,
run: ({api}) => {
let devDepRequest = resolveDevDepRequestRef(devDepRequestRef);
for (let filePath of nullthrows(
devDepRequest.invalidateOnFileChange,
'DevDepRequest missing invalidateOnFileChange',
Expand Down Expand Up @@ -225,19 +232,43 @@ export async function runDevDepRequest<TResult: RequestResult>(
});
}

const devDepRequests: Map<string, DevDepRequest> = createBuildCache();
export function resolveDevDepRequestRef(
devDepRequestRef: DevDepRequest | DevDepRequestRef,
): DevDepRequest {
const devDepRequest =
devDepRequestRef.type === 'ref'
? devDepRequests.get(devDepRequestRef.hash)
: devDepRequestRef;
if (devDepRequest == null) {
throw new Error(
`Worker send back a reference to a missing dev dep request.
This might happen due to internal in-memory build caches not being cleared
between builds or due a race condition.
This is a bug in Parcel.`,
);
}

if (devDepRequestRef.type !== 'ref') {
devDepRequests.set(devDepRequest.hash, devDepRequest);
}

return devDepRequest;
}

// A cache of plugin dependency hashes that we've already sent to the main thread.
// Automatically cleared before each build.
const pluginCache = createBuildCache();

export function getWorkerDevDepRequests(
devDepRequests: Array<DevDepRequest>,
): Array<DevDepRequest> {
devDepRequests: Array<DevDepRequest | DevDepRequestRef>,
): Array<DevDepRequest | DevDepRequestRef> {
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 {specifier, resolveFrom, hash} = devDepRequest;
if (hash === pluginCache.get(specifier)) {
return {specifier, resolveFrom, hash};
return {type: 'ref', specifier, resolveFrom, hash};
} else {
pluginCache.set(specifier, hash);
return devDepRequest;
Expand Down
5 changes: 3 additions & 2 deletions packages/core/core/src/requests/PathRequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type {
Config,
Dependency,
DevDepRequest,
DevDepRequestRef,
ParcelOptions,
} from '../types';
import type {ConfigAndCachePath} from './ParcelConfigRequest';
Expand Down Expand Up @@ -163,7 +164,7 @@ export class ResolverRunner {
options: ParcelOptions;
pluginOptions: PluginOptions;
previousDevDeps: Map<string, string>;
devDepRequests: Map<string, DevDepRequest>;
devDepRequests: Map<string, DevDepRequest | DevDepRequestRef>;
configs: Map<string, Config>;

constructor({config, options, previousDevDeps}: ResolverRunnerOpts) {
Expand Down Expand Up @@ -237,7 +238,7 @@ export class ResolverRunner {
}
}

runDevDepRequest(devDepRequest: DevDepRequest) {
runDevDepRequest(devDepRequest: DevDepRequest | DevDepRequestRef) {
let {specifier, resolveFrom} = devDepRequest;
let key = `${specifier}:${fromProjectPathRelative(resolveFrom)}`;
this.devDepRequests.set(key, devDepRequest);
Expand Down
13 changes: 10 additions & 3 deletions packages/core/core/src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -258,16 +258,23 @@ export type DevDepRequest = {|
specifier: DependencySpecifier,
resolveFrom: ProjectPath,
hash: string,
invalidateOnFileCreate?: Array<InternalFileCreateInvalidation>,
invalidateOnFileChange?: Set<ProjectPath>,
invalidateOnStartup?: boolean,
invalidateOnFileCreate: Array<InternalFileCreateInvalidation>,
invalidateOnFileChange: Set<ProjectPath>,
invalidateOnStartup: boolean,
additionalInvalidations?: Array<{|
specifier: DependencySpecifier,
resolveFrom: ProjectPath,
range?: ?SemverRange,
|}>,
|};

export type DevDepRequestRef = {|
type: 'ref',
specifier: DependencySpecifier,
resolveFrom: ProjectPath,
hash: string,
|};

declare type GlobPattern = string;

export type ParcelOptions = {|
Expand Down
62 changes: 62 additions & 0 deletions packages/core/core/test/requests/DevDepRequest.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// @flow strict-local

// eslint-disable-next-line @parcel/no-self-package-imports
import {clearBuildCaches} from '@parcel/core/src/buildCache';
import {resolveDevDepRequestRef} from '../../src/requests/DevDepRequest';
import type {DevDepRequest, DevDepRequestRef} from '../../src/types';
import {toProjectPath} from '../../src/projectPath';
import assert from 'assert';

describe('DevDepRequest', () => {
beforeEach(() => {
clearBuildCaches();
});

describe('resolveDevDepRequestRef', () => {
it('will return requests as is', () => {
const request: DevDepRequest = {
specifier: 'test',
hash: 'hash',
invalidateOnFileChange: new Set(),
invalidateOnFileCreate: [],
invalidateOnStartup: false,
resolveFrom: toProjectPath('', 'path.js'),
};
const result = resolveDevDepRequestRef(request);
assert.equal(result, request);
});

it('will return cached requests for refs', () => {
const request: DevDepRequest = {
specifier: 'test',
hash: 'hash',
invalidateOnFileChange: new Set(),
invalidateOnFileCreate: [],
invalidateOnStartup: false,
resolveFrom: toProjectPath('', 'path.js'),
};
resolveDevDepRequestRef(request);

const devDepRequestRef: DevDepRequestRef = {
type: 'ref',
specifier: 'test',
hash: 'hash',
resolveFrom: toProjectPath('', 'path.js'),
};
const result = resolveDevDepRequestRef(devDepRequestRef);
assert.equal(result, request);
});

it('will throw for uncached refs', () => {
const devDepRequestRef: DevDepRequestRef = {
type: 'ref',
specifier: 'test',
hash: 'hash',
resolveFrom: toProjectPath('', 'path.js'),
};
assert.throws(() => {
resolveDevDepRequestRef(devDepRequestRef);
});
});
});
});

0 comments on commit d6a4df3

Please sign in to comment.