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
13 changes: 6 additions & 7 deletions packages/ngtools/webpack/src/ivy/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,19 @@ import * as path from 'path';
import { AngularPluginSymbol, FileEmitterCollection } from './symbol';

export function angularWebpackLoader(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this: any,
this: import('webpack').LoaderContext<unknown> & {
[AngularPluginSymbol]?: FileEmitterCollection;
},
content: string,
// Source map types are broken in the webpack type definitions
// eslint-disable-next-line @typescript-eslint/no-explicit-any
map: any,
map: string,
) {
const callback = this.async();
if (!callback) {
throw new Error('Invalid webpack version');
}

const fileEmitter = this._compilation[AngularPluginSymbol] as FileEmitterCollection;
if (typeof fileEmitter !== 'object') {
const fileEmitter = this[AngularPluginSymbol];
if (!fileEmitter || typeof fileEmitter !== 'object') {
if (this.resourcePath.endsWith('.js')) {
// Passthrough for JS files when no plugin is used
this.callback(undefined, content, map);
Expand Down
38 changes: 23 additions & 15 deletions packages/ngtools/webpack/src/ivy/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,6 @@ export interface AngularWebpackPluginOptions {
inlineStyleFileExtension?: string;
}

// Add support for missing properties in Webpack types as well as the loader's file emitter
interface WebpackCompilation extends Compilation {
[AngularPluginSymbol]: FileEmitterCollection;
}

function initializeNgccProcessor(
compiler: Compiler,
tsconfig: string,
Expand Down Expand Up @@ -87,6 +82,7 @@ function hashContent(content: string): Uint8Array {
}

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

export class AngularWebpackPlugin {
private readonly pluginOptions: AngularWebpackPluginOptions;
Expand Down Expand Up @@ -151,14 +147,9 @@ export class AngularWebpackPlugin {
let ngccProcessor: NgccProcessor | undefined;
let resourceLoader: WebpackResourceLoader | undefined;
let previousUnused: Set<string> | undefined;
compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (thisCompilation) => {
const compilation = thisCompilation as WebpackCompilation;

compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => {
// Register plugin to ensure deterministic emit order in multi-plugin usage
if (!compilation[AngularPluginSymbol]) {
compilation[AngularPluginSymbol] = new FileEmitterCollection();
}
const emitRegistration = compilation[AngularPluginSymbol].register();
const emitRegistration = this.registerWithCompilation(compilation);

this.watchMode = compiler.watchMode;

Expand All @@ -182,7 +173,7 @@ export class AngularWebpackPlugin {
}

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

// Create diagnostics reporter and report configuration file errors
const diagnosticsReporter = createDiagnosticsReporter(compilation);
Expand Down Expand Up @@ -314,6 +305,23 @@ export class AngularWebpackPlugin {
});
}

private registerWithCompilation(compilation: Compilation) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: missing return type

let fileEmitters = compilationFileEmitters.get(compilation);
if (!fileEmitters) {
fileEmitters = new FileEmitterCollection();
compilationFileEmitters.set(compilation, fileEmitters);
compilation.compiler.webpack.NormalModule.getCompilationHooks(compilation).loader.tap(
PLUGIN_NAME,
(loaderContext: { [AngularPluginSymbol]?: FileEmitterCollection }) => {
loaderContext[AngularPluginSymbol] = fileEmitters;
},
);
}
const emitRegistration = fileEmitters.register();

return emitRegistration;
}

private markResourceUsed(normalizedResourcePath: string, currentUnused: Set<string>): void {
if (!currentUnused.has(normalizedResourcePath)) {
return;
Expand All @@ -331,7 +339,7 @@ export class AngularWebpackPlugin {

private async rebuildRequiredFiles(
modules: Iterable<Module>,
compilation: WebpackCompilation,
compilation: Compilation,
fileEmitter: FileEmitter,
): Promise<void> {
if (this.requiredFilesToEmit.size === 0) {
Expand Down Expand Up @@ -377,7 +385,7 @@ export class AngularWebpackPlugin {
this.requiredFilesToEmitCache.clear();
}

private loadConfiguration(compilation: WebpackCompilation) {
private loadConfiguration() {
const {
options: compilerOptions,
rootNames,
Expand Down