Skip to content

Commit

Permalink
refactor(@ngtools/webpack): remove NGCC integration
Browse files Browse the repository at this point in the history
This commit removes usage of NGCC which was used to convert old View Engine libraries to Ivy.

BREAKING CHANGE: NGCC integration has been removed and as a result Angular View Engine libraries will no longer work.
  • Loading branch information
alan-agius4 authored and angular-robot[bot] committed Feb 15, 2023
1 parent d2ef386 commit c8ac660
Show file tree
Hide file tree
Showing 3 changed files with 1 addition and 434 deletions.
62 changes: 0 additions & 62 deletions packages/ngtools/webpack/src/ivy/host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import type { CompilerHost } from '@angular/compiler-cli';
import { createHash } from 'crypto';
import * as path from 'path';
import * as ts from 'typescript';
import { NgccProcessor } from '../ngcc_processor';
import { WebpackResourceLoader } from '../resource_loader';
import { normalizePath } from './paths';

Expand Down Expand Up @@ -191,67 +190,6 @@ export function augmentHostWithDependencyCollection(
}
}

export function augmentHostWithNgcc(
host: ts.CompilerHost,
ngcc: NgccProcessor,
moduleResolutionCache?: ts.ModuleResolutionCache,
): void {
augmentResolveModuleNames(
host,
(resolvedModule, moduleName) => {
if (resolvedModule && ngcc) {
ngcc.processModule(moduleName, resolvedModule);
}

return resolvedModule;
},
moduleResolutionCache,
);

if (host.resolveTypeReferenceDirectives) {
const baseResolveTypeReferenceDirectives = host.resolveTypeReferenceDirectives;
host.resolveTypeReferenceDirectives = function (
names: string[] | ts.FileReference[],
...parameters
) {
return names.map((name) => {
const fileName = typeof name === 'string' ? name : name.fileName;
const result = baseResolveTypeReferenceDirectives.call(host, [fileName], ...parameters);

if (result[0] && ngcc) {
ngcc.processModule(fileName, result[0]);
}

return result[0];
});
};
} else {
host.resolveTypeReferenceDirectives = function (
moduleNames: string[] | ts.FileReference[],
containingFile: string,
redirectedReference: ts.ResolvedProjectReference | undefined,
options: ts.CompilerOptions,
) {
return moduleNames.map((name) => {
const fileName = typeof name === 'string' ? name : name.fileName;
const result = ts.resolveTypeReferenceDirective(
fileName,
containingFile,
options,
host,
redirectedReference,
).resolvedTypeReferenceDirective;

if (result && ngcc) {
ngcc.processModule(fileName, result);
}

return result;
});
};
}
}

export function augmentHostWithReplacements(
host: ts.CompilerHost,
replacements: Record<string, string>,
Expand Down
69 changes: 1 addition & 68 deletions packages/ngtools/webpack/src/ivy/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import type { CompilerHost, CompilerOptions, NgtscProgram } from '@angular/compi
import { strict as assert } from 'assert';
import * as ts from 'typescript';
import type { Compilation, Compiler, Module, NormalModule } from 'webpack';
import { NgccProcessor } from '../ngcc_processor';
import { TypeScriptPathsPlugin } from '../paths-plugin';
import { WebpackResourceLoader } from '../resource_loader';
import { SourceFileCache } from './cache';
Expand All @@ -23,7 +22,6 @@ import {
import {
augmentHostWithCaching,
augmentHostWithDependencyCollection,
augmentHostWithNgcc,
augmentHostWithReplacements,
augmentHostWithResources,
augmentHostWithSubstitutions,
Expand Down Expand Up @@ -57,48 +55,11 @@ export interface AngularWebpackPluginOptions {
* The Angular compilation state that is maintained across each Webpack compilation.
*/
interface AngularCompilationState {
ngccProcessor?: NgccProcessor;
resourceLoader?: WebpackResourceLoader;
previousUnused?: Set<string>;
pathsPlugin: TypeScriptPathsPlugin;
}

function initializeNgccProcessor(
compiler: Compiler,
tsconfig: string,
compilerNgccModule: typeof import('@angular/compiler-cli/ngcc') | undefined,
): { processor: NgccProcessor; errors: string[]; warnings: string[] } {
const { inputFileSystem, options: webpackOptions } = compiler;
const mainFields = webpackOptions.resolve?.mainFields?.flat() ?? [];

const errors: string[] = [];
const warnings: string[] = [];
const resolver = compiler.resolverFactory.get('normal', {
// Caching must be disabled because it causes the resolver to become async after a rebuild
cache: false,
extensions: ['.json'],
useSyncFileSystemCalls: true,
});

// The compilerNgccModule field is guaranteed to be defined during a compilation
// due to the `beforeCompile` hook. Usage of this property accessor prior to the
// hook execution is an implementation error.
assert.ok(compilerNgccModule, `'@angular/compiler-cli/ngcc' used prior to Webpack compilation.`);

const processor = new NgccProcessor(
compilerNgccModule,
mainFields,
warnings,
errors,
compiler.context,
tsconfig,
inputFileSystem,
resolver,
);

return { processor, errors, warnings };
}

const PLUGIN_NAME = 'angular-compiler';
const compilationFileEmitters = new WeakMap<Compilation, FileEmitterCollection>();

Expand All @@ -110,7 +71,6 @@ interface FileEmitHistoryItem {
export class AngularWebpackPlugin {
private readonly pluginOptions: AngularWebpackPluginOptions;
private compilerCliModule?: typeof import('@angular/compiler-cli');
private compilerNgccModule?: typeof import('@angular/compiler-cli/ngcc');
private watchMode?: boolean;
private ngtscNextProgram?: NgtscProgram;
private builder?: ts.EmitAndSemanticDiagnosticsBuilderProgram;
Expand Down Expand Up @@ -163,21 +123,13 @@ export class AngularWebpackPlugin {
// Set resolver options
const pathsPlugin = new TypeScriptPathsPlugin();
compiler.hooks.afterResolvers.tap(PLUGIN_NAME, (compiler) => {
// When Ivy is enabled we need to add the fields added by NGCC
// to take precedence over the provided mainFields.
// NGCC adds fields in package.json suffixed with '_ivy_ngcc'
// Example: module -> module__ivy_ngcc
compiler.resolverFactory.hooks.resolveOptions
.for('normal')
.tap(PLUGIN_NAME, (resolveOptions) => {
const originalMainFields = resolveOptions.mainFields;
const ivyMainFields = originalMainFields?.flat().map((f) => `${f}_ivy_ngcc`) ?? [];

resolveOptions.plugins ??= [];
resolveOptions.plugins.push(pathsPlugin);

// https://github.com/webpack/webpack/issues/11635#issuecomment-707016779
return util.cleverMerge(resolveOptions, { mainFields: [...ivyMainFields, '...'] });
return resolveOptions;
});
});

Expand Down Expand Up @@ -216,21 +168,6 @@ export class AngularWebpackPlugin {
state.resourceLoader = new WebpackResourceLoader(this.watchMode);
}

// Initialize and process eager ngcc if not already setup
if (!state.ngccProcessor) {
const { processor, errors, warnings } = initializeNgccProcessor(
compiler,
this.pluginOptions.tsconfig,
this.compilerNgccModule,
);

processor.process();
warnings.forEach((warning) => addWarning(compilation, warning));
errors.forEach((error) => addError(compilation, error));

state.ngccProcessor = processor;
}

// Setup and read TypeScript and Angular compiler configuration
const { compilerOptions, rootNames, errors } = this.loadConfiguration();

Expand Down Expand Up @@ -284,9 +221,6 @@ export class AngularWebpackPlugin {
// Setup source file dependency collection
augmentHostWithDependencyCollection(host, this.fileDependencies, moduleResolutionCache);

// Setup on demand ngcc
augmentHostWithNgcc(host, state.ngccProcessor, moduleResolutionCache);

// Setup resource loading
state.resourceLoader.update(compilation, changedFiles);
augmentHostWithResources(host, state.resourceLoader, {
Expand Down Expand Up @@ -760,7 +694,6 @@ export class AngularWebpackPlugin {
// Once TypeScript provides support for keeping the dynamic import this workaround can
// be dropped.
this.compilerCliModule = await new Function(`return import('@angular/compiler-cli');`)();
this.compilerNgccModule = await new Function(`return import('@angular/compiler-cli/ngcc');`)();
}

private async addFileEmitHistory(
Expand Down
Loading

0 comments on commit c8ac660

Please sign in to comment.