refactor(@ngtools/webpack): remove forwardSlashPath utility usage from Ivy plugin

A cached path normalization helper is now used in places that still require normalization.  Usage was also removed completely in locations that are not needed either because the path was later normalized or the normalization would provide no benefit.
This commit is contained in:
Charles Lyding 2020-11-24 09:45:55 -05:00 committed by Alan Agius
parent 4c46c191c7
commit ff9e245a51
5 changed files with 70 additions and 50 deletions

View File

@ -11,7 +11,7 @@ import * as path from 'path';
import * as ts from 'typescript';
import { NgccProcessor } from '../ngcc_processor';
import { WebpackResourceLoader } from '../resource_loader';
import { forwardSlashPath } from '../utils';
import { normalizePath } from './paths';
export function augmentHostWithResources(
host: ts.CompilerHost,
@ -21,7 +21,7 @@ export function augmentHostWithResources(
const resourceHost = host as CompilerHost;
resourceHost.readResource = function (fileName: string) {
const filePath = forwardSlashPath(fileName);
const filePath = normalizePath(fileName);
if (
options.directTemplateLoading &&
@ -41,7 +41,7 @@ export function augmentHostWithResources(
};
resourceHost.resourceNameToFileName = function (resourceName: string, containingFile: string) {
return forwardSlashPath(path.join(path.dirname(containingFile), resourceName));
return path.join(path.dirname(containingFile), resourceName);
};
resourceHost.getModifiedResourceFiles = function () {
@ -157,7 +157,7 @@ export function augmentHostWithReplacements(
const normalizedReplacements: Record<string, string> = {};
for (const [key, value] of Object.entries(replacements)) {
normalizedReplacements[forwardSlashPath(key)] = forwardSlashPath(value);
normalizedReplacements[normalizePath(key)] = normalizePath(value);
}
const tryReplace = (resolvedModule: ts.ResolvedModule | undefined) => {

View File

@ -0,0 +1,42 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as nodePath from 'path';
const normalizationCache = new Map<string, string>();
export function normalizePath(path: string): string {
let result = normalizationCache.get(path);
if (result === undefined) {
result = nodePath.win32.normalize(path).replace(/\\/g, nodePath.posix.sep);
normalizationCache.set(path, result);
}
return result;
}
const externalizationCache = new Map<string, string>();
function externalizeForWindows(path: string): string {
let result = externalizationCache.get(path);
if (result === undefined) {
result = nodePath.win32.normalize(path);
externalizationCache.set(path, result);
}
return result;
}
export const externalizePath = (() => {
if (process.platform !== 'win32') {
return (path: string) => path;
}
return externalizeForWindows;
})();

View File

@ -18,7 +18,6 @@ import {
import { NgccProcessor } from '../ngcc_processor';
import { TypeScriptPathsPlugin } from '../paths-plugin';
import { WebpackResourceLoader } from '../resource_loader';
import { forwardSlashPath } from '../utils';
import { addError, addWarning } from '../webpack-diagnostics';
import { isWebpackFiveOrHigher, mergeResolverMainFields } from '../webpack-version';
import { DiagnosticsReporter, createDiagnosticsReporter } from './diagnostics';
@ -30,6 +29,7 @@ import {
augmentHostWithSubstitutions,
augmentProgramWithVersioning,
} from './host';
import { externalizePath, normalizePath } from './paths';
import { AngularPluginSymbol, FileEmitter } from './symbol';
import { createWebpackSystem } from './system';
import { createAotTransformers, createJitTransformers, mergeTransformers } from './transformation';
@ -180,7 +180,7 @@ export class AngularWebpackPlugin {
// Create a Webpack-based TypeScript compiler host
const system = createWebpackSystem(
compiler.inputFileSystem,
forwardSlashPath(compiler.context),
normalizePath(compiler.context),
);
const host = ts.createIncrementalCompilerHost(compilerOptions, system);
@ -190,7 +190,8 @@ export class AngularWebpackPlugin {
// Invalidate existing cache based on compilation file timestamps
for (const [file, time] of compilation.fileTimestamps) {
if (this.buildTimestamp < time) {
cache.delete(forwardSlashPath(file));
// Cache stores paths using the POSIX directory separator
cache.delete(normalizePath(file));
}
}
} else {
@ -254,7 +255,7 @@ export class AngularWebpackPlugin {
const rebuild = (filename: string) => new Promise<void>((resolve) => {
const module = modules.find(
({ resource }: compilation.Module & { resource?: string }) =>
resource && forwardSlashPath(resource) === filename,
resource && normalizePath(resource) === filename,
);
if (!module) {
resolve();
@ -279,7 +280,7 @@ export class AngularWebpackPlugin {
.map((sourceFile) => sourceFile.fileName),
);
modules.forEach(({ resource }: compilation.Module & { resource?: string }) => {
const sourceFile = resource && builder.getSourceFile(forwardSlashPath(resource));
const sourceFile = resource && builder.getSourceFile(resource);
if (!sourceFile) {
return;
}
@ -408,8 +409,7 @@ export class AngularWebpackPlugin {
const getDependencies = (sourceFile: ts.SourceFile) => {
const dependencies = [];
for (const resourceDependency of angularCompiler.getResourceDependencies(sourceFile)) {
const resourcePath = forwardSlashPath(resourceDependency);
for (const resourcePath of angularCompiler.getResourceDependencies(sourceFile)) {
dependencies.push(
resourcePath,
// Retrieve all dependencies of the resource (stylesheet imports, etc.)
@ -444,8 +444,7 @@ export class AngularWebpackPlugin {
// NOTE: This can be removed once support for the deprecated lazy route string format is removed
for (const lazyRoute of angularCompiler.listLazyRoutes()) {
const [routeKey] = lazyRoute.route.split('#');
const routePath = forwardSlashPath(lazyRoute.referencedModule.filePath);
this.lazyRouteMap[routeKey] = routePath;
this.lazyRouteMap[routeKey] = lazyRoute.referencedModule.filePath;
}
return this.createFileEmitter(
@ -513,8 +512,7 @@ export class AngularWebpackPlugin {
const pendingAnalysis = angularCompiler.analyzeAsync().then(() => {
for (const lazyRoute of angularCompiler.listLazyRoutes()) {
const [routeKey] = lazyRoute.route.split('#');
const routePath = forwardSlashPath(lazyRoute.referencedModule.filePath);
this.lazyRouteMap[routeKey] = routePath;
this.lazyRouteMap[routeKey] = lazyRoute.referencedModule.filePath;
}
return this.createFileEmitter(builder, transformers, () => []);

View File

@ -7,45 +7,25 @@
*/
import * as ts from 'typescript';
import { InputFileSystem } from 'webpack';
import { externalizePath } from './paths';
function shouldNotWrite(): never {
throw new Error('Webpack TypeScript System should not write.');
}
// Webpack's CachedInputFileSystem uses the default directory separator in the paths it uses
// for keys to its cache. If the keys do not match then the file watcher will not purge outdated
// files and cause stale data to be used in the next rebuild. TypeScript always uses a `/` (POSIX)
// directory separator internally which is also supported with Windows system APIs. However,
// if file operations are performed with the non-default directory separator, the Webpack cache
// will contain a key that will not be purged.
function createToSystemPath(): (path: string) => string {
if (process.platform === 'win32') {
const cache = new Map<string, string>();
return (path) => {
let value = cache.get(path);
if (value === undefined) {
value = path.replace(/\//g, '\\');
cache.set(path, value);
}
return value;
};
}
// POSIX-like platforms retain the existing directory separator
return (path) => path;
}
export function createWebpackSystem(input: InputFileSystem, currentDirectory: string): ts.System {
const toSystemPath = createToSystemPath();
// Webpack's CachedInputFileSystem uses the default directory separator in the paths it uses
// for keys to its cache. If the keys do not match then the file watcher will not purge outdated
// files and cause stale data to be used in the next rebuild. TypeScript always uses a `/` (POSIX)
// directory separator internally which is also supported with Windows system APIs. However,
// if file operations are performed with the non-default directory separator, the Webpack cache
// will contain a key that will not be purged. `externalizePath` ensures the paths are as expected.
const system: ts.System = {
...ts.sys,
readFile(path: string) {
let data;
try {
data = input.readFileSync(toSystemPath(path));
data = input.readFileSync(externalizePath(path));
} catch {
return undefined;
}
@ -60,28 +40,28 @@ export function createWebpackSystem(input: InputFileSystem, currentDirectory: st
},
getFileSize(path: string) {
try {
return input.statSync(toSystemPath(path)).size;
return input.statSync(externalizePath(path)).size;
} catch {
return 0;
}
},
fileExists(path: string) {
try {
return input.statSync(toSystemPath(path)).isFile();
return input.statSync(externalizePath(path)).isFile();
} catch {
return false;
}
},
directoryExists(path: string) {
try {
return input.statSync(toSystemPath(path)).isDirectory();
return input.statSync(externalizePath(path)).isDirectory();
} catch {
return false;
}
},
getModifiedTime(path: string) {
try {
return input.statSync(toSystemPath(path)).mtime;
return input.statSync(externalizePath(path)).mtime;
} catch {
return undefined;
}

View File

@ -11,7 +11,7 @@
import * as path from 'path';
import * as vm from 'vm';
import { RawSource } from 'webpack-sources';
import { forwardSlashPath } from './utils';
import { normalizePath } from './ivy/paths';
const NodeTemplatePlugin = require('webpack/lib/node/NodeTemplatePlugin');
const NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin');
@ -44,7 +44,7 @@ export class WebpackResourceLoader {
this.changedFiles.clear();
for (const [file, time] of parentCompilation.fileTimestamps) {
if (this.buildTimestamp < time) {
this.changedFiles.add(forwardSlashPath(file));
this.changedFiles.add(normalizePath(file));
}
}
}
@ -159,7 +159,7 @@ export class WebpackResourceLoader {
// Save the dependencies for this resource.
this._fileDependencies.set(filePath, new Set(childCompilation.fileDependencies));
for (const file of childCompilation.fileDependencies) {
const resolvedFile = forwardSlashPath(file);
const resolvedFile = normalizePath(file);
const entry = this._reverseDependencies.get(resolvedFile);
if (entry) {
entry.add(filePath);