Skip to content

Commit 22ddfd8

Browse files
committed
Added lazy loading to jupyterlab-plotly and plotlywidget
Currently plotly.js is bundled with the main bundle which increases the size of bundle drastically and jupyterlab takes a lot of time to load. With this change, plotly.js will be loaded on demand. This uses dynamic imports to achieve this. Fixes plotly#1913
1 parent 141aa6d commit 22ddfd8

File tree

5 files changed

+253
-225
lines changed

5 files changed

+253
-225
lines changed

Diff for: packages/javascript/jupyterlab-plotly/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "jupyterlab-plotly",
3-
"version": "4.6.0",
3+
"version": "4.6.1",
44
"description": "The plotly JupyterLab extension",
55
"author": "The plotly.py team",
66
"license": "MIT",

Diff for: packages/javascript/jupyterlab-plotly/src/javascript-renderer-extension.ts

+22-16
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ import { Message } from '@lumino/messaging';
77

88
import { IRenderMime } from '@jupyterlab/rendermime-interfaces';
99

10-
import Plotly from 'plotly.js/dist/plotly.min';
11-
1210
import '../style/index.css';
1311

1412
/**
@@ -27,12 +25,12 @@ const CSS_ICON_CLASS = 'jp-MaterialIcon jp-PlotlyIcon';
2725
*/
2826
export const MIME_TYPE = 'application/vnd.plotly.v1+json';
2927

30-
interface IPlotlySpec {
31-
data: Plotly.Data;
32-
layout: Plotly.Layout;
33-
frames?: Plotly.Frame[];
28+
interface PlotlyHTMLElement extends HTMLElement {
29+
on(event: 'plotly_webglcontextlost', callback: () => void): void;
3430
}
3531

32+
type Frame = { [key: string]: any };
33+
3634
export class RenderedPlotly extends Widget implements IRenderMime.IRenderer {
3735
/**
3836
* Create a new widget for rendering Plotly.
@@ -48,8 +46,11 @@ export class RenderedPlotly extends Widget implements IRenderMime.IRenderer {
4846
this.node.appendChild(this._img_el);
4947

5048
// Install image hover callback
51-
this._img_el.addEventListener('mouseenter', event => {
52-
this.createGraph(this._model);
49+
import(/* webpackChunkName: 'plotly'*/ 'plotly.js/dist/plotly').then(Plotly => {
50+
51+
this._img_el.addEventListener('mouseenter', event => {
52+
this.createGraph(this._model, Plotly);
53+
})
5354
})
5455
}
5556

@@ -74,7 +75,9 @@ export class RenderedPlotly extends Widget implements IRenderMime.IRenderer {
7475
return Promise.resolve();
7576
} else {
7677
// Create a new graph
77-
return this.createGraph(model);
78+
return import(/* webpackChunkName: 'plotly'*/ 'plotly.js/dist/plotly').then(Plotly => {
79+
this.createGraph(model, Plotly);
80+
})
7881
}
7982
}
8083

@@ -122,10 +125,11 @@ export class RenderedPlotly extends Widget implements IRenderMime.IRenderer {
122125
}
123126
}
124127

125-
private createGraph(model: IRenderMime.IMimeModel) {
128+
private createGraph(model: IRenderMime.IMimeModel, Plotly: any) {
126129
const { data, layout, frames, config } = model.data[this._mimeType] as
127130
| any
128-
| IPlotlySpec;
131+
| { data: Plotly.Data; layout: Plotly.Layout; frames?: Frame[]; }
132+
| { data: Plotly.Data; layout: Plotly.Layout; frames?: Plotly.Frame[]; }
129133

130134
return Plotly.react(this.node, data, layout, config).then(plot => {
131135
this.showGraph();
@@ -153,7 +157,7 @@ export class RenderedPlotly extends Widget implements IRenderMime.IRenderer {
153157
}
154158

155159
// Handle webgl context lost events
156-
(<Plotly.PlotlyHTMLElement>(this.node)).on('plotly_webglcontextlost', () => {
160+
(<PlotlyHTMLElement>(this.node)).on('plotly_webglcontextlost', () => {
157161
const png_data = <string>model.data['image/png'];
158162
if(png_data !== undefined && png_data !== null) {
159163
// We have PNG data, use it
@@ -183,9 +187,11 @@ export class RenderedPlotly extends Widget implements IRenderMime.IRenderer {
183187
*/
184188
protected onUpdateRequest(msg: Message): void {
185189
if (this.isVisible && this.hasGraphElement()) {
186-
Plotly.redraw(this.node).then(() => {
187-
Plotly.Plots.resize(this.node);
188-
});
190+
import(/* webpackChunkName: 'plotly'*/ 'plotly.js/dist/plotly').then(Plotly => {
191+
Plotly.redraw(this.node).then(() => {
192+
Plotly.Plots.resize(this.node);
193+
});
194+
})
189195
}
190196
}
191197

@@ -226,4 +232,4 @@ const extensions: IRenderMime.IExtension | IRenderMime.IExtension[] = [
226232
}
227233
];
228234

229-
export default extensions;
235+
export default extensions;

Diff for: packages/javascript/jupyterlab-plotly/tsconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"noUnusedLocals": true,
99
"esModuleInterop": true,
1010
"preserveWatchOutput": true,
11-
"module": "commonjs",
11+
"module": "esnext",
1212
"moduleResolution": "node",
1313
"target": "es2015",
1414
"lib": ["dom", "es2015"],

Diff for: packages/javascript/plotlywidget/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "plotlywidget",
3-
"version": "4.6.0",
3+
"version": "4.6.1",
44
"description": "The plotly JupyterLab extension",
55
"author": "The plotly.py team",
66
"license": "MIT",
@@ -23,7 +23,7 @@
2323
],
2424
"scripts": {
2525
"build": "webpack",
26-
"clean": "rimraf dist/ && rimraf ../../python/plotly/plotlywidget/static'",
26+
"clean": "rimraf dist/ && rimraf ../../python/plotly/plotlywidget/static",
2727
"test": "echo \"Error: no test specified\" && exit 1"
2828
},
2929
"devDependencies": {

0 commit comments

Comments
 (0)