Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to inline fonts in CSS with webpack?

Problem background: I am using katex to render some math on a page. I then want to create a PDF version of part of that page, so I create a HTML document that containing the part to be exported that inlines all CSS and pass it to the renderer. The renderer cannot access the node resources, that's why everything is inlined. It works perfectly, except for the fonts.

I tried both url-loader and bas64-inline-loader, but the generated fonts are not inlined. I inspected the generated CSS in the debugger, and the old URLs are still in, no data-URLs for the fonts.

This is my current webpack.config.js:

const path = require('path');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    mode: 'development',
    entry: {
        "editor": './src/editor.js',
        "editor.worker": 'monaco-editor/esm/vs/editor/editor.worker.js',
        "json.worker": 'monaco-editor/esm/vs/language/json/json.worker',
        "css.worker": 'monaco-editor/esm/vs/language/css/css.worker',
        "html.worker": 'monaco-editor/esm/vs/language/html/html.worker',
        "ts.worker": 'monaco-editor/esm/vs/language/typescript/ts.worker',
    },
    output: {
        globalObject: 'self',
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.(woff|woff2|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
                use: ['url-loader']
            },
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            }
        ]
    },
    plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            filename: 'editor_text.html',
            template: 'src/editor_text.html'
        }),
        new HtmlWebpackPlugin({
            filename: 'editor_markdown.html',
            template: 'src/editor_markdown.html',
            inlineSource: '/katex/.*'
        })
    ]
};
like image 465
Axel Avatar asked Nov 05 '19 16:11

Axel


1 Answers

The best way is to use postcss-cli and postcss-inline-base64

webpack:

{
  test: /\.(css|sass|scss)$/,
  use: [
    MiniCssExtractPlugin.loader,
    {
      loader: 'css-loader',
      options: {
        importLoaders: 2,
        sourceMap: true
      },
    },
    {
      loader: 'postcss-loader', // important
      options: {
        sourceMap: true,
        config: {
          path: './config/',
        },
      },
    },
    {
      loader: 'sass-loader',
      options: {
        sourceMap: true,
      },
    },
  ],
}, {
  test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
  use: [{
    loader: 'file-loader',
  }]
},

Create config folder width postcss.config.js

module.exports = {
  plugins: {
    'postcss-inline-base64': {
      baseDir: './sources/'
    },
  },
};

baseDir is the path to the fonts. In the scss file I add a font in this way:

@font-face {
  font-family: 'Lato-Light';
  src: url('b64---../fonts/Lato-Light.ttf---') format('truetype');
  font-weight: normal;
  font-style: normal;
}

As a result of the work we have a nicely converted font to base64 @font-face{font-family:Lato-Light;src:url("data:font/ttf;charset=utf-8;base64,...

UPDATE: I prepared a small example postcss-inline-base64

like image 186
Grzegorz T. Avatar answered Oct 17 '22 05:10

Grzegorz T.