14

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/.*'
        })
    ]
};
Axel
  • 13,939
  • 5
  • 50
  • 79

2 Answers2

4

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

Grzegorz T.
  • 3,903
  • 2
  • 11
  • 24
  • 1
    Thanks alot. My problem is that the katex.css file which includes the `@font-face` statements is inside a node module (katex). I don't reference any of these fonts in my own css files. I am looking for a way to replace the URLs on the fly when webpack runs. As I understand it, I'd have to change the `@font-face` statements in katex.css if I want to use your solution. – Axel Nov 09 '19 at 08:08
  • Yes you can't quite try another plugin [postcss-base64](https://github.com/jelmerdemaat/postcss-base64) I haven't used this one but from what I've read in the documentation you can choose the extension so it should work. Then you won't have to modify the files. I will test if I find a moment of time. – Grzegorz T. Nov 09 '19 at 09:43
  • Ok plugin which I suggested does not work as I wanted, but this one you will not have to change anything in the files, all fonts will automatically be changed to [postcss-font-base64](https://github.com/ckarlbe/postcss-font-base64) -> update [example](https://github.com/tomik23/webpack-babel-corejs/tree/postcss-inline-base64) – Grzegorz T. Nov 09 '19 at 10:01
0

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

George Wayne
  • 160
  • 1
  • 5