Summary
@livekit/components-react@2.9.24 inlines loglevel's UMD source into dist/room-Bfb4OWAI.mjs and reads it back through .default. The inlined wrapper keeps its AMD branch, so in any environment where a global define.amd exists, module.exports is never assigned and the package throws at module evaluation:
TypeError: <ns>.default.getLogger is not a function
2.9.23 is unaffected. Pinning to 2.9.23 is the only workaround we found.
The difference between 2.9.23 and 2.9.24
2.9.23 — dist/contexts-BtSGUJjc.mjs:2647, direct call on the module:
], I = zr.getLogger("lk-components-js");
2.9.24 — dist/room-Bfb4OWAI.mjs:2578, via .default:
], R = Ms.default.getLogger("lk-components-js");
where (same file, line 2405):
var Ms = /* @__PURE__ */ di(So(), 1);
So is an esbuild __commonJS factory wrapping loglevel's UMD source, inlined verbatim (same file, ~line 900):
So = /* @__PURE__ */ Qn(((e, t) => {
(function(n, r) {
"use strict";
typeof define == "function" && define.amd ? define(r) : typeof t == "object" && t.exports ? t.exports = r() : n.log = r();
})(e, function() { /* … loglevel … */ });
}));
Why that breaks
If a global define with .amd is present, the first branch wins: define(r) is called and t.exports is never assigned. So() therefore returns an empty exports object, __toESM({}, 1).default is {}, and .getLogger is undefined.
This is specifically a consequence of inlining the UMD build. A normal import loglevel from "loglevel" — which @livekit/components-core@0.12.15 still does, and which works — leaves the resolution to the host, where loglevel's self-reference (log.default === log) makes .default correct.
Where a global define.amd comes from
Two independent cases hit us:
- Build time — bundlers that parse AMD syntax. Our Next.js
output: 'export' prerender fails at module evaluation for every page that transitively imports LiveKit. Reproduces identically under both Turbopack and webpack (next build --webpack), so it is not a Turbopack-specific interop quirk.
- Runtime — an AMD loader on the page. We load part of our app as AMD micro-frontends, so
window.define.amd is defined globally; the LiveKit bundle then throws in the browser on load.
Note for reproduction
Importing the package directly in Node works, because there is no global define:
node --input-type=module -e "import('@livekit/components-react').then(()=>console.log('OK'))"
# → OK
So this can't be reproduced with a plain Node import — it needs a build, or a page with an AMD loader present.
What does not help
For anyone else hitting this, we measured all of these and none of them work:
transpilePackages: ['@livekit/components-core', '@livekit/components-react']
serverExternalPackages: [...] — the external then fails to load with the same error
next build --webpack instead of Turbopack
Only pinning to 2.9.23 fixes it.
Environment
@livekit/components-react 2.9.24 (broken) / 2.9.23 (works)
@livekit/components-core 0.12.15
livekit-client 2.22.1
loglevel 1.9.1 (as pinned by components-core)
- Next.js 16.3.3,
output: 'export'; also webpack 5.110 for the AMD micro-frontend bundle
- Node 24
Suggested fix
Don't inline loglevel's UMD build — either keep loglevel external (as components-core does), or inline its CJS/ESM entry rather than the UMD one so there is no define.amd branch to take.
Happy to test a canary against both of our builds if that helps.
Summary
@livekit/components-react@2.9.24inlinesloglevel's UMD source intodist/room-Bfb4OWAI.mjsand reads it back through.default. The inlined wrapper keeps its AMD branch, so in any environment where a globaldefine.amdexists,module.exportsis never assigned and the package throws at module evaluation:2.9.23 is unaffected. Pinning to
2.9.23is the only workaround we found.The difference between 2.9.23 and 2.9.24
2.9.23 —
dist/contexts-BtSGUJjc.mjs:2647, direct call on the module:2.9.24 —
dist/room-Bfb4OWAI.mjs:2578, via.default:where (same file, line 2405):
Sois an esbuild__commonJSfactory wrapping loglevel's UMD source, inlined verbatim (same file, ~line 900):Why that breaks
If a global
definewith.amdis present, the first branch wins:define(r)is called andt.exportsis never assigned.So()therefore returns an empty exports object,__toESM({}, 1).defaultis{}, and.getLoggerisundefined.This is specifically a consequence of inlining the UMD build. A normal
import loglevel from "loglevel"— which@livekit/components-core@0.12.15still does, and which works — leaves the resolution to the host, where loglevel's self-reference (log.default === log) makes.defaultcorrect.Where a global
define.amdcomes fromTwo independent cases hit us:
output: 'export'prerender fails at module evaluation for every page that transitively imports LiveKit. Reproduces identically under both Turbopack and webpack (next build --webpack), so it is not a Turbopack-specific interop quirk.window.define.amdis defined globally; the LiveKit bundle then throws in the browser on load.Note for reproduction
Importing the package directly in Node works, because there is no global
define:So this can't be reproduced with a plain Node import — it needs a build, or a page with an AMD loader present.
What does not help
For anyone else hitting this, we measured all of these and none of them work:
transpilePackages: ['@livekit/components-core', '@livekit/components-react']serverExternalPackages: [...]— the external then fails to load with the same errornext build --webpackinstead of TurbopackOnly pinning to
2.9.23fixes it.Environment
@livekit/components-react2.9.24 (broken) / 2.9.23 (works)@livekit/components-core0.12.15livekit-client2.22.1loglevel1.9.1 (as pinned by components-core)output: 'export'; also webpack 5.110 for the AMD micro-frontend bundleSuggested fix
Don't inline loglevel's UMD build — either keep
loglevelexternal (as components-core does), or inline its CJS/ESM entry rather than the UMD one so there is nodefine.amdbranch to take.Happy to test a canary against both of our builds if that helps.