Skip to content

Commit f446252

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

File tree

2 files changed

+31
-35
lines changed

2 files changed

+31
-35
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

+29-34
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,30 @@ 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];
98+
Object.keys(childCompilation.assets).forEach(assetName => {
99+
if (assetName !== filePath && this._parentCompilation.assets[assetName] == undefined) {
100+
this._parentCompilation.assets[assetName] = childCompilation.assets[assetName];
101101
}
102102
});
103103

104104
// Save the dependencies for this resource.
105-
this._resourceDependencies.set(outputName, childCompilation.fileDependencies);
105+
this._resourceDependencies.set(filePath, childCompilation.fileDependencies);
106106

107107
resolve({
108108
// Output name.
109-
outputName,
109+
outputName: filePath,
110110
// Compiled code.
111-
source: childCompilation.assets[outputName].source()
111+
source: childCompilation.assets[filePath].source()
112112
});
113113
}
114114
});
115115
});
116116
}
117117

118-
private _evaluate(output: CompilationOutput): Promise<string> {
118+
private _evaluate({ outputName, source }: CompilationOutput): Promise<string> {
119119
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);
120+
// Evaluate code
121+
const evaluatedSource = vm.runInNewContext(source, undefined, { filename: outputName });
127122

128123
if (typeof evaluatedSource == 'string') {
129124
return Promise.resolve(evaluatedSource);
@@ -137,6 +132,6 @@ export class WebpackResourceLoader {
137132

138133
get(filePath: string): Promise<string> {
139134
return this._compile(filePath)
140-
.then((result: CompilationOutput) => this._evaluate(result));
135+
.then((result: CompilationOutput) => result.source);
141136
}
142137
}

0 commit comments

Comments
 (0)