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.

141 lines
3.9 KiB

4 years ago
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const AliasPlugin = require("enhanced-resolve/lib/AliasPlugin");
  7. const ParserHelpers = require("../ParserHelpers");
  8. const nodeLibsBrowser = require("node-libs-browser");
  9. module.exports = class NodeSourcePlugin {
  10. constructor(options) {
  11. this.options = options;
  12. }
  13. apply(compiler) {
  14. const options = this.options;
  15. if (options === false) {
  16. // allow single kill switch to turn off this plugin
  17. return;
  18. }
  19. const getPathToModule = (module, type) => {
  20. if (type === true || (type === undefined && nodeLibsBrowser[module])) {
  21. if (!nodeLibsBrowser[module]) {
  22. throw new Error(
  23. `No browser version for node.js core module ${module} available`
  24. );
  25. }
  26. return nodeLibsBrowser[module];
  27. } else if (type === "mock") {
  28. return require.resolve(`node-libs-browser/mock/${module}`);
  29. } else if (type === "empty") {
  30. return require.resolve("node-libs-browser/mock/empty");
  31. } else {
  32. return module;
  33. }
  34. };
  35. const addExpression = (parser, name, module, type, suffix) => {
  36. suffix = suffix || "";
  37. parser.hooks.expression.for(name).tap("NodeSourcePlugin", () => {
  38. if (
  39. parser.state.module &&
  40. parser.state.module.resource === getPathToModule(module, type)
  41. )
  42. return;
  43. const mockModule = ParserHelpers.requireFileAsExpression(
  44. parser.state.module.context,
  45. getPathToModule(module, type)
  46. );
  47. return ParserHelpers.addParsedVariableToModule(
  48. parser,
  49. name,
  50. mockModule + suffix
  51. );
  52. });
  53. };
  54. compiler.hooks.compilation.tap(
  55. "NodeSourcePlugin",
  56. (compilation, { normalModuleFactory }) => {
  57. const handler = (parser, parserOptions) => {
  58. if (parserOptions.node === false) return;
  59. let localOptions = options;
  60. if (parserOptions.node) {
  61. localOptions = Object.assign({}, localOptions, parserOptions.node);
  62. }
  63. if (localOptions.global) {
  64. parser.hooks.expression
  65. .for("global")
  66. .tap("NodeSourcePlugin", () => {
  67. const retrieveGlobalModule = ParserHelpers.requireFileAsExpression(
  68. parser.state.module.context,
  69. require.resolve("../../buildin/global")
  70. );
  71. return ParserHelpers.addParsedVariableToModule(
  72. parser,
  73. "global",
  74. retrieveGlobalModule
  75. );
  76. });
  77. }
  78. if (localOptions.process) {
  79. const processType = localOptions.process;
  80. addExpression(parser, "process", "process", processType);
  81. }
  82. if (localOptions.console) {
  83. const consoleType = localOptions.console;
  84. addExpression(parser, "console", "console", consoleType);
  85. }
  86. const bufferType = localOptions.Buffer;
  87. if (bufferType) {
  88. addExpression(parser, "Buffer", "buffer", bufferType, ".Buffer");
  89. }
  90. if (localOptions.setImmediate) {
  91. const setImmediateType = localOptions.setImmediate;
  92. addExpression(
  93. parser,
  94. "setImmediate",
  95. "timers",
  96. setImmediateType,
  97. ".setImmediate"
  98. );
  99. addExpression(
  100. parser,
  101. "clearImmediate",
  102. "timers",
  103. setImmediateType,
  104. ".clearImmediate"
  105. );
  106. }
  107. };
  108. normalModuleFactory.hooks.parser
  109. .for("javascript/auto")
  110. .tap("NodeSourcePlugin", handler);
  111. normalModuleFactory.hooks.parser
  112. .for("javascript/dynamic")
  113. .tap("NodeSourcePlugin", handler);
  114. }
  115. );
  116. compiler.hooks.afterResolvers.tap("NodeSourcePlugin", compiler => {
  117. for (const lib of Object.keys(nodeLibsBrowser)) {
  118. if (options[lib] !== false) {
  119. compiler.resolverFactory.hooks.resolver
  120. .for("normal")
  121. .tap("NodeSourcePlugin", resolver => {
  122. new AliasPlugin(
  123. "described-resolve",
  124. {
  125. name: lib,
  126. onlyModule: true,
  127. alias: getPathToModule(lib, options[lib])
  128. },
  129. "resolve"
  130. ).apply(resolver);
  131. });
  132. }
  133. }
  134. });
  135. }
  136. };