• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

andreashuber69 / async-css-plugin / #97

24 May 2025 06:28AM UTC coverage: 100.0%. Remained the same
#97

push

andreashuber69
docs: fix link text

20 of 20 branches covered (100.0%)

Branch coverage included in aggregate %.

23 of 23 relevant lines covered (100.0%)

5.22 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/src/AsyncCssPlugin.ts
1
// https://github.com/andreashuber69/async-css-plugin/blob/develop/README.md#----async-css-plugin
2

3
import HtmlWebpackPlugin from "html-webpack-plugin";
4
import type { Compilation, Compiler } from "webpack";
5

6
import type { MessageType, Options } from "./Options.ts";
7

8
class AsyncCssPlugin {
9
    public constructor(options?: Options) {
10
        ({ logLevel: this.logLevel } = { logLevel: "warn", ...options });
10✔
11

12
        switch (this.logLevel) {
10✔
13
            case "info":
14
            case "warn":
15
            case "error":
16
                break;
9✔
17
            default:
18
                throw new Error(`options.logLevel is invalid: ${this.logLevel}.`);
1✔
19
        }
20
    }
21

22
    public apply(compiler: Partial<Compiler> | null | undefined): void {
23
        const compilation = compiler?.hooks?.compilation;
9✔
24

25
        if (!compilation?.tap) {
9✔
26
            throw new Error("compiler?.hooks?.compilation?.tap is undefined. Is your webpack package version too old?");
1✔
27
        }
28

29
        compilation.tap(AsyncCssPlugin.name, (c) => this.checkHook(c));
9✔
30
    }
31

32
    private static log(messageType: MessageType, message: string) {
33
        console[messageType](`\n${AsyncCssPlugin.name}[${messageType}]: ${message}`);
3✔
34
    }
35

36
    private readonly logLevel: MessageType;
37

38
    private checkHook(compilation: Compilation) {
39
        const alterAssetTags = HtmlWebpackPlugin.getHooks?.(compilation).alterAssetTags;
9✔
40

41
        if (!alterAssetTags?.tap) {
9✔
42
            throw new Error("Cannot get alterAssetTags hook. Is your config missing the HtmlWebpackPlugin?");
1✔
43
        }
44

45
        alterAssetTags.tap(AsyncCssPlugin.name, (data) => this.checkTags(data, data?.assetTags?.styles));
8✔
46
    }
47

48
    private checkTags<Output extends { readonly outputName: string }>(
49
        output: Output,
50
        styleTags: readonly HtmlWebpackPlugin.HtmlTagObject[] | null | undefined,
51
    ) {
52
        for (const { tagName, attributes } of styleTags ?? []) {
7✔
53
            if ((tagName === "link") && (attributes?.["rel"] === "stylesheet")) {
4✔
54
                this.processTag(output.outputName, attributes);
3✔
55
            }
56
        }
57

58
        return output;
7✔
59
    }
60

61
    private processTag(outputName: string, attributes: HtmlWebpackPlugin.HtmlTagObject["attributes"]) {
62
        if (attributes["media"]) {
3✔
63
            const message = `The link for ${attributes["href"]} already has a media attribute, will not modify.`;
1✔
64
            (this.logLevel !== "error") && AsyncCssPlugin.log("warn", message);
1✔
65
        } else {
66
            Object.assign(attributes, {
2✔
67
                media: "print",
68
                onload: [attributes["onload"], "this.media='all'"].filter(Boolean).join(";"),
69
            });
70

71
            const message = `${outputName}: Modified link to ${attributes["href"]}.`;
2✔
72
            (this.logLevel === "info") && AsyncCssPlugin.log("info", message);
2✔
73
        }
74
    }
75
}
76

77
// eslint-disable-next-line import/no-default-export
78
export default AsyncCssPlugin;
79

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc