Merge pull request 'chore: make bundle fully self-contained, no external imports' (#270) from chore/no-external-bundle into main
This commit is contained in:
@@ -196,18 +196,13 @@ uncaged-workflow init workspace ${workspaceName}
|
|||||||
|
|
||||||
function bundleTs(): string {
|
function bundleTs(): string {
|
||||||
return [
|
return [
|
||||||
'import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";',
|
'import { mkdir, readdir, writeFile } from "node:fs/promises";',
|
||||||
'import { join } from "node:path";',
|
'import { join } from "node:path";',
|
||||||
"",
|
"",
|
||||||
'const rootDir = join(import.meta.dir, "..");',
|
'const rootDir = join(import.meta.dir, "..");',
|
||||||
'const workflowsDir = join(rootDir, "workflows");',
|
'const workflowsDir = join(rootDir, "workflows");',
|
||||||
'const distDir = join(rootDir, "dist");',
|
'const distDir = join(rootDir, "dist");',
|
||||||
"",
|
"",
|
||||||
"type JsonDeps = {",
|
|
||||||
" dependencies: Record<string, string> | null;",
|
|
||||||
" devDependencies: Record<string, string> | null;",
|
|
||||||
"};",
|
|
||||||
"",
|
|
||||||
"function isEntryFile(name: string): boolean {",
|
"function isEntryFile(name: string): boolean {",
|
||||||
' return name.endsWith("-entry.ts");',
|
' return name.endsWith("-entry.ts");',
|
||||||
"}",
|
"}",
|
||||||
@@ -216,36 +211,6 @@ function bundleTs(): string {
|
|||||||
' return name.slice(0, -".ts".length);',
|
' return name.slice(0, -".ts".length);',
|
||||||
"}",
|
"}",
|
||||||
"",
|
"",
|
||||||
"async function uncagedWorkflowExternals(): Promise<string[]> {",
|
|
||||||
" const names = new Set<string>();",
|
|
||||||
' const paths = [join(rootDir, "package.json"), join(workflowsDir, "package.json")];',
|
|
||||||
" for (const pkgPath of paths) {",
|
|
||||||
" let raw: string;",
|
|
||||||
" try {",
|
|
||||||
' raw = await readFile(pkgPath, "utf8");',
|
|
||||||
" } catch {",
|
|
||||||
" continue;",
|
|
||||||
" }",
|
|
||||||
" const parsed = JSON.parse(raw) as JsonDeps;",
|
|
||||||
" const blocks = [parsed.dependencies, parsed.devDependencies];",
|
|
||||||
" for (const block of blocks) {",
|
|
||||||
" if (block == null) {",
|
|
||||||
" continue;",
|
|
||||||
" }",
|
|
||||||
" for (const key of Object.keys(block)) {",
|
|
||||||
' if (key.startsWith("@uncaged/workflow")) {',
|
|
||||||
" names.add(key);",
|
|
||||||
" }",
|
|
||||||
" }",
|
|
||||||
" }",
|
|
||||||
" }",
|
|
||||||
" if (names.size === 0) {",
|
|
||||||
' names.add("@uncaged/workflow-runtime");',
|
|
||||||
' names.add("@uncaged/workflow-protocol");',
|
|
||||||
" }",
|
|
||||||
" return [...names];",
|
|
||||||
"}",
|
|
||||||
"",
|
|
||||||
"async function main(): Promise<void> {",
|
"async function main(): Promise<void> {",
|
||||||
" await mkdir(distDir, { recursive: true });",
|
" await mkdir(distDir, { recursive: true });",
|
||||||
" let files: string[];",
|
" let files: string[];",
|
||||||
@@ -261,7 +226,6 @@ function bundleTs(): string {
|
|||||||
' console.warn("bundle: no *-entry.ts files under workflows/");',
|
' console.warn("bundle: no *-entry.ts files under workflows/");',
|
||||||
" return;",
|
" return;",
|
||||||
" }",
|
" }",
|
||||||
" const external = await uncagedWorkflowExternals();",
|
|
||||||
" for (const file of entries) {",
|
" for (const file of entries) {",
|
||||||
" const stem = entryStem(file);",
|
" const stem = entryStem(file);",
|
||||||
" const entryPath = join(workflowsDir, file);",
|
" const entryPath = join(workflowsDir, file);",
|
||||||
@@ -272,7 +236,6 @@ function bundleTs(): string {
|
|||||||
' target: "node",',
|
' target: "node",',
|
||||||
" splitting: false,",
|
" splitting: false,",
|
||||||
' naming: { entry: "[name].esm.js" },',
|
' naming: { entry: "[name].esm.js" },',
|
||||||
" external,",
|
|
||||||
" });",
|
" });",
|
||||||
" if (!result.success) {",
|
" if (!result.success) {",
|
||||||
" for (const log of result.logs) {",
|
" for (const log of result.logs) {",
|
||||||
|
|||||||
@@ -329,9 +329,8 @@ const adapter = createCursorAgent({
|
|||||||
|
|
||||||
The bundle validator only allows these import specifiers:
|
The bundle validator only allows these import specifiers:
|
||||||
- Node built-ins (\`node:fs\`, \`node:path\`, etc.)
|
- Node built-ins (\`node:fs\`, \`node:path\`, etc.)
|
||||||
- \`@uncaged/workflow-*\` packages
|
|
||||||
|
|
||||||
Third-party packages (**including zod**) must be bundled into the \`.esm.js\` file, not left as external imports. When using \`bun build\`, only mark \`@uncaged/*\` as external.
|
All other dependencies — including \`@uncaged/workflow-*\` packages, zod, and any third-party code — must be bundled into the \`.esm.js\` file. Bundles are fully self-contained: same Node/Bun version = same behavior.
|
||||||
|
|
||||||
### No default exports
|
### No default exports
|
||||||
|
|
||||||
|
|||||||
@@ -37,9 +37,6 @@ function isAllowedImportSpecifier(spec: string): boolean {
|
|||||||
if (spec.startsWith(".") || spec.startsWith("/") || spec.startsWith("file:")) {
|
if (spec.startsWith(".") || spec.startsWith("/") || spec.startsWith("file:")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (spec.startsWith("@uncaged/workflow")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return isBuiltin(spec);
|
return isBuiltin(spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +291,7 @@ function validateImportDeclaration(node: ImportDeclaration): string | null {
|
|||||||
return "only static string import specifiers are allowed";
|
return "only static string import specifiers are allowed";
|
||||||
}
|
}
|
||||||
if (!isAllowedImportSpecifier(spec)) {
|
if (!isAllowedImportSpecifier(spec)) {
|
||||||
return `disallowed import specifier "${spec}" (only Node built-ins and @uncaged/workflow-* packages are allowed)`;
|
return `disallowed import specifier "${spec}" (only Node built-ins are allowed; all other dependencies must be bundled)`;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -309,7 +306,7 @@ function validateExportSource(
|
|||||||
return staticMessage;
|
return staticMessage;
|
||||||
}
|
}
|
||||||
if (!isAllowedImportSpecifier(spec)) {
|
if (!isAllowedImportSpecifier(spec)) {
|
||||||
return `${disallowedPrefix} "${spec}" (only Node built-ins and @uncaged/workflow-* packages are allowed)`;
|
return `${disallowedPrefix} "${spec}" (only Node built-ins are allowed; all other dependencies must be bundled)`;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user