Pdfmake: Strategies to reduce library code size by half and get rid of vfs_fonts.js

Created on 18 May 2018  ·  10Comments  ·  Source: bpampuch/pdfmake

Pdfmake is a great library but has the downside of big code size. To be fair, the size comes from its dependencies not for its own code

Here are the strategies i used to reduce the code by half and also get rid of vfs_fonts.js

  • In fontkit:

    • remove support for woff2 format (its brotli dependency has a big payload)

    • remove support for indic shaper

    • refactoring to avoid dependency on core-js

  • In pdfmake:

    • Do not bundle iconv-lite, which is used only by fonts that do not have cmap

  • In project:

    • Fetch fonts on demand and build the vfs object dynamically

The fontkit changes were published as fontkit-lite

The pdfmake changes were published as pdfmake-lite

Let me know if any of this changes can be integrated in the project. One possibility is to create two bundles: pdfmake.js with all features, and pdfmake-lite.js with smaller bundle and a few less features.

This is the code i'm using to load the fonts on demand:

function fetchFont (fontURL) {
  return new Promise((resolve, reject) => {
    const request = new XMLHttpRequest()
    request.open('GET', fontURL, true)
    request.responseType = 'arraybuffer'

    request.onload = function (e) {
      resolve(request.response)
    }

    request.onerror = reject

    request.send()
  })
}

class PdfFontLoader {
  constructor () {
    this.fontDefs = []
    this.vfs = {}
  }
  addFont (fontDef) {
    this.fontDefs.push(fontDef)
  }

  load () {
    return new Promise((resolve, reject) => {
      if (this.loaded) {
        resolve()
      } else {
        const fetches = this.fontDefs.map(fontDef => {
          return fetchFont(fontDef.URL).then((data) => {
            this.vfs[fontDef.name] = data
          })
        })
        Promise.all(fetches).then(() => {
          this.loaded = true
          resolve()
        }).catch(reject)
      }
    })
  }
}

export const fontLoader = new PdfFontLoader()

pdfMake.vfs = fontLoader.vfs
fontLoader.addFont({URL: 'Roboto-Regular.ttf', name: 'Roboto-Regular.ttf'})
fontLoader.addFont({URL: 'Roboto-Italic.ttf', name: 'Roboto-Italic.ttf'})
fontLoader.addFont({URL: 'Roboto-Medium.ttf', name: 'Roboto-Medium.ttf'})
fontLoader.addFont({URL: 'Roboto-MediumItalic.ttf', name: 'Roboto-MediumItalic.ttf'})

//later call fontLoader.load()

Most helpful comment

The font files are in the same server, deployed with the app bundle.

I wrote a library to load assets dynamically. https://github.com/blikblum/pdfmake-utils

And a full example at https://github.com/blikblum/pdfmake-playground

All 10 comments

Awesome stuff @blikblum ! Just started using pdfmake and had been looking to bring down the bundle size of my app, so this has been super helpful! pdfmake-lite is working well so far 👍

Regarding fonts, I had a question. I'm trying to see if I could get avoid using vfs_fonts.js by using fontkit-lite.

Where do the font files come from in your example?

fontLoader.addFont({URL: 'Roboto-Regular.ttf', name: 'Roboto-Regular.ttf'})
fontLoader.addFont({URL: 'Roboto-Italic.ttf', name: 'Roboto-Italic.ttf'})
fontLoader.addFont({URL: 'Roboto-Medium.ttf', name: 'Roboto-Medium.ttf'})
fontLoader.addFont({URL: 'Roboto-MediumItalic.ttf', name: 'Roboto-MediumItalic.ttf'})

Somewhere in _node_modules_? I looked in fontkit-lite but didn't seem them.

Thanks!

The font files are in the same server, deployed with the app bundle.

I wrote a library to load assets dynamically. https://github.com/blikblum/pdfmake-utils

And a full example at https://github.com/blikblum/pdfmake-playground

Thanks @blikblum !

I ended up pulling them down and bundling them with webpack from here
https://github.com/google/fonts#download-all-google-fonts

Thanks for all your help, it looks like with this I was able to get the pdfmake bundle size down from 2.53 MB to 1.18 MB (uncompressed) 🎉

@blikblum This simply cannot be realized because:

  • fontkit - package simply doesn't allow loading of only some formats/shapers
  • pdfmake - yes, this is possible
  • project - out of pdfmake scope
  • pdfkit - problem is same as fontkit

Now only iconv-lite can be removed on "lite" package, but it doesn't bring a big size reduction without others (fontkit/pdfkit).

@liborm85 All fine

I know the limitations of fontkit. That's i i'm maintaining my fork (without IndicShaper and Woff2Font); Hopefully we can make it more modular;

iconv-lite is 125k minified which alone is bigger than react: https://bundlephobia.com/[email protected]. Fonts that don't have cmap are rare these days

Regarding font loading, it could be added a recipe how to do it. Webpack users can have a great benefit since sometimes the font is already loaded by the browser to use in the webpage

BTW: in my pdfmake-lite package i use vanilla / unchanged pdfkit. The only thing that can be improved size wise in pdfkit is making the password support optional

Is it possible to use fonts in vfs_fonts.js in your CSS for general styling to avoid having to load them twice?

It is possible but i never got time to do a test.

We did it with async javascript. We were loading fonts when there was a
need to create a pdf.

On Mon, Jun 8, 2020 at 7:10 PM Luiz Américo notifications@github.com
wrote:

It is possible but i never got time to do a test.


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/bpampuch/pdfmake/issues/1374#issuecomment-640609547,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AF6MDNIXVNUYIVMJ4EC33L3RVTS3NANCNFSM4FASUU3A
.

Fetching fonts in project from url address solves version 0.1.66+. Usage is described documentation.

What about the typings for pdfmake-lite? I just installed it on my Angular App and seems to be a good way to reduce the bundle size (was 2.3 MB based on analyzer, now it is 1.62 MB)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jkd003 picture jkd003  ·  3Comments

ValeSauer picture ValeSauer  ·  3Comments

kumarandena picture kumarandena  ·  3Comments

SummerSonnet picture SummerSonnet  ·  3Comments

m-brudi picture m-brudi  ·  3Comments