Skip to content

AMD define() in UMD wrapper breaks Turbopack production builds #386

@johanhenrikssn

Description

@johanhenrikssn

Summary

Every source file is wrapped in a UMD wrapper that includes an AMD define() branch. This breaks Turbopack (the default bundler in Next.js 16+) during production builds with TP1200: unsupported AMD define() form, even when the package is marked as an external dependency.

The AMD branch is unreachable dead code, since this is a Node.js-only package and Node.js has never supported AMD natively. Removing the AMD branch from the codegen template would fix Turbopack without breaking any existing consumer.

Environment

  • docusign-esign@8.7.0
  • next@16.2.3 (Turbopack, default in Next.js 16+)
  • Node.js 24

Error

Error: Turbopack build failed with 2 errors:
./node_modules/docusign-esign/src/Configuration.js:4:5
TP1200 unsupported AMD define() dependency element form

./node_modules/docusign-esign/src/index.js:14:5
TP1200 unsupported AMD define() form

Turbopack does not implement an AMD parser. Marking the package as external via serverExternalPackages or turbopack.resolveAlias does not help, because Turbopack's externals-tracing phase still parses the files during production builds and fails on the AMD branch.

Root cause

Every file in node_modules/docusign-esign/src/ uses a UMD wrapper, e.g.:

(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define([undefined, './ApiClient'], factory);  // <-- fails here
  } else if (typeof module === 'object' && module.exports) {
    module.exports = factory(undefined, require('./ApiClient'));
  } else {
    root.Docusign = {};
    factory(root.Docusign, root.Docusign.ApiClient);
  }
}(this, function(module, ApiClient) {
  // ...
}));

In Node.js, define is never defined, so the AMD branch never executes. Only the CommonJS branch runs. The AMD branch is left over from the Swagger/OpenAPI codegen UMD template.

Why AMD should be removed

AMD (Asynchronous Module Definition) was a community specification from ~2011 for async module loading in browsers via RequireJS.

  • AMD was never standardized in any TC39 spec.
  • Node.js has never supported AMD natively. AMD was a browser pattern, requiring RequireJS or a similar loader.
  • RequireJS itself is end-of-life: it was moved to OpenJS Foundation Emeritus status and is no longer actively developed.
  • ES Modules (ESM) have been the official JavaScript module standard since ES2015 and are natively supported in modern browsers and Node.js (>=12).
  • No modern bundler parses AMD except webpack, which retains support only for legacy compatibility. Turbopack, Vite/Rollup, and esbuild do not implement an AMD parser.

Since this is published as a Node.js SDK (it depends on superagent, uses fs/path/crypto, etc.), the AMD and browser-globals branches of the UMD wrapper are dead code in every environment the package actually runs in. Removing them is a non-breaking change.

Suggested fix

The .swagger-codegen-ignore file at the root of this repo confirms src/ is regenerated from Swagger Codegen, with only src/OAuth.js, src/RestApi.js, and src/oauth/ exempted from regeneration. The fix is to update the JavaScript client's UMD wrapper template (the mustache template that emits the (function(root, factory) { ... }(this, function(...) { ... })) shell around every file) to emit plain CommonJS, then regenerate.

Before (UMD with AMD branch, ~8 lines of boilerplate per file):

(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define([undefined, './ApiClient'], factory);
  } else if (typeof module === 'object' && module.exports) {
    module.exports = factory(undefined, require('./ApiClient'));
  } else {
    root.Docusign = {};
    factory(root.Docusign, root.Docusign.ApiClient);
  }
}(this, function(module, ApiClient) {
  // ...
}));

After (plain CommonJS):

const ApiClient = require('./ApiClient');
// ...
module.exports = SomeClass;

An ESM codegen target would also work and would additionally let downstream bundlers tree-shake unused models.

Current workaround

We are using pnpm patch to replace the AMD condition with false in all 623 generated files:

- if (typeof define === 'function' && define.amd) {
+ if (false) {

This disables the AMD branch so Turbopack skips it. It works, but every consumer on a modern bundler has to maintain their own patch.

Impact

This blocks any Next.js 16+ project from using Turbopack for production builds (which is now the default; webpack is no longer shipped as the default bundler). It also affects any Vite, Rollup, or esbuild-based project, though those are less commonly used for SSR Node.js apps that integrate with DocuSign.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions