Skip to content

Commit d08d2f9

Browse files
committed
refactor(@ngtools/webpack): restructure webpack resource loader
1 parent 7b1391d commit d08d2f9

File tree

2 files changed

+28
-38
lines changed

2 files changed

+28
-38
lines changed

packages/@ngtools/webpack/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
"enhanced-resolve": "^3.1.0",
3232
"magic-string": "^0.22.3",
3333
"semver": "^5.3.0",
34-
"source-map": "^0.5.6"
34+
"source-map": "^0.5.6",
35+
"webpack-sources": "^1.1.0"
3536
},
3637
"peerDependencies": {
3738
"webpack": "^2.2.0 || ^3.0.0"

packages/@ngtools/webpack/src/resource_loader.ts

+26-37
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as vm from 'vm';
22
import * as path from 'path';
3+
import { OriginalSource } from 'webpack-sources';
34

45
const NodeTemplatePlugin = require('webpack/lib/node/NodeTemplatePlugin');
56
const NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin');
@@ -53,12 +54,7 @@ export class WebpackResourceLoader {
5354
new LoaderTargetPlugin('node')
5455
);
5556

56-
// Store the result of the parent compilation before we start the child compilation
57-
let assetsBeforeCompilation = Object.assign(
58-
{},
59-
this._parentCompilation.assets[outputOptions.filename]
60-
);
61-
57+
// NOTE: This is not needed with webpack 3.6+
6258
// Fix for "Uncaught TypeError: __webpack_require__(...) is not a function"
6359
// Hot module replacement requires that every child compiler has its own
6460
// cache. @see https://github.com/ampedandwired/html-webpack-plugin/pull/179
@@ -71,9 +67,25 @@ export class WebpackResourceLoader {
7167
}
7268
});
7369

70+
childCompiler.plugin('this-compilation', (compilation: any) => {
71+
compilation.plugin('additional-assets', (callback: (err?: Error) => void) => {
72+
const asset = compilation.assets[filePath];
73+
if (asset) {
74+
this._evaluate({ outputName: filePath, source: asset.source() })
75+
.then(output => {
76+
compilation.assets[filePath] = new OriginalSource(output, filePath);
77+
callback();
78+
})
79+
.catch(err => callback(err));
80+
} else {
81+
callback();
82+
}
83+
});
84+
});
85+
7486
// Compile and return a promise
7587
return new Promise((resolve, reject) => {
76-
childCompiler.runAsChild((err: Error, entries: any[], childCompilation: any) => {
88+
childCompiler.compile((err: Error, childCompilation: any) => {
7789
// Resolve / reject the promise
7890
if (childCompilation && childCompilation.errors && childCompilation.errors.length) {
7991
const errorDetails = childCompilation.errors.map(function (error: any) {
@@ -83,47 +95,24 @@ export class WebpackResourceLoader {
8395
} else if (err) {
8496
reject(err);
8597
} else {
86-
// Replace [hash] placeholders in filename
87-
const outputName = this._parentCompilation.mainTemplate.applyPluginsWaterfall(
88-
'asset-path', outputOptions.filename, {
89-
hash: childCompilation.hash,
90-
chunk: entries[0]
91-
});
92-
93-
// Restore the parent compilation to the state like it was before the child compilation.
94-
Object.keys(childCompilation.assets).forEach((fileName) => {
95-
// If it wasn't there and it's a source file (absolute path) - delete it.
96-
if (assetsBeforeCompilation[fileName] === undefined && path.isAbsolute(fileName)) {
97-
delete this._parentCompilation.assets[fileName];
98-
} else {
99-
// Otherwise, add it to the parent compilation.
100-
this._parentCompilation.assets[fileName] = childCompilation.assets[fileName];
101-
}
102-
});
103-
10498
// Save the dependencies for this resource.
105-
this._resourceDependencies.set(outputName, childCompilation.fileDependencies);
99+
this._resourceDependencies.set(filePath, childCompilation.fileDependencies);
106100

107101
resolve({
108102
// Output name.
109-
outputName,
103+
outputName: filePath,
110104
// Compiled code.
111-
source: childCompilation.assets[outputName].source()
105+
source: childCompilation.assets[filePath].source()
112106
});
113107
}
114108
});
115109
});
116110
}
117111

118-
private _evaluate(output: CompilationOutput): Promise<string> {
112+
private _evaluate({ outputName, source }: CompilationOutput): Promise<string> {
119113
try {
120-
const outputName = output.outputName;
121-
const vmContext = vm.createContext(Object.assign({ require: require }, global));
122-
const vmScript = new vm.Script(output.source, { filename: outputName });
123-
124-
// Evaluate code and cast to string
125-
let evaluatedSource: string;
126-
evaluatedSource = vmScript.runInContext(vmContext);
114+
// Evaluate code
115+
const evaluatedSource = vm.runInNewContext(source, undefined, { filename: outputName });
127116

128117
if (typeof evaluatedSource == 'string') {
129118
return Promise.resolve(evaluatedSource);
@@ -137,6 +126,6 @@ export class WebpackResourceLoader {
137126

138127
get(filePath: string): Promise<string> {
139128
return this._compile(filePath)
140-
.then((result: CompilationOutput) => this._evaluate(result));
129+
.then((result: CompilationOutput) => result.source);
141130
}
142131
}

0 commit comments

Comments
 (0)