loader.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. 'use strict';
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.pitch = pitch;
  6. exports.default = function () {};
  7. var _fs = require('fs');
  8. var _fs2 = _interopRequireDefault(_fs);
  9. var _path = require('path');
  10. var _path2 = _interopRequireDefault(_path);
  11. var _module = require('module');
  12. var _module2 = _interopRequireDefault(_module);
  13. var _loaderUtils = require('loader-utils');
  14. var _loaderUtils2 = _interopRequireDefault(_loaderUtils);
  15. var _NodeTemplatePlugin = require('webpack/lib/node/NodeTemplatePlugin');
  16. var _NodeTemplatePlugin2 = _interopRequireDefault(_NodeTemplatePlugin);
  17. var _NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin');
  18. var _NodeTargetPlugin2 = _interopRequireDefault(_NodeTargetPlugin);
  19. var _LibraryTemplatePlugin = require('webpack/lib/LibraryTemplatePlugin');
  20. var _LibraryTemplatePlugin2 = _interopRequireDefault(_LibraryTemplatePlugin);
  21. var _SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin');
  22. var _SingleEntryPlugin2 = _interopRequireDefault(_SingleEntryPlugin);
  23. var _LimitChunkCountPlugin = require('webpack/lib/optimize/LimitChunkCountPlugin');
  24. var _LimitChunkCountPlugin2 = _interopRequireDefault(_LimitChunkCountPlugin);
  25. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  26. const NS = _path2.default.dirname(_fs2.default.realpathSync(__filename));
  27. const pluginName = 'mini-css-extract-plugin';
  28. const exec = (loaderContext, code, filename) => {
  29. const module = new _module2.default(filename, loaderContext);
  30. module.paths = _module2.default._nodeModulePaths(loaderContext.context); // eslint-disable-line no-underscore-dangle
  31. module.filename = filename;
  32. module._compile(code, filename); // eslint-disable-line no-underscore-dangle
  33. return module.exports;
  34. };
  35. const findModuleById = (modules, id) => {
  36. for (const module of modules) {
  37. if (module.id === id) {
  38. return module;
  39. }
  40. }
  41. return null;
  42. };
  43. function pitch(request) {
  44. const query = _loaderUtils2.default.getOptions(this) || {};
  45. const loaders = this.loaders.slice(this.loaderIndex + 1);
  46. this.addDependency(this.resourcePath);
  47. const childFilename = '*'; // eslint-disable-line no-path-concat
  48. const publicPath = typeof query.publicPath === 'string' ? query.publicPath : this._compilation.outputOptions.publicPath;
  49. const outputOptions = {
  50. filename: childFilename,
  51. publicPath
  52. };
  53. const childCompiler = this._compilation.createChildCompiler(`${pluginName} ${request}`, outputOptions);
  54. new _NodeTemplatePlugin2.default(outputOptions).apply(childCompiler);
  55. new _LibraryTemplatePlugin2.default(null, 'commonjs2').apply(childCompiler);
  56. new _NodeTargetPlugin2.default().apply(childCompiler);
  57. new _SingleEntryPlugin2.default(this.context, `!!${request}`, pluginName).apply(childCompiler);
  58. new _LimitChunkCountPlugin2.default({ maxChunks: 1 }).apply(childCompiler);
  59. // We set loaderContext[NS] = false to indicate we already in
  60. // a child compiler so we don't spawn another child compilers from there.
  61. childCompiler.hooks.thisCompilation.tap(`${pluginName} loader`, compilation => {
  62. compilation.hooks.normalModuleLoader.tap(`${pluginName} loader`, (loaderContext, module) => {
  63. loaderContext[NS] = false; // eslint-disable-line no-param-reassign
  64. if (module.request === request) {
  65. module.loaders = loaders.map(loader => {
  66. // eslint-disable-line no-param-reassign
  67. return {
  68. loader: loader.path,
  69. options: loader.options,
  70. ident: loader.ident
  71. };
  72. });
  73. }
  74. });
  75. });
  76. let source;
  77. childCompiler.hooks.afterCompile.tap(pluginName, compilation => {
  78. source = compilation.assets[childFilename] && compilation.assets[childFilename].source();
  79. // Remove all chunk assets
  80. compilation.chunks.forEach(chunk => {
  81. chunk.files.forEach(file => {
  82. delete compilation.assets[file]; // eslint-disable-line no-param-reassign
  83. });
  84. });
  85. });
  86. const callback = this.async();
  87. childCompiler.runAsChild((err, entries, compilation) => {
  88. if (err) return callback(err);
  89. if (compilation.errors.length > 0) {
  90. return callback(compilation.errors[0]);
  91. }
  92. compilation.fileDependencies.forEach(dep => {
  93. this.addDependency(dep);
  94. }, this);
  95. compilation.contextDependencies.forEach(dep => {
  96. this.addContextDependency(dep);
  97. }, this);
  98. if (!source) {
  99. return callback(new Error("Didn't get a result from child compiler"));
  100. }
  101. let text;
  102. let locals;
  103. try {
  104. text = exec(this, source, request);
  105. locals = text && text.locals;
  106. if (!Array.isArray(text)) {
  107. text = [[null, text]];
  108. } else {
  109. text = text.map(line => {
  110. const module = findModuleById(compilation.modules, line[0]);
  111. return {
  112. identifier: module.identifier(),
  113. content: line[1],
  114. media: line[2],
  115. sourceMap: line[3]
  116. };
  117. });
  118. }
  119. this[NS](text);
  120. } catch (e) {
  121. return callback(e);
  122. }
  123. let resultSource = `// extracted by ${pluginName}`;
  124. if (locals && typeof resultSource !== 'undefined') {
  125. resultSource += `\nmodule.exports = ${JSON.stringify(locals)};`;
  126. }
  127. return callback(null, resultSource);
  128. });
  129. }