Axel
Axel

Reputation: 14169

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/.*'
        })
    ]
};

Upvotes: 14

Views: 3897

Answers (2)

George Wayne
George Wayne

Reputation: 191

There is an npm package named base64-inline-loader and this seems to be a good choice for my problem.

In my vue project, you can refer to my configuration.

First, add package

yarn add -D base64-inline-loader

And then, deal with ”vue.config.js“

chainWebpack(config) {
  const fontsRule = config.module.rule('fonts')
  fontsRule.uses.clear()
  config.module
    .rule('fonts')
    .test(/\.(ttf|otf|eot|woff|woff2)$/)
    .use('base64-inline-loader')
    .loader('base64-inline-loader')
    .tap((options) => {
      // modify the options...
      return options
    })
    .end()
  }

Tested and verified enter image description here

Upvotes: 0

Grzegorz T.
Grzegorz T.

Reputation: 4133

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

Upvotes: 4

Related Questions