UNPKG

2.92 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4 */
5
6"use strict";
7
8const { ConcatSource } = require("webpack-sources");
9const ModuleFilenameHelpers = require("./ModuleFilenameHelpers");
10const Template = require("./Template");
11
12const validateOptions = require("schema-utils");
13const schema = require("../schemas/plugins/BannerPlugin.json");
14
15/** @typedef {import("../declarations/plugins/BannerPlugin").BannerPluginArgument} BannerPluginArgument */
16/** @typedef {import("../declarations/plugins/BannerPlugin").BannerPluginOptions} BannerPluginOptions */
17
18const wrapComment = str => {
19 if (!str.includes("\n")) {
20 return Template.toComment(str);
21 }
22 return `/*!\n * ${str
23 .replace(/\*\//g, "* /")
24 .split("\n")
25 .join("\n * ")}\n */`;
26};
27
28class BannerPlugin {
29 /**
30 * @param {BannerPluginArgument} options options object
31 */
32 constructor(options) {
33 if (arguments.length > 1) {
34 throw new Error(
35 "BannerPlugin only takes one argument (pass an options object)"
36 );
37 }
38
39 validateOptions(schema, options, "Banner Plugin");
40
41 if (typeof options === "string" || typeof options === "function") {
42 options = {
43 banner: options
44 };
45 }
46
47 /** @type {BannerPluginOptions} */
48 this.options = options;
49
50 const bannerOption = options.banner;
51 if (typeof bannerOption === "function") {
52 const getBanner = bannerOption;
53 this.banner = this.options.raw
54 ? getBanner
55 : data => wrapComment(getBanner(data));
56 } else {
57 const banner = this.options.raw
58 ? bannerOption
59 : wrapComment(bannerOption);
60 this.banner = () => banner;
61 }
62 }
63
64 apply(compiler) {
65 const options = this.options;
66 const banner = this.banner;
67 const matchObject = ModuleFilenameHelpers.matchObject.bind(
68 undefined,
69 options
70 );
71
72 compiler.hooks.compilation.tap("BannerPlugin", compilation => {
73 compilation.hooks.optimizeChunkAssets.tap("BannerPlugin", chunks => {
74 for (const chunk of chunks) {
75 if (options.entryOnly && !chunk.canBeInitial()) {
76 continue;
77 }
78
79 for (const file of chunk.files) {
80 if (!matchObject(file)) {
81 continue;
82 }
83
84 let query = "";
85 let filename = file;
86 const hash = compilation.hash;
87 const querySplit = filename.indexOf("?");
88
89 if (querySplit >= 0) {
90 query = filename.substr(querySplit);
91 filename = filename.substr(0, querySplit);
92 }
93
94 const lastSlashIndex = filename.lastIndexOf("/");
95
96 const basename =
97 lastSlashIndex === -1
98 ? filename
99 : filename.substr(lastSlashIndex + 1);
100
101 const data = {
102 hash,
103 chunk,
104 filename,
105 basename,
106 query
107 };
108
109 const comment = compilation.getPath(banner(data), data);
110
111 compilation.updateAsset(
112 file,
113 old => new ConcatSource(comment, "\n", old)
114 );
115 }
116 }
117 });
118 });
119 }
120}
121
122module.exports = BannerPlugin;