Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@ import type {
import assert from 'node:assert';
import { realpath } from 'node:fs/promises';
import * as path from 'node:path';
import { pathToFileURL } from 'node:url';
import { maxWorkers } from '../../../utils/environment-options';
import { JavaScriptTransformer } from '../javascript-transformer';
import { LoadResultCache } from '../load-result-cache';
import { LoadResultCache, createCachedLoad } from '../load-result-cache';
import { logCumulativeDurations, profileAsync, resetCumulativeDurations } from '../profiling';
import { BundleStylesheetOptions } from '../stylesheets/bundle-options';
import { AngularHostOptions } from './angular-host';
Expand Down Expand Up @@ -280,7 +279,7 @@ export function createCompilerPlugin(
try {
await profileAsync('NG_EMIT_TS', async () => {
for (const { filename, contents } of await compilation.emitAffectedFiles()) {
typeScriptFileCache.set(pathToFileURL(filename).href, contents);
typeScriptFileCache.set(path.normalize(filename), contents);
}
});
} catch (error) {
Expand Down Expand Up @@ -323,7 +322,9 @@ export function createCompilerPlugin(
});

build.onLoad({ filter: /\.[cm]?[jt]sx?$/ }, async (args) => {
const request = pluginOptions.fileReplacements?.[args.path] ?? args.path;
const request = path.normalize(
pluginOptions.fileReplacements?.[path.normalize(args.path)] ?? args.path,
);

// Skip TS load attempt if JS TypeScript compilation not enabled and file is JS
if (shouldTsIgnoreJs && /\.[cm]?js$/.test(request)) {
Expand All @@ -334,7 +335,7 @@ export function createCompilerPlugin(
// the options cannot change and do not need to be represented in the key. If the
// cache is later stored to disk, then the options that affect transform output
// would need to be added to the key as well as a check for any change of content.
let contents = typeScriptFileCache.get(pathToFileURL(request).href);
let contents = typeScriptFileCache.get(request);

if (contents === undefined) {
// If the Angular compilation had errors the file may not have been emitted.
Expand Down Expand Up @@ -364,7 +365,7 @@ export function createCompilerPlugin(
);

// Store as the returned Uint8Array to allow caching the fully transformed code
typeScriptFileCache.set(pathToFileURL(request).href, contents);
typeScriptFileCache.set(request, contents);
}

return {
Expand All @@ -373,27 +374,25 @@ export function createCompilerPlugin(
};
});

build.onLoad({ filter: /\.[cm]?js$/ }, (args) =>
profileAsync(
'NG_EMIT_JS*',
async () => {
// The filename is currently used as a cache key. Since the cache is memory only,
// the options cannot change and do not need to be represented in the key. If the
// cache is later stored to disk, then the options that affect transform output
// would need to be added to the key as well as a check for any change of content.
let contents = pluginOptions.sourceFileCache?.babelFileCache.get(args.path);
if (contents === undefined) {
contents = await javascriptTransformer.transformFile(args.path, pluginOptions.jit);
pluginOptions.sourceFileCache?.babelFileCache.set(args.path, contents);
}
build.onLoad(
{ filter: /\.[cm]?js$/ },
createCachedLoad(pluginOptions.loadResultCache, async (args) => {
return profileAsync(
'NG_EMIT_JS*',
async () => {
const contents = await javascriptTransformer.transformFile(
args.path,
pluginOptions.jit,
);

return {
contents,
loader: 'js',
};
},
true,
),
return {
contents,
loader: 'js',
};
},
true,
);
}),
);

// Setup bundling of component templates and stylesheets when in JIT mode
Expand Down Expand Up @@ -531,18 +530,20 @@ function bundleWebWorker(
}

function createMissingFileError(request: string, original: string, root: string): PartialMessage {
const relativeRequest = path.relative(root, request);
const error = {
text: `File '${path.relative(root, request)}' is missing from the TypeScript compilation.`,
text: `File '${relativeRequest}' is missing from the TypeScript compilation.`,
notes: [
{
text: `Ensure the file is part of the TypeScript program via the 'files' or 'include' property.`,
},
],
};

if (request !== original) {
const relativeOriginal = path.relative(root, original);
if (relativeRequest !== relativeOriginal) {
error.notes.push({
text: `File is requested from a file replacement of '${path.relative(root, original)}'.`,
text: `File is requested from a file replacement of '${relativeOriginal}'.`,
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import { platform } from 'node:os';
import * as path from 'node:path';
import { pathToFileURL } from 'node:url';
import type ts from 'typescript';
import { MemoryLoadResultCache } from '../load-result-cache';

Expand All @@ -17,7 +16,6 @@ const WINDOWS_SEP_REGEXP = new RegExp(`\\${path.win32.sep}`, 'g');

export class SourceFileCache extends Map<string, ts.SourceFile> {
readonly modifiedFiles = new Set<string>();
readonly babelFileCache = new Map<string, Uint8Array>();
readonly typeScriptFileCache = new Map<string, string | Uint8Array>();
readonly loadResultCache = new MemoryLoadResultCache();

Expand All @@ -32,8 +30,8 @@ export class SourceFileCache extends Map<string, ts.SourceFile> {
this.modifiedFiles.clear();
}
for (let file of files) {
this.babelFileCache.delete(file);
this.typeScriptFileCache.delete(pathToFileURL(file).href);
file = path.normalize(file);
this.typeScriptFileCache.delete(file);
this.loadResultCache.invalidate(file);

// Normalize separators to allow matching TypeScript Host paths
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ export function createCachedLoad(

// Do not cache null or undefined
if (result) {
// Ensure requested path is included if it was a resolved file
if (args.namespace === 'file') {
result.watchFiles ??= [];
result.watchFiles.push(args.path);
}
await cache.put(loadCacheKey, result);
}
}
Expand Down Expand Up @@ -79,6 +84,8 @@ export class MemoryLoadResultCache implements LoadResultCache {
}

get watchFiles(): string[] {
return [...this.#loadResults.keys(), ...this.#fileDependencies.keys()];
// this.#loadResults.keys() is not included here because the keys
// are namespaced request paths and not disk-based file paths.
return [...this.#fileDependencies.keys()];
}
}