Unable to resolve "event-target-shim/index" from "node_modules/@livekit/react-native-webrtc/src/MediaDevices.ts"
Describe the bug After installing all dependencies as per document we are facing "Unable to resolve "event-target-shim/index" from "node_modules/@livekit/react-native-webrtc/src/MediaDevices.ts" error.
To Reproduce
Steps to reproduce the behavior:
- Install all dependencies as per document.
- Run npx expo run:ios
- See error
Expected behavior
App should work without any issues
Screenshots
Device Info:
- Device: Iphone 16
- OS: 18
Dependencies Info (please reference your package-lock.json or yarn.lock file, not just your package.json):
- @livekit/react-native:
- livekit-client:
- react-native-webrtc:
Additional context We are having bare managed flow for react native expo.
Do you have a metro.config.js file in your expo project? If so, you may have changed your resolver in a way that it can't find the event-target-shim package. You might need to add a new config for config.resolver.extraNodeModules that points it to the correct path.
When we try to make import like
import { EventTarget, Event, defineEventAttribute } from 'event-target-shim'
instead of
import { EventTarget, Event, defineEventAttribute } from 'event-target-shim/index'
updated this changes in node_modules for time being. WIth this the above issue is resolved but now getting following error on import
import {registerGlobals} from '@livekit/react-native';
registerGlobals();
ERROR TypeError: Super expression must either be null or a function, js engine: hermes
Yeah, that won't work, since the event-target-shim and event-target-shim/index are meant to resolve to two separate packages, due to RN and RN-webrtc resolving to two separate versions of the package. Context here: https://github.com/react-native-webrtc/react-native-webrtc/issues/1503
Can you provide your metro.config.js file?
Here is my config file
const {getDefaultConfig} = require('expo/metro-config'); const path = require('path'); const fs = require('fs');
// Set your root paths const projectRoot = __dirname; const workspaceRoot = path.resolve(projectRoot, '../..'); const packagesRoot = path.resolve(workspaceRoot, 'packages'); const coreAppRoot = path.resolve(packagesRoot, 'core');
// Get default config and override projectRoot const config = getDefaultConfig(projectRoot); config.projectRoot = coreAppRoot;
// Optional: Add source extensions if needed config.resolver.sourceExts = [...config.resolver.sourceExts, 'cjs', 'mjs'];
// Add terser minifier config.transformer.minifierPath = 'metro-minify-terser';
// 1. Watch entire monorepo config.watchFolders = [workspaceRoot];
// 2. Set node module resolution paths const getDirs = (root) => fs .readdirSync(root, {withFileTypes: true}) .filter((dir) => dir.isDirectory()) .filter((dir) => dir.name !== 'core') // skip core since it's already set as projectRoot .map((dir) => dir.name);
const packages = getDirs(packagesRoot);
config.resolver.nodeModulesPaths = [ path.resolve(projectRoot, 'node_modules'), path.resolve(workspaceRoot, 'node_modules'), ...packages.map((packageName) => path.resolve(packagesRoot, packageName, 'node_modules'), ), ];
// 3. Force Metro to resolve subdependencies only from above paths config.resolver.disableHierarchicalLookup = true;
// 4. Extra polyfills or shims config.resolver.extraNodeModules = { stream: require.resolve('readable-stream'), 'event-target-shim/index': path.resolve( workspaceRoot, 'node_modules/event-target-shim/index', ), };
// Optional: Rewrite URL workaround for iOS config.server.rewriteRequestUrl = (url) => { if (!url.endsWith('.bundle')) return url;
return ( url + '?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true' ); };
module.exports = config;
Hi @davidliu Can you please provide any update on above issue ?
I think the config here is disabling it from looking up subdependencies:
// 3. Force Metro to resolve subdependencies only from above paths
config.resolver.disableHierarchicalLookup = true;
See this for reference: https://github.com/react-native-webrtc/react-native-webrtc/issues/1567#issuecomment-2227736860
If it's possible to turn it to false, that probably would fix it directly.
Alternatively, if that's not possible, then you can go look for where the event-target-shim subdependency gets put and add it to config.resolver.extraNodeModules or config.resolver.nodeModulesPaths. Note that react-native depends on ~5.0.0, but react-native-webrtc depends on ~6.0.0. Verify the package you're pointing at is the ~6.0.0 version. I think the existing one you're pointing at might be the ~5.0.0 version.
For reference default expo with yarn or npm installs it at the path node_modules/@livekit/react-native-webrtc/node_modules/event-target-shim for me, but this may be different for you.
If this doesn't work, I'll need some details on how your workspace is setup so I can emulate it myself, including the package manager and version that you're using.
@davidliu Above issue resolved after adding following in metro config, but facing new error after this.
config.resolver.resolveRequest = (context, moduleName, platform) => {
if (
// If the bundle is resolving "event-target-shim" from a module that is part of "react-native-webrtc".
// moduleName.startsWith('event-target-shim') &&¸
context.originModulePath.includes('react-native-webrtc')
) {
// Resolve event-target-shim relative to the react-native-webrtc package to use v6.
// React Native requires v5 which is not compatible with react-native-webrtc.
const eventTargetShimPath = resolveFrom(
context.originModulePath,
moduleName,
);
return {
filePath: eventTargetShimPath,
type: 'sourceFile',
};
}
// Ensure you call the default resolver.
return context.resolveRequest(context, moduleName, platform);
};
ERROR Error: Cannot find module './EventEmitter' Require stack:
- /Users/xyz/Documents/xxxx/node_modules/@livekit/react-native-webrtc/src/index.ts/noop.js
What's the purpose of the rest of the stuff in the metro config? This would be faster if I could emulate the setup and package manager you're using to repro, but it seems very custom.
@davidliu The rest stuff is related to other features in the project, i have tested after removing those from metro config still i face that issue.
iOS packages/core/index.js ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░ 95.2% (4254/4359)[metropolis311.debug.dylib] Metro has encountered an error: Package subpath './index' is not defined by "exports" in
/Users/sharad.pawar/Documents/xyz-mobile/node_modules/@livekit/react-native-webrtc/node_modules/event-target-shim/package.json: node:internal/errors (405:5)
ERROR Error: Package subpath './index' is not defined by "exports" in /Users/sharad.pawar/Documents/xyz-mobile/node_modules/@livekit/react-native-webrtc/node_modules/event-target-shim/package.json
Below is current metro config
const {getDefaultConfig} = require('expo/metro-config');
const path = require('path');
const fs = require('fs');
const resolveFrom = require('resolve-from');
// Set your root paths
const projectRoot = __dirname;
const workspaceRoot = path.resolve(projectRoot, '../..');
const packagesRoot = path.resolve(workspaceRoot, 'packages');
const coreAppRoot = path.resolve(packagesRoot, 'core');
// // Get default config and override projectRoot
const config = getDefaultConfig(projectRoot);
config.projectRoot = coreAppRoot;
// // Optional: Add source extensions if needed
config.resolver.sourceExts = [...config.resolver.sourceExts, 'cjs', 'mjs'];
// // Add terser minifier
config.transformer.minifierPath = 'metro-minify-terser';
// // 1. Watch entire monorepo
config.watchFolders = [workspaceRoot];
// 2. Set node module resolution paths
const getDirs = (root) =>
fs
.readdirSync(root, {withFileTypes: true})
.filter((dir) => dir.isDirectory())
.filter((dir) => dir.name !== 'core') // skip core since it's already set as projectRoot
.map((dir) => dir.name);
const packages = getDirs(packagesRoot);
config.resolver.nodeModulesPaths = [
path.resolve(projectRoot, 'node_modules'),
path.resolve(workspaceRoot, 'node_modules'),
...packages.map((packageName) =>
path.resolve(packagesRoot, packageName, 'node_modules'),
),
];
// Optional: Rewrite URL workaround for iOS
config.server.rewriteRequestUrl = (url) => {
if (!url.endsWith('.bundle')) return url;
return (
url + '?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true'
);
};
// Learn more https://docs.expo.io/guides/customizing-metro
/** @type {import('expo/metro-config').MetroConfig} */
Do you still think it is something with metro config?
We're encountering the same issue:
iOS Bundling failed 42470ms index.js (13723 modules)
error: Error: Missing "./index" specifier in "event-target-shim" package
Here is our metro.config.js. It's been modified to support our monorepo structure and Package Exports:
const { getDefaultConfig } = require('expo/metro-config');
const path = require('path');
const projectRoot = __dirname;
const monorepoRoot = path.resolve(projectRoot, '..');
/** @type {import('expo/metro-config').MetroConfig} */
const config = getDefaultConfig(__dirname);
// https://reactnative.dev/blog/2023/06/21/package-exports-support
config.resolver.unstable_enablePackageExports = true;
config.transformer.getTransformOptions = async () => ({
transform: {
inlineRequires: true,
},
});
// Watch monorepo root node_modules for changes
config.watchFolders = [
path.resolve(monorepoRoot, 'node_modules'),
path.resolve(monorepoRoot, 'shared'),
projectRoot,
];
config.resolver.nodeModulesPaths = [
path.resolve(projectRoot, 'node_modules'),
path.resolve(monorepoRoot, 'node_modules'),
];
module.exports = config;
We're using pnpm 10.7.0 with node-linker=hoisted (as required for Expo), Expo 51.0.30, and React Native 0.74.5.
Our structure looks something like this:
.
|- package.json
|- node_modules/
|- app/
|- node_modules/
|- package.json
|- ...
|- web/
|- node_modules/
|- package.json
|- ...
|- shared/
|- ...
where app/ has the RN/Expo LiveKit SDK packages installed, and web/ has the web/React LiveKit SDK packages.
I tried the modified config.resolver.resolveRequest @shared-incapsulate shared above and also ran into the same error as @sharad-incapsulate.
I resolved this by patching @livekit/react-native-webrtc to replace all instances of event-target-shim/index with event-target-shim.
I did not get an error on registerGlobals();, so it would seem something about how we're resolving modules resolves them correctly. Perhaps having
config.resolver.unstable_enablePackageExports = true;
fixes the issue with disambiguating versions.
I was porting the sample https://github.com/livekit-examples/react-native-meet to test out in the latest expo and I get this similar error
WARN Attempted to import the module "/.../expo-audio-app-test-livekit/test/node_modules/@livekit/react-native-webrtc/node_modules/event-target-shim/index" which is not listed in the "exports" of "/.../expo-audio-app-test-livekit/test/node_modules/@livekit/react-native-webrtc/node_modules/event-target-shim" under the requested subpath "./index". Falling back to file-based resolution. Consider updating the call site or asking the package maintainer(s) to expose this API.
iOS Bundling failed 8716ms node_modules/expo-router/entry.js (1327 modules)
ERROR SyntaxError: /.../expo-audio-app-test-livekit/test/app/src/callservice/CallService.d.ts: Missing semicolon. (1:7)
> 1 | declare async function startCallService();
| ^
2 | declare async function stopCallService();
3 | export { startCallService, stopCallService };
which seems to be similar error. Any help here?
All i did was create a sample default expo app then imported the <App /> component (and its deps) the react-native-meet repo
It would appear this is a bug with @livekit/react-native-webrtc.
I'll start with my workaround, then explain why I think it's happening.
Workaround
First, you'll want to ensure every dependency uses the version of `event-target-shim` that supports the `exports` field.
For pnpm:
// in the root package.json:
"resolutions": {
"event-target-shim": "6.0.2"
},
Then, you can apply this minimal patch for [email protected] to add /index as an export path and point it to the entrypoint:
diff --git a/package.json b/package.json
index 045cf8bb2890a73e03d8aad727ab9f81bae2176a..420303ed1a1f19884d53f8d6bc23316cb68a3973 100644
--- a/package.json
+++ b/package.json
@@ -8,6 +8,10 @@
"import": "./index.mjs",
"require": "./index.js"
},
+ "./index": {
+ "import": "./index.mjs",
+ "require": "./index.js"
+ },
"./es5": {
"import": "./es5.mjs",
"require": "./es5.js"
This will ensure @livekit/react-native-webrtc can resolve the bad imports until a proper fix is available.
Root Cause
Every file depending on `event-target-shim` imports it like so:
import { EventTarget, defineEventAttribute } from 'event-target-shim/index';
Module resolution is pretty gnarly for TS projects, so there are a couple of reasons this might have been valid at once (or seemed valid and passed CI, but then breaks in other projects).
Taking a look at version 5 of event-target-shim, I noticed it relies on the legacy main field in package.json:
"main": "dist/event-target-shim",
"types": "index.d.ts",
"files": [
"dist",
"index.d.ts"
]
The correct import specifier in this case would be event-target-shim (without the /index supbath).
Version 6, however, embraces the modern best practice of using the exports in package.json (but retains the main field as a fallback):
"main": "index.js",
"exports": {
".": {
"import": "./index.mjs",
"require": "./index.js"
},
"./es5": {
"import": "./es5.mjs",
"require": "./es5.js"
},
"./umd": "./umd.js",
"./package.json": "./package.json"
},
There's no ./index under the exports field—so the correct import specifier for bundlers/runtimes support package.json exports is event-target-shim (again without /index. For bundlers/runtimes that don't, that doesn't change—it will just fall back to the file specified in main.
Under any circumstance that I can tell, @livekit/react-native-webrtc should NOT specify the /index subpath when importing event-target-shim.
@helmturner so this issue has quite a bit of history behind it. Basically react-native-webrtc targets event-target-shim ^6.0.0, but react-native relies on ^5.0.0 and hasn't still upgraded it in quite a while.
https://github.com/react-native-webrtc/react-native-webrtc/issues/1503
The quirky workaround is what we've been relying on so that the different versions are resolved correctly. It isn't really feasible at the moment to downgrade event-target-shim back to ^5.0.0 to fix this.
If you've got a example repo available that repros the issue, that'd be very extremely helpful, as maybe we can figure out a different way to deal with this better.