Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changeset/tame-lamps-sin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"@workflow/example-nitro-v3": patch
"@workflow/nitro": patch
---

Support custom `workflows/` dirs:

* Project root dir
* Project source dir (if specified, which is usually server/) from all scan layers
* Custom dirs provided via workflows: { dirs: [] } nitro config
5 changes: 3 additions & 2 deletions packages/nitro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@
},
"dependencies": {
"@swc/core": "1.11.24",
"@workflow/swc-plugin": "workspace:*",
"@workflow/cli": "workspace:*",
"@workflow/core": "workspace:*",
"exsolve": "^1.0.7"
"@workflow/swc-plugin": "workspace:*",
"exsolve": "^1.0.7",
"pathe": "^2.0.3"
},
"devDependencies": {
"@types/node": "catalog:",
Expand Down
17 changes: 15 additions & 2 deletions packages/nitro/src/builders.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { mkdir, readFile, writeFile } from 'node:fs/promises';
import { join } from 'node:path';
import { BaseBuilder } from '@workflow/cli/dist/lib/builders/base-builder';
import { VercelBuildOutputAPIBuilder } from '@workflow/cli/dist/lib/builders/vercel-build-output-api';
import type { Nitro } from 'nitro/types';
import { join, resolve } from 'pathe';

const CommonBuildOptions = {
dirs: ['workflows'],
buildTarget: 'next' as const, // unused in base
stepsBundlePath: '', // unused in base
workflowsBundlePath: '', // unused in base
Expand All @@ -16,6 +15,7 @@ export class VercelBuilder extends VercelBuildOutputAPIBuilder {
constructor(nitro: Nitro) {
super({
...CommonBuildOptions,
dirs: getWorkflowDirs(nitro),
workingDir: nitro.options.rootDir,
});
}
Expand All @@ -38,6 +38,7 @@ export class LocalBuilder extends BaseBuilder {
const outDir = join(nitro.options.buildDir, 'workflow');
super({
...CommonBuildOptions,
dirs: getWorkflowDirs(nitro),
workingDir: nitro.options.rootDir,
watch: nitro.options.dev,
});
Expand Down Expand Up @@ -68,3 +69,15 @@ export class LocalBuilder extends BaseBuilder {
});
}
}

export function getWorkflowDirs(nitro: Nitro) {
return unique([
...(nitro.options.workflow?.dirs ?? []),
join(nitro.options.rootDir, 'workflows'),
...nitro.options.scanDirs.map((dir) => join(dir, 'workflows')),
].map((dir) => resolve(nitro.options.rootDir, dir))).sort();
}

function unique<T>(array: T[]): T[] {
return Array.from(new Set(array));
}
9 changes: 6 additions & 3 deletions packages/nitro/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { posix } from 'node:path';
import type { Nitro, NitroModule, RollupConfig } from 'nitro/types';
import { join } from 'pathe';
import { LocalBuilder, VercelBuilder } from './builders';
import { workflowRollupPlugin } from './rollup-plugin';
import type { ModuleOptions } from './types';

export type { ModuleOptions };

export default {
name: 'workflow/nitro',
Expand Down Expand Up @@ -61,13 +64,13 @@ function addVirtualHandler(nitro: Nitro, route: string, buildPath: string) {
// Nitro v2 (legacy)
nitro.options.virtual[`#${buildPath}`] = /* js */ `
import { fromWebHandler } from "h3";
import { POST } from "${posix.join(nitro.options.buildDir, buildPath)}";
import { POST } from "${join(nitro.options.buildDir, buildPath)}";
export default fromWebHandler(POST);
`;
} else {
// Nitro v3+ (native web handlers)
nitro.options.virtual[`#${buildPath}`] = /* js */ `
import { POST } from "${posix.join(nitro.options.buildDir, buildPath)}";
import { POST } from "${join(nitro.options.buildDir, buildPath)}";
export default ({ req }) => POST(req);
`;
}
Expand Down
21 changes: 21 additions & 0 deletions packages/nitro/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export interface ModuleOptions {
/**
* Directories to scan for workflows and steps.
*
* By default, `workflows/` directory will be scanned from root and all layer source dirs.
*/
dirs?: string[];
}

declare module 'nitro/types' {
interface NitroOptions {
workflow?: ModuleOptions;
}
}

// @ts-expect-error (legacy)
declare module 'nitropack' {
interface NitroOptions {
workflow?: ModuleOptions;
}
}
30 changes: 30 additions & 0 deletions packages/nitro/test/dirs.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { Nitro } from 'nitro/types';
import { describe, expect, test } from 'vitest';
import { getWorkflowDirs } from '../src/builders.ts';

const nitroMock = (dirs: string[]) => {
return ({
options: {
rootDir: '/root',
scanDirs: ['/root/server/'],
workflow: { dirs: dirs },
},
}) as unknown as Nitro;
}

describe('nitro:getWorkflowDirs', () => {
test('default dirs', () => {
const result = getWorkflowDirs(nitroMock([]));
expect(result).toEqual(['/root/server/workflows', '/root/workflows']);
});

test('custom dirs', () => {
const result = getWorkflowDirs(nitroMock(['./relative/dir1', '/custom/dir2']));
expect(result).toEqual([
'/custom/dir2',
'/root/relative/dir1',
'/root/server/workflows',
'/root/workflows',
]);
});
});
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion workbench/nitro-v3/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
"start": "node .output/server/index.mjs"
},
"devDependencies": {
"workflow": "workspace:*",
"ai": "catalog:",
"lodash.chunk": "^4.2.0",
"nitro": "npm:[email protected]",
"openai": "^6.1.0",
"workflow": "workspace:*",
"zod": "catalog:"
}
}
Loading