提交学习笔记专用
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

134 lines
3.5 KiB

  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { ConcatSource } = require("webpack-sources");
  7. const Compilation = require("./Compilation");
  8. const ModuleFilenameHelpers = require("./ModuleFilenameHelpers");
  9. const Template = require("./Template");
  10. const createSchemaValidation = require("./util/create-schema-validation");
  11. /** @typedef {import("../declarations/plugins/BannerPlugin").BannerFunction} BannerFunction */
  12. /** @typedef {import("../declarations/plugins/BannerPlugin").BannerPluginArgument} BannerPluginArgument */
  13. /** @typedef {import("./Compilation").PathData} PathData */
  14. /** @typedef {import("./Compiler")} Compiler */
  15. /** @typedef {import("./TemplatedPathPlugin").TemplatePath} TemplatePath */
  16. const validate = createSchemaValidation(
  17. /** @type {((value: typeof import("../schemas/plugins/BannerPlugin.json")) => boolean)} */
  18. (require("../schemas/plugins/BannerPlugin.check")),
  19. () => require("../schemas/plugins/BannerPlugin.json"),
  20. {
  21. name: "Banner Plugin",
  22. baseDataPath: "options"
  23. }
  24. );
  25. /**
  26. * @param {string} str string to wrap
  27. * @returns {string} wrapped string
  28. */
  29. const wrapComment = (str) => {
  30. if (!str.includes("\n")) {
  31. return Template.toComment(str);
  32. }
  33. return `/*!\n * ${str
  34. .replace(/\*\//g, "* /")
  35. .split("\n")
  36. .join("\n * ")
  37. .replace(/\s+\n/g, "\n")
  38. .trimEnd()}\n */`;
  39. };
  40. const PLUGIN_NAME = "BannerPlugin";
  41. class BannerPlugin {
  42. /**
  43. * @param {BannerPluginArgument} options options object
  44. */
  45. constructor(options) {
  46. if (typeof options === "string" || typeof options === "function") {
  47. options = {
  48. banner: options
  49. };
  50. }
  51. validate(options);
  52. this.options = options;
  53. const bannerOption = options.banner;
  54. if (typeof bannerOption === "function") {
  55. const getBanner = bannerOption;
  56. /** @type {BannerFunction} */
  57. this.banner = this.options.raw
  58. ? getBanner
  59. : /** @type {BannerFunction} */ (data) => wrapComment(getBanner(data));
  60. } else {
  61. const banner = this.options.raw
  62. ? bannerOption
  63. : wrapComment(bannerOption);
  64. /** @type {BannerFunction} */
  65. this.banner = () => banner;
  66. }
  67. }
  68. /**
  69. * Apply the plugin
  70. * @param {Compiler} compiler the compiler instance
  71. * @returns {void}
  72. */
  73. apply(compiler) {
  74. const options = this.options;
  75. const banner = this.banner;
  76. const matchObject = ModuleFilenameHelpers.matchObject.bind(
  77. undefined,
  78. options
  79. );
  80. const cache = new WeakMap();
  81. const stage =
  82. this.options.stage || Compilation.PROCESS_ASSETS_STAGE_ADDITIONS;
  83. compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
  84. compilation.hooks.processAssets.tap({ name: PLUGIN_NAME, stage }, () => {
  85. for (const chunk of compilation.chunks) {
  86. if (options.entryOnly && !chunk.canBeInitial()) {
  87. continue;
  88. }
  89. for (const file of chunk.files) {
  90. if (!matchObject(file)) {
  91. continue;
  92. }
  93. /** @type {PathData} */
  94. const data = { chunk, filename: file };
  95. const comment = compilation.getPath(
  96. /** @type {TemplatePath} */
  97. (banner),
  98. data
  99. );
  100. compilation.updateAsset(file, (old) => {
  101. const cached = cache.get(old);
  102. if (!cached || cached.comment !== comment) {
  103. const source = options.footer
  104. ? new ConcatSource(old, "\n", comment)
  105. : new ConcatSource(comment, "\n", old);
  106. cache.set(old, { source, comment });
  107. return source;
  108. }
  109. return cached.source;
  110. });
  111. }
  112. }
  113. });
  114. });
  115. }
  116. }
  117. module.exports = BannerPlugin;