How do I create a Webpack bundle with a payload converter?

I opened a GitHub issue at [Feature Request] Add example of bundling with a payload converter · Issue #324 · temporalio/samples-typescript · GitHub.

I have a Webpack-bundled app, and want to add a payload converter. I’ve managed to get the worker bundle created. However, the client code resolution doesn’t work. When I start my service (NestJS, with modules that have Temporal clients), I see the following error when an attempt is made (during NestJS startup) to instantiate a client:

ValueError: Could not find a file at the specified payloadConverterPath: './shared/temporal/payload-converter.ts'.

What’s the correct way to bundle this given all the code is in index.js?

Seems like you can pass payloadConverterPath as an option to the bundleWorkflowCode function. Does that work?

No, that does not work for the client code. Webpack is the issue here. I need to figure out how to get rid of it, especially since there is no need to combine the server files into a single file.

Seems like you’re bundling your entire backend application and not just using the SDK’s workflow bundler.
You’ll need to have the payload converter path and all of its dependencies available to the application and possibly won’t be able to use relative paths, this beats the purpose of bundling your app IMHO.
You could also create another webpack entrypoint for the payload converter if you think bundling is required.
Since your converter it’s a TypeScript file, you’ll need to either ensure that you have it in a compiled format or that you’re starting your program with ts-node or a similar tool.

I’m curious what bundling a server side application buys you.

Server-side bundling buys us nothing. The project was setup that way before I joined, and I haven’t had time to remove Webpack.

This issue should be considered closed. As I mentioned in the previous comment, the issue is Webpack, not Temporal.

1 Like

It is too bad temporal doesn’t support actual modules besides payloadConverterPath. Anyways a possible workaround is possible:

  const worker = await Worker.create({
        connection,
        workflowBundle: {
            codePath,
        },
        activities: createActivities({ ... }),
        dataConverter: { payloadConverterPath: '__payloadConverter' },
        taskQueue,
    });

And somewhere early in your server code:

const Module = require('module');
const originalRequire = Module.prototype.require;

Module.prototype.require = function(moduleName){
    if (moduleName === '__payloadConverter') {
        return require('serverPath/.../payloadConverter');
    }
    return originalRequire.apply(this, arguments);
};

Actually our original solution built the payloadConverter separately and the build module placed next to our server bundle, but this created another problem, the modules, hence the classes were different in the activities and what payloadConverter returned.