3

I need to import into my project some CSS files with Webpack 5 and I need to inline all these resources (it's a requirement sadly). Inside the CSS there are some fonts and images with relative URI, like this:

@font-face { font-family: "MyFont"; src: url(./fonts/Roboto-Regular.ttf) format("truetype"); font-weight: normal;}
@font-face { font-family: "MyFont"; src: url(./fonts/Roboto-Bold.ttf) format("truetype"); font-weight: bold;}
@font-face { font-family: "MyFont"; src: url(./fonts/Roboto-Italic.ttf) format("truetype"); font-weight: normal; font-style: italic;}
@font-face { font-family: "MyFont"; src: url(./fonts/Roboto-BoldItalic.ttf) format("truetype"); font-weight: bold; font-style: italic;}
@font-face { font-family: 'Material Icons'; font-style: normal; font-weight: 400; src: url(./fonts/material-icons.woff2) format('woff2'); }
@font-face { font-family: 'Material Icons Outlined'; font-style: normal; font-weight: 400; src: url(./fonts/material-icons-outlined.woff2) format('woff2'); }
    

 * { font-family: "MyFont", "Roboto-Light", "Noto Sans CJK SC", "DejaVu Sans"; }

.UICheckbox         { width:80px; height:89px; background-image:url("img/checkboxOFF.png"); background-repeat:no-repeat; }
.UICheckbox.checked { background-image:url("img/checkboxON.png"); }

Since I need to import as base64 the CSS files I cannot actually process automatically the resources found inside of them (contrary to how it is done with PostCSS or similiars). My current webpack configuration is the following but it just ignores the url() statements:

      {
        test: /\.(png|jpg|gif)$/i,
        type: "asset/inline",
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/i,
        type: "asset/inline",
      },
      {
        test: /\.css$/i,
        type: "asset/inline",
      },

Is there a better way to handle this?

Barnercart
  • 1,523
  • 1
  • 11
  • 23
  • Does this answer your question? [How to inline fonts in CSS with webpack?](https://stackoverflow.com/questions/58715958/how-to-inline-fonts-in-css-with-webpack) – Heretic Monkey Jul 14 '22 at 13:11
  • 1
    Not really, I've tried a bit the configuration stated in the answer already and it doesn't seem updated/compatible with Webpack 5. – Barnercart Jul 14 '22 at 13:40
  • Also, I need to inline also the CSS files, so I think I need a solution that before inlining the CSS data tells webpack "Hey, you have some `url()` dependencies to inline too". Something like that. – Barnercart Jul 14 '22 at 14:50

1 Answers1

0

I found a solution that is not really generic or solid but does the job, at least in my case scenario.

The imports are relatives to a fixed source path so the idea is to read the resources found inside the url() rules and process it as DataURI in base64 encoding.

I found quite useful the use of datauri which provides a way to include data in-line as if they were external resources and manages the mimetypes automatically.

npm install datauri --save

Then I had to modify the generator handler inside webpack.config.js to process the resources manually exploiting the datauri package.

const path = require("path");
const Datauri = require("datauri/sync");

const EXTERNAL_ROOT_PATH = "./src/external/dev/";

module.exports = {
  ...

  module: {
    rules: [
       {
        test: /\.css$/i,
        type: "asset/inline",
        generator: {
          dataUrl: (content) => {
            content = content.toString();

            // Get the resource paths inside the CSS url() rules
            let asset_urls = [];
            let match,
              regex = /url\((.*?)\)/gi;
            while ((match = regex.exec(content))) {
              asset_urls.push(match[1]);
            }
            // console.log(asset_urls);

            // Convert the resource to a DataURI and replace it inside url()
            asset_urls.forEach((file_path) => {
              // Sanitize the file path first
              sanitized_file_path = file_path.replace(/[\"\']/g, "").replace(/^(?:\.\.\/)+/, "");

              const data_uri = Datauri(path.join(EXTERNAL_ROOT_PATH, sanitized_file_path));
              // console.log(data_uri.content); //=> "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
              // console.log(data_uri.mimetype); //=> "image/png"
              // console.log(data_uri.base64); //=> "iVBORw0KGgoAAAANSUhEUgAA..."
              // console.log(data_uri.buffer); //=> file buffer

              content = content.replace(file_path, data_uri.content);
            });

            return "data:text/css;base64," + Buffer.from(content).toString("base64");
          },
        },
      },
    ],
  },
};
Barnercart
  • 1,523
  • 1
  • 11
  • 23