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.

DllReferencePlugin.js 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const parseJson = require("json-parse-better-errors");
  7. const DelegatedSourceDependency = require("./dependencies/DelegatedSourceDependency");
  8. const DelegatedModuleFactoryPlugin = require("./DelegatedModuleFactoryPlugin");
  9. const ExternalModuleFactoryPlugin = require("./ExternalModuleFactoryPlugin");
  10. const DelegatedExportsDependency = require("./dependencies/DelegatedExportsDependency");
  11. const NullFactory = require("./NullFactory");
  12. const makePathsRelative = require("./util/identifier").makePathsRelative;
  13. const WebpackError = require("./WebpackError");
  14. const validateOptions = require("schema-utils");
  15. const schema = require("../schemas/plugins/DllReferencePlugin.json");
  16. /** @typedef {import("../declarations/plugins/DllReferencePlugin").DllReferencePluginOptions} DllReferencePluginOptions */
  17. /** @typedef {import("../declarations/plugins/DllReferencePlugin").DllReferencePluginOptionsManifest} DllReferencePluginOptionsManifest */
  18. class DllReferencePlugin {
  19. /**
  20. * @param {DllReferencePluginOptions} options options object
  21. */
  22. constructor(options) {
  23. validateOptions(schema, options, "Dll Reference Plugin");
  24. this.options = options;
  25. }
  26. apply(compiler) {
  27. compiler.hooks.compilation.tap(
  28. "DllReferencePlugin",
  29. (compilation, { normalModuleFactory }) => {
  30. compilation.dependencyFactories.set(
  31. DelegatedSourceDependency,
  32. normalModuleFactory
  33. );
  34. compilation.dependencyFactories.set(
  35. DelegatedExportsDependency,
  36. new NullFactory()
  37. );
  38. }
  39. );
  40. compiler.hooks.beforeCompile.tapAsync(
  41. "DllReferencePlugin",
  42. (params, callback) => {
  43. if ("manifest" in this.options) {
  44. const manifest = this.options.manifest;
  45. if (typeof manifest === "string") {
  46. params.compilationDependencies.add(manifest);
  47. compiler.inputFileSystem.readFile(manifest, (err, result) => {
  48. if (err) return callback(err);
  49. // Catch errors parsing the manifest so that blank
  50. // or malformed manifest files don't kill the process.
  51. try {
  52. params["dll reference " + manifest] = parseJson(
  53. result.toString("utf-8")
  54. );
  55. } catch (e) {
  56. // Store the error in the params so that it can
  57. // be added as a compilation error later on.
  58. const manifestPath = makePathsRelative(
  59. compiler.options.context,
  60. manifest
  61. );
  62. params[
  63. "dll reference parse error " + manifest
  64. ] = new DllManifestError(manifestPath, e.message);
  65. }
  66. return callback();
  67. });
  68. return;
  69. }
  70. }
  71. return callback();
  72. }
  73. );
  74. compiler.hooks.compile.tap("DllReferencePlugin", params => {
  75. let name = this.options.name;
  76. let sourceType = this.options.sourceType;
  77. let content =
  78. "content" in this.options ? this.options.content : undefined;
  79. if ("manifest" in this.options) {
  80. let manifestParameter = this.options.manifest;
  81. let manifest;
  82. if (typeof manifestParameter === "string") {
  83. // If there was an error parsing the manifest
  84. // file, exit now because the error will be added
  85. // as a compilation error in the "compilation" hook.
  86. if (params["dll reference parse error " + manifestParameter]) {
  87. return;
  88. }
  89. manifest =
  90. /** @type {DllReferencePluginOptionsManifest} */ (params[
  91. "dll reference " + manifestParameter
  92. ]);
  93. } else {
  94. manifest = manifestParameter;
  95. }
  96. if (manifest) {
  97. if (!name) name = manifest.name;
  98. if (!sourceType) sourceType = manifest.type;
  99. if (!content) content = manifest.content;
  100. }
  101. }
  102. const externals = {};
  103. const source = "dll-reference " + name;
  104. externals[source] = name;
  105. const normalModuleFactory = params.normalModuleFactory;
  106. new ExternalModuleFactoryPlugin(sourceType || "var", externals).apply(
  107. normalModuleFactory
  108. );
  109. new DelegatedModuleFactoryPlugin({
  110. source: source,
  111. type: this.options.type,
  112. scope: this.options.scope,
  113. context: this.options.context || compiler.options.context,
  114. content,
  115. extensions: this.options.extensions
  116. }).apply(normalModuleFactory);
  117. });
  118. compiler.hooks.compilation.tap(
  119. "DllReferencePlugin",
  120. (compilation, params) => {
  121. if ("manifest" in this.options) {
  122. let manifest = this.options.manifest;
  123. if (typeof manifest === "string") {
  124. // If there was an error parsing the manifest file, add the
  125. // error as a compilation error to make the compilation fail.
  126. let e = params["dll reference parse error " + manifest];
  127. if (e) {
  128. compilation.errors.push(e);
  129. }
  130. }
  131. }
  132. }
  133. );
  134. }
  135. }
  136. class DllManifestError extends WebpackError {
  137. constructor(filename, message) {
  138. super();
  139. this.name = "DllManifestError";
  140. this.message = `Dll manifest ${filename}\n${message}`;
  141. Error.captureStackTrace(this, this.constructor);
  142. }
  143. }
  144. module.exports = DllReferencePlugin;