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 { getAttributeOrThrow } from "../lib/attribute";
import { throttle } from "../lib/utils"; 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 // See https://github.com/vega/vega-lite/blob/b61b13c2cbd4ecde0448544aff6cdaea721fd22a/src/compile/data/assemble.ts#L228-L231
const DEFAULT_DATASET_NAME = "source_0"; const DEFAULT_DATASET_NAME = "source_0";
@ -37,7 +45,10 @@ const VegaLite = {
spec.data = { values: [] }; 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) .then((result) => result.view)
.catch((error) => { .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.`; 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) => { this.state.viewPromise.then((view) => {
const currentData = view.data(dataset); const currentData = view.data(dataset);
const changeset = buildChangeset(currentData, data, window); buildChangeset(currentData, data, window).then((changeset) => {
// Schedule resize after the run finishes // Schedule resize after the run finishes
throttledResize(view); throttledResize(view);
view.change(dataset, changeset).run(); view.change(dataset, changeset).run();
});
}); });
} }
); );
@ -84,17 +96,19 @@ function getProps(hook) {
} }
function buildChangeset(currentData, newData, window) { function buildChangeset(currentData, newData, window) {
if (window === 0) { return importVega().then(({ vega }) => {
return vega.changeset().remove(currentData); if (window === 0) {
} else if (window) { return vega.changeset().remove(currentData);
const toInsert = newData.slice(-window); } else if (window) {
const freeSpace = Math.max(window - toInsert.length, 0); const toInsert = newData.slice(-window);
const toRemove = currentData.slice(0, -freeSpace); const freeSpace = Math.max(window - toInsert.length, 0);
const toRemove = currentData.slice(0, -freeSpace);
return vega.changeset().remove(toRemove).insert(toInsert); return vega.changeset().remove(toRemove).insert(toInsert);
} else { } else {
return vega.changeset().insert(newData); return vega.changeset().insert(newData);
} }
});
} }
export default VegaLite; 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: { optimization: {
minimizer: ["...", new CssMinimizerPlugin()], 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: { resolve: {
fallback: { fallback: {