plugin.js 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. /* eslint-disable import/no-extraneous-dependencies */
  2. const Promise = require('bluebird');
  3. const Chunk = require('webpack/lib/Chunk');
  4. const SVGCompiler = require('svg-baker');
  5. const Sprite = require('svg-baker/lib/sprite');
  6. const { NAMESPACE } = require('./config');
  7. const utils = require('./utils');
  8. class SVGSpritePlugin {
  9. constructor() {
  10. this.svgCompiler = new SVGCompiler();
  11. }
  12. /**
  13. * This need to find plugin from loader context
  14. */
  15. // eslint-disable-next-line class-methods-use-this
  16. get NAMESPACE() {
  17. return NAMESPACE;
  18. }
  19. apply(compiler) {
  20. const plugin = this;
  21. const { symbols } = this.svgCompiler;
  22. // Handle only main compilation
  23. compiler.plugin('this-compilation', (compilation) => {
  24. // Share svgCompiler with loader
  25. compilation.plugin('normal-module-loader', (loaderContext) => {
  26. loaderContext[NAMESPACE] = plugin;
  27. });
  28. // Replace placeholders with real URL to symbol (in modules processed by sprite-loader)
  29. compilation.plugin('after-optimize-chunks', function replacePlaceholdersInModules() {
  30. const map = utils.aggregate(symbols, this);
  31. const replacements = map.reduce((acc, item) => {
  32. acc[item.resource] = item.url;
  33. return acc;
  34. }, {});
  35. map.forEach(item => utils.replaceInModuleSource(item.module, replacements));
  36. });
  37. // Replace placeholders with real URL to symbol (in modules extracted by extract-text-webpack-plugin)
  38. compilation.plugin('optimize-extracted-chunks', function replacePlaceholdersInExtractedChunks(chunks) {
  39. const map = utils.aggregate(symbols, this);
  40. const replacements = map.reduce((acc, item) => {
  41. acc[item.resource] = item.useUrl;
  42. return acc;
  43. }, {});
  44. chunks.forEach((chunk) => {
  45. chunk.modules
  46. // dirty hack to identify modules extracted by extract-text-webpack-plugin
  47. // TODO refactor
  48. .filter(module => '_originalModule' in module)
  49. .forEach(module => utils.replaceInModuleSource(module, replacements));
  50. });
  51. });
  52. // Create sprite chunk
  53. compilation.plugin('additional-assets', function emitSpriteChunks(done) {
  54. const sprites = utils.groupSymbolsBySprites(utils.aggregate(symbols, this));
  55. const filenames = Object.keys(sprites);
  56. return Promise.map(filenames, (spriteFilename) => {
  57. const spriteSymbols = sprites[spriteFilename];
  58. return Sprite.create({ symbols: spriteSymbols, filename: spriteFilename })
  59. .then((sprite) => {
  60. const content = sprite.render();
  61. const chunk = new Chunk(spriteFilename);
  62. chunk.ids = [];
  63. chunk.files.push(spriteFilename);
  64. compilation.assets[spriteFilename] = {
  65. source() { return content; },
  66. size() { return content.length; }
  67. };
  68. compilation.chunks.push(chunk);
  69. });
  70. })
  71. .then(() => {
  72. done();
  73. return true;
  74. })
  75. .catch(e => done(e));
  76. });
  77. });
  78. }
  79. }
  80. module.exports = SVGSpritePlugin;