Home > Enterprise >  Inlining fonts and images inside CSS files with Webpack5?
Inlining fonts and images inside CSS files with Webpack5?

Time:07-20

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?

CodePudding user response:

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");
          },
        },
      },
    ],
  },
};
  • Related