mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-30 05:02:58 +00:00
perf(server): minify plugin client bundles
Plugin client bundles are sent and evaluated as the esbuild text. On a mobile link that text is the catalog download. Minify whitespace and syntax after the Hermes interop getters are made eager. Identifier minify stays off so that replacement still matches, and server bundles stay readable. Co-authored-by: RoundRedDot <roundreddot@gmail.com>
This commit is contained in:
@@ -567,6 +567,42 @@ export default function contribute(client) {
|
||||
expect(clientBundle).toContain("__async");
|
||||
});
|
||||
|
||||
it("minifies the client bundle after Hermes interop getters are eager", async () => {
|
||||
const entries = await createSplitPlugin();
|
||||
await writeFile(
|
||||
entries.client,
|
||||
`import { useState } from "react";
|
||||
const label = "\\u2013";
|
||||
export default function contribute(client) {
|
||||
void useState;
|
||||
void label;
|
||||
client.addCommandCenterItem({ id: "open", title: "Open", icon: "Scan", context: "global", onSelect() {} });
|
||||
return () => undefined;
|
||||
}`,
|
||||
);
|
||||
await writeFile(
|
||||
entries.server,
|
||||
`import { z } from "zod";
|
||||
export default function contribute() {
|
||||
void z.object({});
|
||||
return () => undefined;
|
||||
}`,
|
||||
);
|
||||
|
||||
const { clientBundle, serverBundle } = await compilePlugin(entries);
|
||||
if (clientBundle === null || serverBundle === null) {
|
||||
throw new Error("compilePlugin returned no bundle");
|
||||
}
|
||||
|
||||
expect(clientBundle).not.toContain("get: () => from[key]");
|
||||
expect(clientBundle).not.toContain("get:()=>from[key]");
|
||||
expect(clientBundle).toContain("value:from[key]");
|
||||
expect(clientBundle.split("").every((char) => char.charCodeAt(0) <= 0x7f)).toBe(true);
|
||||
expect(serverBundle).toContain("value: from[key]");
|
||||
expect(serverBundle).not.toContain("value:from[key]");
|
||||
expect(clientBundle.split("\n").length).toBeLessThan(serverBundle.split("\n").length);
|
||||
});
|
||||
|
||||
it("rejects node imports from the client entry", async () => {
|
||||
const entries = await createSplitPlugin();
|
||||
await writeFile(
|
||||
|
||||
@@ -313,6 +313,22 @@ function makeHermesInteropEager(code: string): string {
|
||||
return code.replaceAll("get: () => from[key]", "value: from[key]");
|
||||
}
|
||||
|
||||
async function minifyClientBundle(code: string): Promise<string> {
|
||||
const { transform } = loadEsbuild();
|
||||
// Minify after the eager replace. Whitespace minify rewrites the getter this
|
||||
// replace matches, and identifier minify can delete the helper entirely.
|
||||
const result = await transform(code, {
|
||||
minifyWhitespace: true,
|
||||
minifySyntax: true,
|
||||
minifyIdentifiers: false,
|
||||
target: "es2020",
|
||||
supported: { "async-await": false },
|
||||
charset: "ascii",
|
||||
legalComments: "none",
|
||||
});
|
||||
return result.code;
|
||||
}
|
||||
|
||||
function runtimeSpecifierError(
|
||||
specifier: string,
|
||||
target: PluginBuildTarget | "shared",
|
||||
@@ -424,7 +440,9 @@ async function compileTarget(entryPath: string, target: PluginBuildTarget): Prom
|
||||
checkSharedDependencies(result.metafile.inputs, pluginDirectory);
|
||||
const output = result.outputFiles[0]?.text;
|
||||
if (!output) throw new Error(`Plugin ${target} compilation produced no output`);
|
||||
return wrapCommonJsBundle(makeHermesInteropEager(output));
|
||||
const eager = makeHermesInteropEager(output);
|
||||
const prepared = target === "client" ? await minifyClientBundle(eager) : eager;
|
||||
return wrapCommonJsBundle(prepared);
|
||||
}
|
||||
|
||||
export async function compilePlugin(entryPaths: {
|
||||
|
||||
Reference in New Issue
Block a user