Skip to content

Commit

Permalink
fix(@ngtools/webpack): only use require.resolve as a fallback in NG…
Browse files Browse the repository at this point in the history
…CC processing

Use `enhanced-resolve` instead of `require.resolve` to ensure that we can use symlink path instead of real-path when resolving a linked module.

Closes angular#19395
  • Loading branch information
alan-agius4 authored and clydin committed Nov 16, 2020
1 parent 8466af1 commit 0133d70
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 26 deletions.
11 changes: 2 additions & 9 deletions src/angular_compiler_plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -785,21 +785,14 @@ export class AngularCompilerPlugin {

let ngccProcessor: NgccProcessor | undefined;
if (this._compilerOptions.enableIvy) {
const fileWatchPurger = (path: string) => {
// tslint:disable-next-line: no-any
if ((compilerWithFileSystems.inputFileSystem as any).purge) {
// tslint:disable-next-line: no-any
(compilerWithFileSystems.inputFileSystem as any).purge(path);
}
};

ngccProcessor = new NgccProcessor(
this._mainFields,
fileWatchPurger,
this._warnings,
this._errors,
this._basePath,
this._tsConfigPath,
compilerWithFileSystems.inputFileSystem,
compiler.options.resolve?.symlinks,
);

ngccProcessor.process();
Expand Down
10 changes: 2 additions & 8 deletions src/ivy/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,22 +59,16 @@ function initializeNgccProcessor(
const { inputFileSystem, options: webpackOptions } = compiler;
const mainFields = ([] as string[]).concat(...(webpackOptions.resolve?.mainFields || []));

const fileWatchPurger = (path: string) => {
if (inputFileSystem.purge) {
// Webpack typings do not contain the string parameter overload for purge
(inputFileSystem as { purge(path: string): void }).purge(path);
}
};

const errors: string[] = [];
const warnings: string[] = [];
const processor = new NgccProcessor(
mainFields,
fileWatchPurger,
warnings,
errors,
compiler.context,
tsconfig,
inputFileSystem,
webpackOptions.resolve?.symlinks,
);

return { processor, errors, warnings };
Expand Down
30 changes: 21 additions & 9 deletions src/ngcc_processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
import { LogLevel, Logger, process as mainNgcc } from '@angular/compiler-cli/ngcc';
import { spawnSync } from 'child_process';
import { createHash } from 'crypto';
import { Resolver, ResolverFactory } from 'enhanced-resolve';
import { accessSync, constants, existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
import * as path from 'path';
import * as ts from 'typescript';
import { InputFileSystem } from 'webpack';
import { time, timeEnd } from './benchmark';

// We cannot create a plugin for this, because NGTSC requires addition type
Expand All @@ -28,17 +30,28 @@ export class NgccProcessor {
private _processedModules = new Set<string>();
private _logger: NgccLogger;
private _nodeModulesDirectory: string;
private _resolver: Resolver;

constructor(
private readonly propertiesToConsider: string[],
private readonly fileWatchPurger: (path: string) => void,
private readonly compilationWarnings: (Error | string)[],
private readonly compilationErrors: (Error | string)[],
private readonly basePath: string,
private readonly tsConfigPath: string,
private readonly inputFileSystem: InputFileSystem,
private readonly symlinks: boolean | undefined,
) {
this._logger = new NgccLogger(this.compilationWarnings, this.compilationErrors);
this._nodeModulesDirectory = this.findNodeModulesDirectory(this.basePath);

this._resolver = ResolverFactory.createResolver({
// NOTE: @types/webpack InputFileSystem is missing some methods
// tslint:disable-next-line: no-any
fileSystem: this.inputFileSystem as any,
extensions: ['.json'],
useSyncFileSystemCalls: true,
symlinks,
});
}

/** Process the entire node modules tree. */
Expand Down Expand Up @@ -191,7 +204,10 @@ export class NgccProcessor {

// Purge this file from cache, since NGCC add new mainFields. Ex: module_ivy_ngcc
// which are unknown in the cached file.
this.fileWatchPurger(packageJsonPath);
if (this.inputFileSystem.purge) {
// tslint:disable-next-line: no-any
(this.inputFileSystem.purge as any)(packageJsonPath);
}

this._processedModules.add(resolvedFileName);
}
Expand All @@ -205,14 +221,10 @@ export class NgccProcessor {
*/
private tryResolvePackage(moduleName: string, resolvedFileName: string): string | undefined {
try {
// This is based on the logic in the NGCC compiler
// tslint:disable-next-line:max-line-length
// See: https://github.com/angular/angular/blob/b93c1dffa17e4e6900b3ab1b9e554b6da92be0de/packages/compiler-cli/src/ngcc/src/packages/dependency_host.ts#L85-L121
return require.resolve(`${moduleName}/package.json`, {
paths: [resolvedFileName],
});
const resolvedPath = this._resolver.resolveSync({}, resolvedFileName, `${moduleName}/package.json`);

return resolvedPath || undefined;
} catch {
// if it fails this might be a deep import which doesn't have a package.json
// Ex: @angular/compiler/src/i18n/i18n_ast/package.json
// or local libraries which don't reside in node_modules
const packageJsonPath = path.resolve(resolvedFileName, '../package.json');
Expand Down

0 comments on commit 0133d70

Please sign in to comment.