Skip to content

Dependencies

Plugins can use npm packages. Since the gateway container doesn’t include your project’s node_modules, you need a strategy for making dependencies available at runtime.

Section titled “Bundled dependencies (recommended for most packages)”

esbuild bundles imported packages into the output file by default. This is the simplest approach — the compiled dist/plugin.js is self-contained:

Terminal window
npm install some-library
npm run build # esbuild bundles some-library into dist/plugin.js

No extra setup needed in the container.

Some npm packages don’t bundle correctly with esbuild. The most common case is UMD libraries — packages that use a wrapper like this internally:

if (typeof module !== "undefined") {
module.exports = f(); // clobbers the outer module.exports in the bundle
}

When esbuild bundles such a package into a single CJS file, the library’s module.exports = ... assignment overwrites your plugin’s exports, making init and handle disappear.

The gateway logs an error like:

plugin './dist/my-plugin.js': init() failed: function 'init' not found in module exports

Even though the functions are clearly defined in your source code.

Tell esbuild to skip bundling the problematic package:

{
"scripts": {
"build": "esbuild src/plugin.ts --bundle --format=cjs --platform=node --target=node22 --outfile=dist/plugin.js --external:problematic-package"
}
}

The compiled output will contain require("problematic-package") instead of inlining the package code. Node.js resolves this require() from node_modules/ at runtime — so you must ensure node_modules/ is available inside the container. The simplest way is to volume-mount your project directory (which includes node_modules/) into the container, the same way the examples mount their config directory:

volumes:
- ./:/config # mounts your project root, including node_modules/

If you don’t want to mount node_modules/ (e.g. in a production image), bundle the dependency instead of marking it external — or copy node_modules/ explicitly into your image.

  1. Build and run — if the plugin loads, bundling works fine
  2. If you see the “not found in module exports” error, check the bundle for stray module.exports = assignments from the dependency
  3. Add --external:package-name and rebuild

If your project has multiple plugins or interceptors, build each as a separate entry point:

{
"scripts": {
"build": "esbuild src/plugin.ts src/interceptor.ts --bundle --format=cjs --platform=node --target=node22 --outdir=dist"
}
}

Use --outdir instead of --outfile when building multiple files.