-
Notifications
You must be signed in to change notification settings - Fork 12k
/
Copy pathindex-html-webpack-plugin.ts
119 lines (105 loc) · 3.5 KB
/
index-html-webpack-plugin.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as path from 'path';
import { Compiler, compilation } from 'webpack';
import { RawSource } from 'webpack-sources';
import {
CrossOriginValue,
FileInfo,
augmentIndexHtml,
} from '../../utils/index-file/augment-index-html';
import { IndexHtmlTransform } from '../../utils/index-file/write-index-html';
import { stripBom } from '../../utils/strip-bom';
export interface IndexHtmlWebpackPluginOptions {
input: string;
output: string;
baseHref?: string;
entrypoints: string[];
deployUrl?: string;
sri: boolean;
noModuleEntrypoints: string[];
moduleEntrypoints: string[];
postTransform?: IndexHtmlTransform;
crossOrigin?: CrossOriginValue;
lang?: string;
}
function readFile(filename: string, compilation: compilation.Compilation): Promise<string> {
return new Promise<string>((resolve, reject) => {
compilation.inputFileSystem.readFile(filename, (err: Error, data: Buffer) => {
if (err) {
reject(err);
return;
}
resolve(stripBom(data.toString()));
});
});
}
export class IndexHtmlWebpackPlugin {
private _options: IndexHtmlWebpackPluginOptions;
constructor(options?: Partial<IndexHtmlWebpackPluginOptions>) {
this._options = {
input: 'index.html',
output: 'index.html',
entrypoints: ['polyfills', 'main'],
noModuleEntrypoints: [],
moduleEntrypoints: [],
sri: false,
...options,
};
}
apply(compiler: Compiler) {
compiler.hooks.emit.tapPromise('index-html-webpack-plugin', async compilation => {
// Get input html file
const inputContent = await readFile(this._options.input, compilation);
compilation.fileDependencies.add(this._options.input);
// Get all files for selected entrypoints
const files: FileInfo[] = [];
const noModuleFiles: FileInfo[] = [];
const moduleFiles: FileInfo[] = [];
for (const [entryName, entrypoint] of compilation.entrypoints) {
const entryFiles: FileInfo[] = ((entrypoint && entrypoint.getFiles()) || []).map(
(f: string): FileInfo => ({
name: entryName,
file: f,
extension: path.extname(f),
}),
);
if (this._options.noModuleEntrypoints.includes(entryName)) {
noModuleFiles.push(...entryFiles);
} else if (this._options.moduleEntrypoints.includes(entryName)) {
moduleFiles.push(...entryFiles);
} else {
files.push(...entryFiles);
}
}
const loadOutputFile = async (name: string) => {
const data = compilation.assets[name].source();
return typeof data === 'string' ? data : data.toString();
};
let indexSource = await augmentIndexHtml({
input: this._options.input,
inputContent,
baseHref: this._options.baseHref,
deployUrl: this._options.deployUrl,
sri: this._options.sri,
crossOrigin: this._options.crossOrigin,
files,
noModuleFiles,
loadOutputFile,
moduleFiles,
entrypoints: this._options.entrypoints,
lang: this._options.lang,
});
if (this._options.postTransform) {
indexSource = await this._options.postTransform(indexSource);
}
// Add to compilation assets
compilation.assets[this._options.output] = new RawSource(indexSource);
});
}
}