Just in case someone in the future needs, here’s how you can use bundling with ESM and Nx:
In your tsconfig.json
:
{
"extends": "@tsconfig/node18/tsconfig.json",
"version": "5.0.4",
"compilerOptions": {
"strict": true,
"module": "ESNext",
"moduleResolution": "node",
"target": "ESNext",
"rootDir": "./src",
"outDir": "./lib",
"baseUrl": "."
},
"include": ["src/**/*.ts"]
}
The code to bundle has this general format:
import { bundleWorkflowCode } from '@temporalio/worker';
import { writeFile } from 'node:fs/promises';
import path from 'node:path';
import { createRequire } from 'node:module';
import { fileURLToPath } from 'node:url';
const require = createRequire(import.meta.url);
const __dirname = fileURLToPath(new URL('.', import.meta.url))
async function bundle() {
const { code } = await bundleWorkflowCode({
workflowsPath: require.resolve('../src/workflows/workflows'),
});
const codePath = path.join(__dirname, '../lib/workflow-bundle.js');
await writeFile(codePath, code);
console.log(`Bundle written to ${codePath}`);
}
bundle().catch((err) => {
console.error(err);
process.exit(1);
});
The easiest way was to just recreate require
to be honest… I’m open to ideas here if anyone wants to share!
In the worker, here’s how you can have bundling for production but loading workflows from a file in development:
import { Worker } from '@temporalio/worker';
import { URL, fileURLToPath } from 'node:url';
import * as activities from './activities.js';
import path from 'node:path';
function workflowOptions() {
if (process.env.STAGE === 'production') {
const workflowBundlePathURL = new URL('./workflow-bundle.js', import.meta.url)
return {
workflowBundle: {
codePath: fileURLToPath(workflowBundlePathURL)
}
}
}
const workflowsPathUrl = new URL(`./workflows/workflows${path.extname(import.meta.url)}`, import.meta.url)
return {
workflowsPath: fileURLToPath(workflowsPathUrl)
}
}
async function run() {
const worker = await Worker.create({
...workflowOptions(),
activities,
taskQueue: 'hello-world',
});
await worker.run();
}
The package.json
scripts look like this:
{
"test": "jest",
"build": "tsc --build && npm run bundle",
"bundle": "node --experimental-specifier-resolution=node --loader ts-node/esm scripts/build-workflow-bundle.ts",
"build.watch": "tsc --build --watch",
"worker": "nodemon --exec 'node --experimental-specifier-resolution=node --loader ts-node/esm' src/worker.ts",
}
Assuming this is under packages/workflows
and that Nx is configured as a package-based monorepo, you can just run nx run workflows:build
.