mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-08-19 09:55:15 +02:00
Rationale that explains a decision rather than the code below it belongs in the sandbox README or the PR, not in a header paragraph on every file.
97 lines
3.3 KiB
JavaScript
97 lines
3.3 KiB
JavaScript
/**
|
|
* A stand-in for `yaakcli build --target sandbox`, which does not exist yet.
|
|
* What the CLI would need instead is at the bottom of this file.
|
|
*/
|
|
|
|
import { build } from "esbuild";
|
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
import { dirname, join } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const root = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
|
|
/** Three, not the corpus: one template function, one importer, one auth method. */
|
|
const PLUGINS = ["template-function-timestamp", "importer-curl", "auth-bearer"];
|
|
|
|
const noNodeBuiltins = {
|
|
name: "no-node-builtins",
|
|
setup(build) {
|
|
build.onResolve({ filter: /^(node:|fs$|path$|crypto$|buffer$|process$|os$|util$|stream$)/ }, (args) => ({
|
|
errors: [
|
|
{
|
|
text:
|
|
`\`${args.path}\` is not available in the sandbox runtime. ` +
|
|
`Replace it with a pure-JavaScript equivalent.`,
|
|
},
|
|
],
|
|
}));
|
|
},
|
|
};
|
|
|
|
export async function bundlePlugin(name, { dir = join(root, "plugins", name) } = {}) {
|
|
const result = await build({
|
|
entryPoints: [join(dir, "src", "index.ts")],
|
|
bundle: true,
|
|
write: false,
|
|
format: "cjs",
|
|
platform: "browser",
|
|
target: "es2022",
|
|
minify: false,
|
|
legalComments: "none",
|
|
plugins: [noNodeBuiltins],
|
|
});
|
|
return result.outputFiles[0].text;
|
|
}
|
|
|
|
async function main() {
|
|
const bundles = [];
|
|
for (const name of PLUGINS) {
|
|
const source = await bundlePlugin(name);
|
|
bundles.push({ name, source });
|
|
console.log(`${name}: ${(source.length / 1024).toFixed(1)} KB`);
|
|
}
|
|
|
|
const outFile = join(root, "packages", "platform", "src", "web", "sandboxPlugins.generated.ts");
|
|
mkdirSync(dirname(outFile), { recursive: true });
|
|
writeFileSync(
|
|
outFile,
|
|
[
|
|
"// Generated by scripts/bundle-sandbox-plugins.mjs. Do not edit.",
|
|
"//",
|
|
"// The plugins the browser tier loads into its sandbox, bundled for that",
|
|
"// target and inlined as source text.",
|
|
"",
|
|
"export interface SandboxPluginBundle {",
|
|
" name: string;",
|
|
" source: string;",
|
|
"}",
|
|
"",
|
|
"export const SANDBOX_PLUGINS: SandboxPluginBundle[] = [",
|
|
...bundles.map((b) => ` { name: ${JSON.stringify(b.name)}, source: ${JSON.stringify(b.source)} },`),
|
|
"];",
|
|
"",
|
|
].join("\n"),
|
|
);
|
|
console.log(`Wrote ${outFile}`);
|
|
}
|
|
|
|
if (import.meta.url === `file://${process.argv[1]}`) await main();
|
|
|
|
/*
|
|
* What `yaakcli build --target sandbox` would need, beyond this:
|
|
*
|
|
* 1. `Platform::Browser` in the rolldown options (crates-cli/yaak-cli/src/
|
|
* commands/plugin.rs `bundler_options`), plus a resolver that fails on a
|
|
* Node built-in instead of shimming it — a silent shim turns a missing
|
|
* capability into a runtime error inside someone else's plugin.
|
|
* 2. A `runtime` field in the plugin manifest, so a plugin declares which
|
|
* target it is for and the registry can refuse to install a `node` plugin
|
|
* on a host that has no Node.
|
|
* 3. Both targets emitted for the same source where they both work, since a
|
|
* desktop with a sandbox and a desktop with Node are the same install.
|
|
* 4. Distribution as files, not as inlined strings. Inlining is what this
|
|
* script does because three small bundles cost less than an asset pipeline;
|
|
* the corpus does not, and a plugin the user installs at runtime cannot be
|
|
* inlined at build time at all.
|
|
*/
|