DataUriPlugin.js 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  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. class DataUriPlugin {
  32. /**
  33. * Apply the plugin
  34. * @param {Compiler} compiler the compiler instance
  35. * @returns {void}
  36. */
  37. apply(compiler) {
  38. compiler.hooks.compilation.tap(
  39. "DataUriPlugin",
  40. (compilation, { normalModuleFactory }) => {
  41. normalModuleFactory.hooks.resolveForScheme
  42. .for("data")
  43. .tap("DataUriPlugin", resourceData => {
  44. const match = URIRegEx.exec(resourceData.resource);
  45. if (match) {
  46. resourceData.data.mimetype = match[1] || "";
  47. resourceData.data.parameters = match[2] || "";
  48. resourceData.data.encoding = match[3] || false;
  49. resourceData.data.encodedContent = match[4] || "";
  50. }
  51. });
  52. NormalModule.getCompilationHooks(compilation)
  53. .readResourceForScheme.for("data")
  54. .tap("DataUriPlugin", resource => decodeDataURI(resource));
  55. }
  56. );
  57. }
  58. }
  59. module.exports = DataUriPlugin;