fix(build): externalize qrcode terminal

This commit is contained in:
Vincent Koc
2026-05-02 09:53:12 -07:00
parent a45bcc429a
commit cb88d751b8
2 changed files with 54 additions and 3 deletions

View File

@@ -26,10 +26,18 @@ type TsdownOnLog = (
) => void;
type TsdownInputOptions = (
options: { onLog?: TsdownOnLog },
options: { external?: TsdownExternalOption; onLog?: TsdownOnLog },
format?: unknown,
context?: unknown,
) => { onLog?: TsdownOnLog } | undefined;
) => { external?: TsdownExternalOption; onLog?: TsdownOnLog } | undefined;
type TsdownExternalOption = string | RegExp | Array<string | RegExp> | TsdownExternalFunction;
type TsdownExternalFunction = (
id: string,
parentId: string | undefined,
isResolved: boolean,
) => boolean | null | undefined;
function asConfigArray(config: unknown): TsdownConfigEntry[] {
return Array.isArray(config) ? (config as TsdownConfigEntry[]) : [config as TsdownConfigEntry];
@@ -135,15 +143,22 @@ describe("tsdown config", () => {
it("externalizes known heavy native dependencies", () => {
const unifiedGraph = unifiedDistGraph();
const neverBundle = unifiedGraph?.deps?.neverBundle;
const external = unifiedGraph?.inputOptions?.({})?.external;
if (typeof neverBundle === "function") {
expect(neverBundle("@lancedb/lancedb")).toBe(true);
expect(neverBundle("@matrix-org/matrix-sdk-crypto-nodejs")).toBe(true);
expect(neverBundle("matrix-js-sdk/lib/client.js")).toBe(true);
expect(neverBundle("qrcode-terminal/lib/main.js")).toBe(true);
expect(neverBundle("not-a-runtime-dependency")).toBe(false);
} else {
expect(neverBundle).toEqual(expect.arrayContaining(["@lancedb/lancedb", "matrix-js-sdk"]));
expect(neverBundle).toEqual(
expect.arrayContaining(["@lancedb/lancedb", "matrix-js-sdk", "qrcode-terminal"]),
);
}
expect(typeof external).toBe("function");
const externalize = external as TsdownExternalFunction;
expect(externalize("qrcode-terminal/lib/main.js", undefined, false)).toBe(true);
});
it("suppresses unresolved imports from extension source", () => {

View File

@@ -23,6 +23,11 @@ type InputOptionsReturn = InputOptionsFactory extends (
? Return
: never;
type OnLogFunction = InputOptionsArg extends { onLog?: infer OnLog } ? NonNullable<OnLog> : never;
type ExternalOptionFunction = (
id: string,
parentId: string | undefined,
isResolved: boolean,
) => boolean | null | undefined;
const env = {
NODE_ENV: "production",
@@ -38,12 +43,37 @@ function normalizedLogHaystack(log: { message?: string; id?: string; importer?:
return [log.message, log.id, log.importer].filter(Boolean).join("\n").replaceAll("\\", "/");
}
function matchesExternalOption(
option: unknown,
id: string,
parentId: string | undefined,
isResolved: boolean,
): boolean {
if (!option) {
return false;
}
if (typeof option === "function") {
return (option as ExternalOptionFunction)(id, parentId, isResolved) === true;
}
if (typeof option === "string") {
return option === id;
}
if (option instanceof RegExp) {
return option.test(id);
}
if (Array.isArray(option)) {
return option.some((entry) => matchesExternalOption(entry, id, parentId, isResolved));
}
return false;
}
function buildInputOptions(options: InputOptionsArg): InputOptionsReturn {
if (process.env.OPENCLAW_BUILD_VERBOSE === "1") {
return undefined;
}
const previousOnLog = typeof options.onLog === "function" ? options.onLog : undefined;
const previousExternal = (options as { external?: unknown }).external;
function isSuppressedLog(log: {
code?: string;
@@ -66,6 +96,12 @@ function buildInputOptions(options: InputOptionsArg): InputOptionsReturn {
return {
...options,
external(id: string, parentId: string | undefined, isResolved: boolean) {
return (
shouldNeverBundleDependency(id) ||
matchesExternalOption(previousExternal, id, parentId, isResolved)
);
},
onLog(...args: Parameters<OnLogFunction>) {
const [level, log, defaultHandler] = args;
if (isSuppressedLog(log)) {