Skip to content

Commit 85be04b

Browse files
committed
feat(@ngtools/webpack): allow passing in the right ContextElementDependency class
This should allow multiple webpack versions in the workspace dependencies with no weird errors. Fix #6417 for good.
1 parent 3e8b0e8 commit 85be04b

File tree

2 files changed

+26
-3
lines changed

2 files changed

+26
-3
lines changed

packages/ngtools/webpack/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ The loader works with webpack plugin to compile your TypeScript. It's important
4242
* `skipCodeGeneration`. Optional, defaults to false. Disable code generation and do not refactor the code to bootstrap. This replaces `templateUrl: "string"` with `template: require("string")` (and similar for styles) to allow for webpack to properly link the resources.
4343
* `sourceMap`. Optional. Include sourcemaps.
4444
* `compilerOptions`. Optional. Override options in `tsconfig.json`.
45+
* `contextElementDependencyConstructor`. Optional. Set to `require('webpack/lib/dependencies/ContextElementDependency')` if you are having `No module factory available for dependency type: ContextElementDependency` errors.
4546

4647
## Features
4748
The benefits and ability of using [`@ngtools/webpack`](https://www.npmjs.com/~ngtools) standalone from the Angular CLI as presented in [Stephen Fluin's Angular CLI talk](https://youtu.be/uBRK6cTr4Vk?t=6m45s) at Angular Connect 2016:

packages/ngtools/webpack/src/angular_compiler_plugin.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { ChildProcess, ForkOptions, fork } from 'child_process';
1313
import * as fs from 'fs';
1414
import * as path from 'path';
1515
import * as ts from 'typescript';
16+
import * as webpack from 'webpack';
1617
import { time, timeEnd } from './benchmark';
1718
import { WebpackCompilerHost, workaroundResolve } from './compiler_host';
1819
import { resolveEntryModuleFromMain } from './entry_resolver';
@@ -54,10 +55,13 @@ import {
5455
VirtualWatchFileSystemDecorator,
5556
} from './virtual_file_system_decorator';
5657

57-
58-
const ContextElementDependency = require('webpack/lib/dependencies/ContextElementDependency');
5958
const treeKill = require('tree-kill');
6059

60+
interface ContextElementDependency {}
61+
62+
interface ContextElementDependencyConstructor {
63+
new(modulePath: string, name: string): ContextElementDependency;
64+
}
6165

6266
/**
6367
* Option Constants
@@ -86,6 +90,11 @@ export interface AngularCompilerPluginOptions {
8690
// added to the list of lazy routes
8791
additionalLazyModules?: { [module: string]: string };
8892

93+
// The ContextElementDependency of correct Webpack compilation.
94+
// This is needed when there are multiple Webpack installs.
95+
// tslint:disable-next-line:no-any
96+
contextElementDependencyConstructor?: ContextElementDependencyConstructor;
97+
8998
// Use tsconfig to include path globs.
9099
compilerOptions?: ts.CompilerOptions;
91100

@@ -128,6 +137,8 @@ export class AngularCompilerPlugin {
128137
private _normalizedLocale: string | null;
129138
private _warnings: (string | Error)[] = [];
130139
private _errors: (string | Error)[] = [];
140+
// tslint:disable-next-line:no-any
141+
private _contextElementDependencyConstructor: ContextElementDependencyConstructor;
131142

132143
// TypeChecker process.
133144
private _forkTypeChecker = true;
@@ -267,6 +278,17 @@ export class AngularCompilerPlugin {
267278
this._platformTransformers = options.platformTransformers;
268279
}
269280

281+
// Default ContextElementDependency to the one we can import from here.
282+
if (options.contextElementDependencyConstructor === undefined) {
283+
// Failing to use the right ContextElementDependency will throw the error below:
284+
// "No module factory available for dependency type: ContextElementDependency"
285+
// Hoisting together with peer dependencies can make it so the imported
286+
// ContextElementDependency does not come from the same Webpack instance that is used
287+
// in the compilation. In that case, we can pass the right one as an option to the plugin.
288+
this._contextElementDependencyConstructor =
289+
require('webpack/lib/dependencies/ContextElementDependency');
290+
}
291+
270292
// Create the webpack compiler host.
271293
const webpackCompilerHost = new WebpackCompilerHost(
272294
this._compilerOptions,
@@ -633,7 +655,7 @@ export class AngularCompilerPlugin {
633655
if (modulePath !== null) {
634656
const name = importPath.replace(/(\.ngfactory)?\.(js|ts)$/, '');
635657

636-
return new ContextElementDependency(modulePath, name);
658+
return new this._contextElementDependencyConstructor(modulePath, name);
637659
} else {
638660
return null;
639661
}

0 commit comments

Comments
 (0)