Bokeh + webpack: how to reduce bundle size (currently 3 MB)

Hi! I’m trying to use Bokehjs in a web app which uses webpack as a bundler, it actually works but I get quite large resulting js bundle of size 3MB. I’m not very proficient at writing webpack configs, but I wonder if it is actually a good/supported way to include bokeh in your app at all? I searched documentation and examples but looks like this is not very popular way to use bokeh (at least).

I’m importing bokeh like this:

import * as Bokeh from '@bokeh/bokehjs'

const plt = Bokeh.Plotting
const np = Bokeh.LinAlg

const n = 100;
const x = np.linspace(0, 20, n);
const y = => Math.sin(x));

const p = plt.figure({ height: 300 });

p.line(x, y);, "#root");

Minimal app + webpack configs are here:

Output of webpack-bundle-analyzer:

That report shows that you are including all the optional modules for tables, widgets, and webgl support. Are you actually using those features? If so, then there’s not much to do on the Bokeh side of things.

cc @mateusz

That’s the issue, as you can see from my code I’m not using any of these features (at least explicitly). Even if I replace

import * as Bokeh from '@bokeh/bokehjs'


import { Plotting, LinAlg } from "@bokeh/bokehjs";

the size does’t reduce at all. Is there a way to exclude unused modules?

Ideally, I would like to reach the size of bokeh-2.4.2.min.js from CDN which is 800Kb (250Kb gzipped)

That should be possible, but @mateusz is who would know the details. It might be easier to catch his attention in a GitHub discussion.

Seems like I figured it out myself. Not sure if this is the best way, but that is what I ended up with:

import { figure, show } from "@bokeh/bokehjs/build/js/lib/api/plotting"
import { linspace } from "@bokeh/bokehjs/build/js/lib/api/linalg"

const n = 100;
const x = linspace(0, 20, n);
const y = => Math.sin(x));

const p = figure({ height: 300 });

p.line(x, y);

show(p, "#root");

So, now main.bundle.js in only 673 KB, which is even less than 800 KB of bokeh-2.4.2.min.js. Other modules are extracted as separate bundles, which could be loaded on demand. They have not very readable names, but it is easy to guess what is inside from the picture:

In the simplest case only one js bundle is loaded:

But if I’m switching output backend to webgl

const p = figure({ height: 300, output_backend: 'webgl' });

then you can see that another module is loaded on demand from main.bundle.js

1 Like