马宇豪
2024-07-16 f591c27b57e2418c9495bc02ae8cfff84d35bc18
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
120
121
122
123
124
125
126
127
128
129
/*
    MIT License http://www.opensource.org/licenses/mit-license.php
    Author Tobias Koppers @sokra
*/
 
"use strict";
 
const { ConcatSource } = require("webpack-sources");
const Compilation = require("./Compilation");
const ModuleFilenameHelpers = require("./ModuleFilenameHelpers");
const Template = require("./Template");
const createSchemaValidation = require("./util/create-schema-validation");
 
/** @typedef {import("../declarations/plugins/BannerPlugin").BannerPluginArgument} BannerPluginArgument */
/** @typedef {import("../declarations/plugins/BannerPlugin").BannerPluginOptions} BannerPluginOptions */
/** @typedef {import("./Compiler")} Compiler */
 
const validate = createSchemaValidation(
    require("../schemas/plugins/BannerPlugin.check.js"),
    () => require("../schemas/plugins/BannerPlugin.json"),
    {
        name: "Banner Plugin",
        baseDataPath: "options"
    }
);
 
/**
 * @param {string} str string to wrap
 * @returns {string} wrapped string
 */
const wrapComment = str => {
    if (!str.includes("\n")) {
        return Template.toComment(str);
    }
    return `/*!\n * ${str
        .replace(/\*\//g, "* /")
        .split("\n")
        .join("\n * ")
        .replace(/\s+\n/g, "\n")
        .trimEnd()}\n */`;
};
 
class BannerPlugin {
    /**
     * @param {BannerPluginArgument} options options object
     */
    constructor(options) {
        if (typeof options === "string" || typeof options === "function") {
            options = {
                banner: options
            };
        }
 
        validate(options);
 
        this.options = options;
 
        const bannerOption = options.banner;
        if (typeof bannerOption === "function") {
            const getBanner = bannerOption;
            this.banner = this.options.raw
                ? getBanner
                : data => wrapComment(getBanner(data));
        } else {
            const banner = this.options.raw
                ? bannerOption
                : wrapComment(bannerOption);
            this.banner = () => banner;
        }
    }
 
    /**
     * Apply the plugin
     * @param {Compiler} compiler the compiler instance
     * @returns {void}
     */
    apply(compiler) {
        const options = this.options;
        const banner = this.banner;
        const matchObject = ModuleFilenameHelpers.matchObject.bind(
            undefined,
            options
        );
        const cache = new WeakMap();
 
        compiler.hooks.compilation.tap("BannerPlugin", compilation => {
            compilation.hooks.processAssets.tap(
                {
                    name: "BannerPlugin",
                    stage: Compilation.PROCESS_ASSETS_STAGE_ADDITIONS
                },
                () => {
                    for (const chunk of compilation.chunks) {
                        if (options.entryOnly && !chunk.canBeInitial()) {
                            continue;
                        }
 
                        for (const file of chunk.files) {
                            if (!matchObject(file)) {
                                continue;
                            }
 
                            const data = {
                                chunk,
                                filename: file
                            };
 
                            const comment = compilation.getPath(banner, data);
 
                            compilation.updateAsset(file, old => {
                                let cached = cache.get(old);
                                if (!cached || cached.comment !== comment) {
                                    const source = options.footer
                                        ? new ConcatSource(old, "\n", comment)
                                        : new ConcatSource(comment, "\n", old);
                                    cache.set(old, { source, comment });
                                    return source;
                                }
                                return cached.source;
                            });
                        }
                    }
                }
            );
        });
    }
}
 
module.exports = BannerPlugin;