DataUriPlugin.js 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const NormalModule = require("../NormalModule");
  7. /** @typedef {import("../Compiler")} Compiler */
  8. // data URL scheme: "data:text/javascript;charset=utf-8;base64,some-string"
  9. // http://www.ietf.org/rfc/rfc2397.txt
  10. const URIRegEx = /^data:([^;,]+)?((?:;[^;,]+)*?)(?:;(base64)?)?,(.*)$/i;
  11. /**
  12. * @param {string} uri data URI
  13. * @returns {Buffer | null} decoded data
  14. */
  15. const decodeDataURI = uri => {
  16. const match = URIRegEx.exec(uri);
  17. if (!match) return null;
  18. const isBase64 = match[3];
  19. const body = match[4];
  20. if (isBase64) {
  21. return Buffer.from(body, "base64");
  22. }
  23. // CSS allows to use `data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" style="stroke: rgb(223,224,225); stroke-width: 2px; fill: none; stroke-dasharray: 6px 3px" /></svg>`
  24. // so we return original body if we can't `decodeURIComponent`
  25. try {
  26. return Buffer.from(decodeURIComponent(body), "ascii");
  27. } catch (_) {
  28. return Buffer.from(body, "ascii");
  29. }
  30. };
  31. const PLUGIN_NAME = "DataUriPlugin";
  32. class DataUriPlugin {
  33. /**
  34. * Apply the plugin
  35. * @param {Compiler} compiler the compiler instance
  36. * @returns {void}
  37. */
  38. apply(compiler) {
  39. compiler.hooks.compilation.tap(
  40. PLUGIN_NAME,
  41. (compilation, { normalModuleFactory }) => {
  42. normalModuleFactory.hooks.resolveForScheme
  43. .for("data")
  44. .tap(PLUGIN_NAME, resourceData => {
  45. const match = URIRegEx.exec(resourceData.resource);
  46. if (match) {
  47. resourceData.data.mimetype = match[1] || "";
  48. resourceData.data.parameters = match[2] || "";
  49. resourceData.data.encoding = match[3] || false;
  50. resourceData.data.encodedContent = match[4] || "";
  51. }
  52. });
  53. NormalModule.getCompilationHooks(compilation)
  54. .readResourceForScheme.for("data")
  55. .tap(PLUGIN_NAME, resource => decodeDataURI(resource));
  56. }
  57. );
  58. }
  59. }
  60. module.exports = DataUriPlugin;