Skip to content
Merged
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
8 changes: 8 additions & 0 deletions .changeset/soft-pets-yawn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@workflow/sveltekit": patch
"@workflow/builders": patch
"@workflow/astro": patch
"@workflow/next": patch
---

Pass `tsconfig` to esbuild for support of "paths" aliases
9 changes: 9 additions & 0 deletions lib/steps/paths-alias-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* This is a utility function from outside the workbench app directory.
* It is used to test that esbuild can resolve tsconfig path aliases.
* Note: This is NOT a step function - it's a regular function that gets called
* from within a step to verify path alias imports work correctly.
*/
export function pathsAliasHelper(): string {
return 'pathsAliasHelper';
}
23 changes: 8 additions & 15 deletions packages/astro/src/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,12 @@ export class LocalBuilder extends BaseBuilder {

// Get workflow and step files to bundle
const inputFiles = await this.getInputFiles();
const tsConfig = await this.getTsConfigOptions();
const tsconfigPath = await this.findTsConfigPath();

const options = {
inputFiles,
workflowGeneratedDir,
tsBaseUrl: tsConfig.baseUrl,
tsPaths: tsConfig.paths,
tsconfigPath,
};

// Generate the three Astro route handlers
Expand All @@ -68,13 +67,11 @@ export class LocalBuilder extends BaseBuilder {
private async buildStepsRoute({
inputFiles,
workflowGeneratedDir,
tsPaths,
tsBaseUrl,
tsconfigPath,
}: {
inputFiles: string[];
workflowGeneratedDir: string;
tsBaseUrl?: string;
tsPaths?: Record<string, string[]>;
tsconfigPath?: string;
}) {
// Create steps route: .well-known/workflow/v1/step.js
const stepsRouteFile = join(workflowGeneratedDir, 'step.js');
Expand All @@ -83,8 +80,7 @@ export class LocalBuilder extends BaseBuilder {
inputFiles,
outfile: stepsRouteFile,
externalizeNonSteps: true,
tsBaseUrl,
tsPaths,
tsconfigPath,
});

let stepsRouteContent = await readFile(stepsRouteFile, 'utf-8');
Expand All @@ -106,13 +102,11 @@ export const prerender = false;`
private async buildWorkflowsRoute({
inputFiles,
workflowGeneratedDir,
tsPaths,
tsBaseUrl,
tsconfigPath,
}: {
inputFiles: string[];
workflowGeneratedDir: string;
tsBaseUrl?: string;
tsPaths?: Record<string, string[]>;
tsconfigPath?: string;
}) {
// Create workflows route: .well-known/workflow/v1/flow.js
const workflowsRouteFile = join(workflowGeneratedDir, 'flow.js');
Expand All @@ -121,8 +115,7 @@ export const prerender = false;`
outfile: workflowsRouteFile,
bundleFinalOutput: false,
inputFiles,
tsBaseUrl,
tsPaths,
tsconfigPath,
});

let workflowsRouteContent = await readFile(workflowsRouteFile, 'utf-8');
Expand Down
1 change: 0 additions & 1 deletion packages/builders/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
"@workflow/core": "workspace:*",
"builtin-modules": "5.0.0",
"chalk": "5.6.2",
"comment-json": "4.2.5",
"enhanced-resolve": "5.18.2",
"esbuild": "catalog:",
"find-up": "7.0.0",
Expand Down
10 changes: 1 addition & 9 deletions packages/builders/src/apply-swc-transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,7 @@ export type WorkflowManifest = {
export async function applySwcTransform(
filename: string,
source: string,
mode: 'workflow' | 'step' | 'client' | false,
jscConfig?: {
paths?: Record<string, string[]>;
// this must be absolute path
baseUrl?: string;
}
mode: 'workflow' | 'step' | 'client' | false
): Promise<{
code: string;
workflowManifest: WorkflowManifest;
Expand Down Expand Up @@ -62,9 +57,6 @@ export async function applySwcTransform(
plugins: [[require.resolve('@workflow/swc-plugin'), { mode }]],
}
: undefined,

...jscConfig,

transform: {
react: {
runtime: 'preserve',
Expand Down
69 changes: 12 additions & 57 deletions packages/builders/src/base-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
import { basename, dirname, join, relative, resolve } from 'node:path';
import { promisify } from 'node:util';
import chalk from 'chalk';
import { parse } from 'comment-json';
import enhancedResolveOriginal from 'enhanced-resolve';
import * as esbuild from 'esbuild';
import { findUp } from 'find-up';
Expand Down Expand Up @@ -40,52 +39,12 @@ export abstract class BaseBuilder {
abstract build(): Promise<void>;

/**
* Extracts TypeScript path mappings and baseUrl from tsconfig.json/jsconfig.json.
* Used to properly resolve module imports during bundling.
* Finds tsconfig.json/jsconfig.json for the project.
* Used by esbuild to properly resolve module imports during bundling.
*/
protected async getTsConfigOptions(): Promise<{
baseUrl?: string;
paths?: Record<string, string[]>;
}> {
const options: {
paths?: Record<string, string[]>;
baseUrl?: string;
} = {};

protected async findTsConfigPath(): Promise<string | undefined> {
const cwd = this.config.workingDir || process.cwd();

const tsJsConfig = await findUp(['tsconfig.json', 'jsconfig.json'], {
cwd,
});

if (tsJsConfig) {
try {
const rawJson = await readFile(tsJsConfig, 'utf8');
const parsed: null | {
compilerOptions?: {
paths?: Record<string, string[]> | undefined;
baseUrl?: string;
};
} = parse(rawJson) as any;

if (parsed) {
options.paths = parsed.compilerOptions?.paths;

if (parsed.compilerOptions?.baseUrl) {
options.baseUrl = resolve(cwd, parsed.compilerOptions.baseUrl);
} else {
options.baseUrl = cwd;
}
}
} catch (err) {
console.error(
`Failed to parse ${tsJsConfig} aliases might not apply properly`,
err
);
}
}

return options;
return findUp(['tsconfig.json', 'jsconfig.json'], { cwd });
}

/**
Expand Down Expand Up @@ -288,11 +247,9 @@ export abstract class BaseBuilder {
format = 'cjs',
outfile,
externalizeNonSteps,
tsBaseUrl,
tsPaths,
tsconfigPath,
}: {
tsPaths?: Record<string, string[]>;
tsBaseUrl?: string;
tsconfigPath?: string;
inputFiles: string[];
outfile: string;
format?: 'cjs' | 'esm';
Expand Down Expand Up @@ -394,6 +351,8 @@ export abstract class BaseBuilder {
minify: false,
jsx: 'preserve',
logLevel: 'error',
// Use tsconfig for path alias resolution
tsconfig: tsconfigPath,
resolveExtensions: [
'.ts',
'.tsx',
Expand All @@ -411,8 +370,6 @@ export abstract class BaseBuilder {
mode: 'step',
entriesToBundle: externalizeNonSteps ? combinedStepFiles : undefined,
outdir: outfile ? dirname(outfile) : undefined,
tsBaseUrl,
tsPaths,
workflowManifest,
}),
],
Expand Down Expand Up @@ -447,11 +404,9 @@ export abstract class BaseBuilder {
format = 'cjs',
outfile,
bundleFinalOutput = true,
tsBaseUrl,
tsPaths,
tsconfigPath,
}: {
tsPaths?: Record<string, string[]>;
tsBaseUrl?: string;
tsconfigPath?: string;
inputFiles: string[];
outfile: string;
format?: 'cjs' | 'esm';
Expand Down Expand Up @@ -523,6 +478,8 @@ export abstract class BaseBuilder {
// This intermediate bundle is executed via runInContext() in a VM, so we need
// inline source maps to get meaningful stack traces instead of "evalmachine.<anonymous>".
sourcemap: 'inline',
// Use tsconfig for path alias resolution
tsconfig: tsconfigPath,
resolveExtensions: [
'.ts',
'.tsx',
Expand All @@ -536,8 +493,6 @@ export abstract class BaseBuilder {
plugins: [
createSwcPlugin({
mode: 'workflow',
tsBaseUrl,
tsPaths,
workflowManifest,
}),
// This plugin must run after the swc plugin to ensure dead code elimination
Expand Down
23 changes: 8 additions & 15 deletions packages/builders/src/standalone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,11 @@ export class StandaloneBuilder extends BaseBuilder {

async build(): Promise<void> {
const inputFiles = await this.getInputFiles();
const tsConfig = await this.getTsConfigOptions();
const tsconfigPath = await this.findTsConfigPath();

const options = {
inputFiles,
tsBaseUrl: tsConfig.baseUrl,
tsPaths: tsConfig.paths,
tsconfigPath,
};
const manifest = await this.buildStepsBundle(options);
await this.buildWorkflowsBundle(options);
Expand All @@ -38,12 +37,10 @@ export class StandaloneBuilder extends BaseBuilder {

private async buildStepsBundle({
inputFiles,
tsPaths,
tsBaseUrl,
tsconfigPath,
}: {
inputFiles: string[];
tsBaseUrl?: string;
tsPaths?: Record<string, string[]>;
tsconfigPath?: string;
}) {
console.log('Creating steps bundle at', this.config.stepsBundlePath);

Expand All @@ -53,21 +50,18 @@ export class StandaloneBuilder extends BaseBuilder {
const { manifest } = await this.createStepsBundle({
outfile: stepsBundlePath,
inputFiles,
tsBaseUrl,
tsPaths,
tsconfigPath,
});

return manifest;
}

private async buildWorkflowsBundle({
inputFiles,
tsPaths,
tsBaseUrl,
tsconfigPath,
}: {
inputFiles: string[];
tsBaseUrl?: string;
tsPaths?: Record<string, string[]>;
tsconfigPath?: string;
}): Promise<void> {
console.log(
'Creating workflows bundle at',
Expand All @@ -82,8 +76,7 @@ export class StandaloneBuilder extends BaseBuilder {
await this.createWorkflowsBundle({
outfile: workflowBundlePath,
inputFiles,
tsBaseUrl,
tsPaths,
tsconfigPath,
});
}

Expand Down
15 changes: 1 addition & 14 deletions packages/builders/src/swc-esbuild-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ export interface SwcPluginOptions {
mode: 'step' | 'workflow' | 'client';
entriesToBundle?: string[];
outdir?: string;
tsPaths?: Record<string, string[]>;
tsBaseUrl?: string;
workflowManifest?: WorkflowManifest;
}

Expand Down Expand Up @@ -206,18 +204,7 @@ export function createSwcPlugin(options: SwcPluginOptions): Plugin {
}

const { code: transformedCode, workflowManifest } =
await applySwcTransform(
relativeFilepath,
source,
options.mode,
// we need to provide the tsconfig/jsconfig
// alias via swc so that we can resolve them
// with our custom resolve logic
{
paths: options.tsPaths,
baseUrl: options.tsBaseUrl,
}
);
await applySwcTransform(relativeFilepath, source, options.mode);

if (!options.workflowManifest) {
options.workflowManifest = {};
Expand Down
Loading