DataUriPlugin.js 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  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. const decodeDataURI = uri => {
  12. const match = URIRegEx.exec(uri);
  13. if (!match) return null;
  14. const isBase64 = match[3];
  15. const body = match[4];
  16. if (isBase64) {
  17. return Buffer.from(body, "base64");
  18. }
  19. // 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>`
  20. // so we return original body if we can't `decodeURIComponent`
  21. try {
  22. return Buffer.from(decodeURIComponent(body), "ascii");
  23. } catch (_) {
  24. return Buffer.from(body, "ascii");
  25. }
  26. };
  27. class DataUriPlugin {
  28. /**
  29. * Apply the plugin
  30. * @param {Compiler} compiler the compiler instance
  31. * @returns {void}
  32. */
  33. apply(compiler) {
  34. compiler.hooks.compilation.tap(
  35. "DataUriPlugin",
  36. (compilation, { normalModuleFactory }) => {
  37. normalModuleFactory.hooks.resolveForScheme
  38. .for("data")
  39. .tap("DataUriPlugin", resourceData => {
  40. const match = URIRegEx.exec(resourceData.resource);
  41. if (match) {
  42. resourceData.data.mimetype = match[1] || "";
  43. resourceData.data.parameters = match[2] || "";
  44. resourceData.data.encoding = match[3] || false;
  45. resourceData.data.encodedContent = match[4] || "";
  46. }
  47. });
  48. NormalModule.getCompilationHooks(compilation)
  49. .readResourceForScheme.for("data")
  50. .tap("DataUriPlugin", resource => decodeDataURI(resource));
  51. }
  52. );
  53. }
  54. }
  55. module.exports = DataUriPlugin;