-
Notifications
You must be signed in to change notification settings - Fork 0
/
AsyncCssPlugin.ts
97 lines (82 loc) · 3.56 KB
/
AsyncCssPlugin.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
import * as HtmlWebpackPlugin from "html-webpack-plugin";
import { MessageType, Options } from "./Options";
// tslint:disable-next-line: no-default-export
class AsyncCssPlugin {
public constructor(options: Options = {}) {
Object.assign(this.options, options);
}
// tslint:disable-next-line: no-unsafe-any
public apply({ hooks }: any): void {
if (!hooks) {
this.log("error", "hooks is undefined. Is the version of your webpack package too old?");
}
// tslint:disable-next-line: no-unsafe-any
hooks.compilation.tap(AsyncCssPlugin.name, (compilation: any) => this.checkHook(compilation));
}
private static assertUnreachable(value: never): never {
throw new Error(value);
}
private readonly options: Required<Options> = { logLevel: "warn" };
private logged = false;
private log(messageType: MessageType, message: string) {
if (this.doLog(messageType)) {
if (!this.logged) {
this.logged = true;
console.log(); // Make sure we start our log on a new line
}
console[messageType](`${AsyncCssPlugin.name}[${messageType}]: ${message}`);
}
}
private checkHook(compilation: any) {
// tslint:disable: no-unsafe-any
const { hooks: { htmlWebpackPluginAlterAssetTags } } = compilation;
if (htmlWebpackPluginAlterAssetTags) {
// html-webpack-plugin v3
htmlWebpackPluginAlterAssetTags.tap(AsyncCssPlugin.name, (page: any) => this.checkTags(page, page.head));
// tslint:enable: no-unsafe-any
} else if (HtmlWebpackPlugin && HtmlWebpackPlugin.getHooks) {
// html-webpack-plugin v4
// tslint:disable-next-line: no-unsafe-any
const hooks = HtmlWebpackPlugin.getHooks(compilation);
hooks.alterAssetTags.tap(AsyncCssPlugin.name, (data) => this.checkTags(data, data.assetTags.styles));
} else {
this.log("error", "Cannot find hook. Is your configuration missing the HtmlWebpackPlugin?");
}
}
private doLog(messageType: MessageType) {
switch (this.options.logLevel) {
case "info":
return true;
case "warn":
return messageType !== "info";
case "error":
return messageType === "error";
default:
return AsyncCssPlugin.assertUnreachable(this.options.logLevel);
}
}
private checkTags<TOutput extends { readonly outputName: string }>(output: TOutput, tags: any[]) {
// tslint:disable-next-line: no-unsafe-any
for (const { tagName, attributes } of tags) {
// tslint:disable-next-line: no-unsafe-any
if ((tagName === "link") && (attributes.rel === "stylesheet")) {
this.processTag(output.outputName, attributes);
}
}
return output;
}
// tslint:disable: no-unsafe-any
// tslint:disable-next-line: prefer-function-over-method
private processTag(outputName: string, attributes: any) {
if (attributes.media) {
this.log("warn", `The link for ${attributes.href} already has a media attribute, will not modify.`);
} else {
attributes.media = "print";
attributes.onload = attributes.onload ? `${attributes.onload};` : "";
attributes.onload += "this.media='all'";
this.log("info", `${outputName}: Modified link to ${attributes.href}.`);
}
}
// tslint:enable: no-unsafe-any
}
export = AsyncCssPlugin;