Dynamically import Vega-Lite JS when needed (#673)

This commit is contained in:
Jonatan Kłosko 2021-11-03 15:58:46 +01:00 committed by GitHub
parent 959e799d6e
commit e38d075fc2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 45 additions and 17 deletions

View file

@ -1,8 +1,16 @@
import * as vega from "vega";
import vegaEmbed from "vega-embed";
import { getAttributeOrThrow } from "../lib/attribute";
import { throttle } from "../lib/utils";
/**
* Dynamically imports the vega-related modules.
*/
function importVega() {
return import(
/* webpackChunkName: "vega" */
"./vega"
);
}
// See https://github.com/vega/vega-lite/blob/b61b13c2cbd4ecde0448544aff6cdaea721fd22a/src/compile/data/assemble.ts#L228-L231
const DEFAULT_DATASET_NAME = "source_0";
@ -37,7 +45,10 @@ const VegaLite = {
spec.data = { values: [] };
}
this.state.viewPromise = vegaEmbed(this.state.container, spec, {})
this.state.viewPromise = importVega()
.then(({ vegaEmbed }) => {
return vegaEmbed(this.state.container, spec, {});
})
.then((result) => result.view)
.catch((error) => {
const message = `Failed to render the given Vega-Lite specification, got the following error:\n\n ${error.message}\n\nMake sure to check for typos.`;
@ -57,10 +68,11 @@ const VegaLite = {
this.state.viewPromise.then((view) => {
const currentData = view.data(dataset);
const changeset = buildChangeset(currentData, data, window);
// Schedule resize after the run finishes
throttledResize(view);
view.change(dataset, changeset).run();
buildChangeset(currentData, data, window).then((changeset) => {
// Schedule resize after the run finishes
throttledResize(view);
view.change(dataset, changeset).run();
});
});
}
);
@ -84,17 +96,19 @@ function getProps(hook) {
}
function buildChangeset(currentData, newData, window) {
if (window === 0) {
return vega.changeset().remove(currentData);
} else if (window) {
const toInsert = newData.slice(-window);
const freeSpace = Math.max(window - toInsert.length, 0);
const toRemove = currentData.slice(0, -freeSpace);
return importVega().then(({ vega }) => {
if (window === 0) {
return vega.changeset().remove(currentData);
} else if (window) {
const toInsert = newData.slice(-window);
const freeSpace = Math.max(window - toInsert.length, 0);
const toRemove = currentData.slice(0, -freeSpace);
return vega.changeset().remove(toRemove).insert(toInsert);
} else {
return vega.changeset().insert(newData);
}
return vega.changeset().remove(toRemove).insert(toInsert);
} else {
return vega.changeset().insert(newData);
}
});
}
export default VegaLite;

View file

@ -0,0 +1,4 @@
import * as vega from "vega";
import vegaEmbed from "vega-embed";
export { vega, vegaEmbed };

View file

@ -56,6 +56,16 @@ module.exports = (env, options) => {
],
optimization: {
minimizer: ["...", new CssMinimizerPlugin()],
splitChunks: {
cacheGroups: {
// Chunk splitting is by default enabled for all async chunks,
// so for the dynamically loaded js/vega_lite/vega.js Webpack
// would produce one almost empty chunk and then a vendor chunk
// with "vega" and "vega-embed". We want to dynamically load all
// of it at once, so we disable the default vendors chunk
defaultVendors: false
}
}
},
resolve: {
fallback: {