JavaScript - Importing with or without a bundler
Perspective requires the browser to have access to Perspective’s .wasm
binaries in addition to the bundled .js files, and as a result the build
process requires a few extra steps. Perspective’s NPM releases come with
multiple prebuilt configurations.
ESM builds with a bundler
The recommended builds for production use are packaged as ES Modules and require
a bootstrapping step in order to acquire the .wasm binaries and initialize
Perspective’s JavaScript with them. Because they have no hard-coded dependencies
on the .wasm paths, they are ideal for use with JavaScript bundlers such as
ESBuild, Rollup, Vite or Webpack.
ESM builds must be bootstrapped with their .wasm binaries to initialize. The
wasm binaries can be found in their respective dist/wasm directories.
import perspective_viewer from "@perspective-dev/viewer";
import perspective from "@perspective-dev/client";
// TODO These paths must be provided by the bundler!
const SERVER_WASM = ... // "@perspective-dev/server/dist/wasm/perspective-server.wasm"
const CLIENT_WASM = ... // "@perspective-dev/viewer/dist/wasm/perspective-viewer.wasm"
await Promise.all([
perspective.init_server(SERVER_WASM),
perspective_viewer.init_client(CLIENT_WASM),
]);
// Now Perspective API will work!
const worker = await perspective.worker();
const viewer = document.createElement("perspective-viewer");
The exact syntax will vary slightly depending on the bundler.
Vite
import SERVER_WASM from "@perspective-dev/server/dist/wasm/perspective-server.wasm?url";
import CLIENT_WASM from "@perspective-dev/viewer/dist/wasm/perspective-viewer.wasm?url";
await Promise.all([
perspective.init_server(fetch(SERVER_WASM)),
perspective_viewer.init_client(fetch(CLIENT_WASM)),
]);
You’ll also need to target esnext in your vite.config.js in order to run the
build step:
import { defineConfig } from "vite";
export default defineConfig({
build: {
target: "esnext",
},
});
ESBuild
import SERVER_WASM from "@perspective-dev/server/dist/wasm/perspective-server.wasm";
import CLIENT_WASM from "@perspective-dev/viewer/dist/wasm/perspective-viewer.wasm";
await Promise.all([
perspective.init_server(fetch(SERVER_WASM)),
perspective_viewer.init_client(fetch(CLIENT_WASM)),
]);
ESBuild config JSON to encode this asset as a file:
{
// ...
"loader": {
// ...
".wasm": "file"
}
}
Webpack
import SERVER_WASM from "@perspective-dev/server/dist/wasm/perspective-server.wasm";
import CLIENT_WASM from "@perspective-dev/viewer/dist/wasm/perspective-viewer.wasm";
await Promise.all([
perspective.init_server(SERVER_WASM),
perspective_viewer.init_client(CLIENT_WASM),
]);
Webpack config:
{
// ...
module: {
// ...
rules: [
// ...
{
test: /\.wasm$/,
type: "asset/resource"
},
]
},
experiments: {
// ...
asyncWebAssembly: false,
syncWebAssembly: false,
},
}
Inline builds with a bundler
Inline builds are deprecated and will be removed in a future release.
Perspective’s Inline Builds work by inlining WebAssembly binary content as a base64-encoded string. While inline builds work with most bundlers and do not require bootstrapping, there is an inherent file-size and boot-performance penalty. Prefer your bundler’s inlining features and Perspective ESM builds where possible.
import "@perspective-dev/viewer/dist/esm/perspective-viewer.inline.js";
import psp from "@perspective-dev/client/dist/esm/perspective.inline.js";
CDN builds
Perspective’s CDN builds are good for non-bundled scenarios, such as importing
directly from a <script> tag. CDN builds do not require bootstrapping the
WebAssembly binaries, but they also generally do not work with bundlers.
CDN builds are in ES Module format, thus to include them via a CDN they must be
imported from a <script type="module">:
<script type="module">
import "https://cdn.jsdelivr.net/npm/@perspective-dev/viewer/dist/cdn/perspective-viewer.js";
import "https://cdn.jsdelivr.net/npm/@perspective-dev/viewer-datagrid/dist/cdn/perspective-viewer-datagrid.js";
import "https://cdn.jsdelivr.net/npm/@perspective-dev/viewer-d3fc/dist/cdn/perspective-viewer-d3fc.js";
import perspective from "https://cdn.jsdelivr.net/npm/@perspective-dev/client/dist/cdn/perspective.js";
// .. Do stuff here ..
</script>
Node.js builds
The Node.js runtime for the @perspective-dev/client module runs in-process by
default and does not implement a child_process interface. Hence, there is no
worker() method, and the module object itself directly exports the full
perspective API.
const perspective = require("@perspective-dev/client");
In Node.js, perspective does not run in a WebWorker (as this API does not exist
in Node.js), so no need to call the .worker() factory function - the
perspective library exports the functions directly and run synchronously in
the main process.