Skip to content

Commit

Permalink
Unbundled JavaScript builds
Browse files Browse the repository at this point in the history
Signed-off-by: Andrew Stein <[email protected]>
  • Loading branch information
texodus committed Jan 4, 2025
1 parent 54d8804 commit 19b4ffa
Show file tree
Hide file tree
Showing 27 changed files with 356 additions and 249 deletions.
9 changes: 7 additions & 2 deletions packages/perspective-esbuild-plugin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,13 @@ exports.PerspectiveEsbuildPlugin = function PerspectiveEsbuildPlugin(
});

function setup(build) {
wasm_plugin.setup(build);
worker_plugin.setup(build);
if (options.wasm !== false) {
wasm_plugin.setup(build);
}

if (options.worker !== false) {
worker_plugin.setup(build);
}
}

return {
Expand Down
11 changes: 7 additions & 4 deletions packages/perspective-esbuild-plugin/wasm.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,13 @@ exports.WasmPlugin = function WasmPlugin(inline, webpack_hack) {
args.namespace === "wasm-stub" ||
args.namespace === "wasm-inline"
) {
const entryPoint = path.join(
args.pluginData.resolveDir,
args.path
);
let entryPoint = args.path;
if (args.path.startsWith(".")) {
entryPoint = path.join(
args.pluginData.resolveDir,
entryPoint
);
}

return {
path: entryPoint,
Expand Down
11 changes: 11 additions & 0 deletions packages/perspective-jupyterlab/src/js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

import perspective from "@finos/perspective";
import perspective_viewer from "@finos/perspective-viewer";

import server_wasm from "@finos/perspective/dist/pkg/perspective-server.wasm";
import client_wasm from "@finos/perspective-viewer/dist/pkg/perspective-viewer.wasm";

await Promise.all([
perspective_viewer.init_client(client_wasm),
perspective.init_server(server_wasm),
]);

export * from "./model";
export * from "./version";
export * from "./view";
Expand Down
3 changes: 2 additions & 1 deletion packages/perspective-jupyterlab/src/js/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import {
import { ABCWidgetFactory, DocumentWidget } from "@jupyterlab/docregistry";
import { PerspectiveWidget } from "./psp_widget";

import perspective from "@finos/perspective/src/ts/perspective.ts";
import perspective from "@finos/perspective";

/**
* The name of the factories that creates widgets.
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/perspective-jupyterlab/src/js/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import { DOMWidgetView } from "@jupyter-widgets/base";
import { PerspectiveJupyterWidget } from "./widget";

import perspective from "@finos/perspective/src/ts/perspective.ts";
import perspective from "@finos/perspective";

function isEqual(a, b) {
if (a === b) return true;
Expand Down
46 changes: 39 additions & 7 deletions rust/perspective-js/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ const IS_DEBUG =
!!process.env.PSP_DEBUG || process.argv.indexOf("--debug") >= 0;

const BUILD = [
// WASM assets inlined into a single monolithic `.js` file. No special
// loades required, this version of Perspective should be the easiest
// to use but also the least performant at load time.
// {
// 'Import via `<script type="module">`': true,
// "Requires WASM bootstrap": false,
// "Load as binary": false,
// "Bundler friendly": true,
// },
{
entryPoints: ["src/ts/perspective.inline.ts"],
format: "esm",
Expand All @@ -32,20 +41,43 @@ const BUILD = [
],
outfile: "dist/esm/perspective.inline.js",
},
// WASM assets linked to relative path via `fetch()`. This efficiently
// loading build is great for `<script>` tags but will give many
// bundlers trouble.
// {
// 'Import via `<script type="module">`': true,
// "Requires WASM bootstrap": false,
// "Load as binary": true,
// "Bundler friendly": false,
// },
{
entryPoints: ["src/ts/perspective.ts"],
entryPoints: ["src/ts/perspective.cdn.ts"],
format: "esm",
target: "es2022",
plugins: [PerspectiveEsbuildPlugin()],
outdir: "dist/cdn",
plugins: [PerspectiveEsbuildPlugin({ wasm: false })],
outfile: "dist/cdn/perspective.js",
},
// No WASM assets inlined or linked.
// {
// 'Import via `<script type="module">`': true, // *******
// "Requires WASM bootstrap": true,
// "Load as binary": true,
// "Bundler friendly": true,
// },
{
entryPoints: ["src/ts/perspective.ts"],
entryPoints: ["src/ts/perspective.browser.ts"],
format: "esm",
target: "es2022",
external: ["*.wasm", "*.worker.js"],
outdir: "dist/esm",
plugins: [PerspectiveEsbuildPlugin({ wasm: false })],
outfile: "dist/esm/perspective.js",
},
// Node.js build
// {
// 'Import via `<script type="module">`': false,
// "Requires WASM bootstrap": false,
// "Load as binary": true,
// "Bundler friendly": false,
// },
{
entryPoints: ["src/ts/perspective.node.ts"],
format: "esm",
Expand Down Expand Up @@ -78,7 +110,7 @@ function build_rust() {
}

async function build_web_assets() {
await cpy(["../../cpp/perspective/dist/web/*"], "dist/pkg/web");
await cpy(["../../cpp/perspective/dist/web/*"], "dist/pkg");
await Promise.all(BUILD.map(build)).catch(() => process.exit(1));
}

Expand Down
3 changes: 1 addition & 2 deletions rust/perspective-js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"types": "./dist/esm/perspective.node.d.ts",
"default": "./dist/esm/perspective.node.js"
},
"types": "./dist/esm/perspective.d.ts",
"types": "./dist/esm/perspective.browser.d.ts",
"default": "./dist/esm/perspective.js"
},
"./node": {
Expand All @@ -34,7 +34,6 @@
"src/**/*",
"tsconfig.json"
],
"types": "./dist/esm/perspective.d.ts",
"scripts": {
"build": "node ./build.js",
"clean": "rimraf dist && rimraf build && rimraf src/ts/ts-rs",
Expand Down
4 changes: 2 additions & 2 deletions rust/perspective-js/src/ts/perspective-server.worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

import { PerspectiveSession, PerspectiveServer } from "./engine.ts";
import { compile_perspective } from "./emscripten_api.ts";
import { PerspectiveSession, PerspectiveServer } from "./wasm/engine.ts";
import { compile_perspective } from "./wasm/emscripten_api.ts";

let server: PerspectiveServer;
let session: PerspectiveSession;
Expand Down
121 changes: 121 additions & 0 deletions rust/perspective-js/src/ts/perspective.browser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
// ┃ This file is part of the Perspective library, distributed under the terms ┃
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

export type * from "../../dist/pkg/perspective-js.d.ts";
import type * as psp from "../../dist/pkg/perspective-js.d.ts";

import * as wasm_module from "../../dist/pkg/perspective-js.js";
import * as api from "./wasm/browser.ts";
import { load_wasm_stage_0 } from "./wasm/decompress.ts";

let GLOBAL_SERVER_WASM: Promise<ArrayBuffer>;

export function init_server(
wasm: Promise<ArrayBuffer | Response> | ArrayBuffer | Response,
disable_stage_0: boolean = false
) {
if (wasm instanceof Response) {
GLOBAL_SERVER_WASM = wasm.arrayBuffer();
} else if (wasm instanceof Promise) {
GLOBAL_SERVER_WASM = wasm.then((wasm: ArrayBuffer | Response) => {
if (wasm instanceof Response) {
return wasm.arrayBuffer();
} else {
return wasm;
}
});
} else {
GLOBAL_SERVER_WASM = Promise.resolve(wasm);
}

if (!disable_stage_0) {
GLOBAL_SERVER_WASM = GLOBAL_SERVER_WASM.then(load_wasm_stage_0).then(
(x) => x.buffer as ArrayBuffer
);
}
}

let GLOBAL_CLIENT_WASM: Promise<typeof psp>;

async function compilerize(
wasm: ArrayBuffer | Response,
disable_stage_0: boolean = false
) {
const wasm_buff = disable_stage_0 ? wasm : await load_wasm_stage_0(wasm);
await wasm_module.default(wasm_buff);
await wasm_module.init();
return wasm_module;
}

export type PerspectiveWasm =
| ArrayBuffer
| Response
| typeof psp
| Promise<ArrayBuffer | Response | Object>;

export function init_client(wasm: PerspectiveWasm, disable_stage_0 = false) {
if (wasm instanceof ArrayBuffer) {
GLOBAL_CLIENT_WASM = compilerize(wasm, disable_stage_0);
} else if (wasm instanceof Response) {
GLOBAL_CLIENT_WASM = wasm
.arrayBuffer()
.then((x) => compilerize(x, disable_stage_0));
} else if (wasm instanceof Promise) {
GLOBAL_CLIENT_WASM = wasm.then((wasm) => {
if (wasm instanceof ArrayBuffer) {
return compilerize(wasm, disable_stage_0);
} else if (wasm instanceof Response) {
return wasm
.arrayBuffer()
.then((x) => compilerize(x, disable_stage_0));
} else {
// } else if (wasm instanceof Object) {
return wasm as typeof psp;
}
});
} else if (wasm instanceof Object) {
GLOBAL_CLIENT_WASM = Promise.resolve(wasm as typeof psp);
}

console.log(GLOBAL_CLIENT_WASM);
}

function get_client() {
if (GLOBAL_CLIENT_WASM === undefined) {
const viewer_class: any = customElements.get("perspective-viewer");
if (viewer_class) {
GLOBAL_CLIENT_WASM = Promise.resolve(viewer_class.__wasm_module__);
} else {
throw new Error("Missing perspective-client.wasm");
}
}

return GLOBAL_CLIENT_WASM;
}

function get_server() {
if (GLOBAL_SERVER_WASM === undefined) {
throw new Error("Missing perspective-server.wasm");
}

return GLOBAL_SERVER_WASM.then((x) => x.slice(0));
}

export async function websocket(url: string | URL) {
return await api.websocket(get_client(), url);
}

export async function worker() {
return await api.worker(get_client(), get_server());
}

export default { websocket, worker, init_client, init_server };
Original file line number Diff line number Diff line change
Expand Up @@ -10,38 +10,10 @@
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

import * as api from "./browser.ts";
export type * from "../../dist/pkg/perspective-js.d.ts";
import perspective from "./perspective.browser.ts";
export * from "./perspective.browser.ts";

import type * as psp from "../../dist/pkg/perspective-js.d.ts";
const url = new URL("../pkg/perspective-server.wasm", import.meta.url);
perspective.init_server(fetch(url));

type WasmElement = {
__wasm_module__: Promise<typeof psp>;
};

export async function compile_perspective() {
let elem = customElements.get(
"perspective-viewer"
) as unknown as WasmElement;
if (!elem) {
console.warn("No `<perspective-viewer>` Custom Element found, waiting");
await customElements.whenDefined("perspective-viewer");
elem = customElements.get(
"perspective-viewer"
) as unknown as WasmElement;
}

return elem.__wasm_module__;
}

export async function websocket(url: string | URL) {
const wasm_module = compile_perspective();
return await api.websocket(wasm_module, url);
}

export async function worker() {
const wasm_module = compile_perspective();
return await api.worker(wasm_module);
}

export default { websocket, worker };
export default perspective;
50 changes: 8 additions & 42 deletions rust/perspective-js/src/ts/perspective.inline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,49 +10,15 @@
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

import * as api from "./browser.ts";
export type * from "../../dist/pkg/perspective-js.d.ts";
import perspective from "./perspective.browser.ts";
export * from "./perspective.browser.ts";

import * as wasm_module from "../../dist/pkg/perspective-js.js";
import wasm_binary from "../../dist/pkg/perspective-js.wasm";
import { load_wasm_stage_0 } from "@finos/perspective/src/ts/decompress.ts";
const server_url = new URL("../pkg/perspective-server.wasm", import.meta.url);
const client_url = new URL("../pkg/perspective-js.wasm", import.meta.url);

import type * as psp from "../../dist/pkg/perspective-js.d.ts";
await perspective.init_server(fetch(server_url));
await perspective.init_client(fetch(client_url));

type WasmElement = {
__wasm_module__: Promise<typeof psp>;
};
console.warn("Perspective wasn been initialized in inline mode");

export async function compile_perspective() {
let elem = customElements.get(
"perspective-viewer"
) as unknown as WasmElement;

if (!elem) {
console.warn(
"No `<perspective-viewer>` Custom Element found, using inline `Client`."
);

const module = await load_wasm_stage_0(
wasm_binary as unknown as ArrayBuffer
);

await wasm_module.default(module);
await wasm_module.init();
return wasm_module;
}

return elem.__wasm_module__;
}

export async function websocket(url: string | URL) {
const wasm_module = compile_perspective();
return await api.websocket(wasm_module, url);
}

export async function worker() {
const wasm_module = compile_perspective();
return await api.worker(wasm_module);
}

export default { websocket, worker };
export default perspective;
Loading

0 comments on commit 19b4ffa

Please sign in to comment.