Summary
dist/index.mjs emits an extensionless subpath specifier for lodash, which Node's ESM resolver rejects. The ESM build is therefore not loadable by Node directly.
Reproduce
npm run build
node --input-type=module -e "import('./dist/index.mjs')"
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '<repo>/node_modules/lodash/debounce'
imported from <repo>/dist/index.mjs
Did you mean to import "lodash/debounce.js"?
Cause
src/custom/SearchBar.tsx:3:
import debounce from 'lodash/debounce';
lodash ships no exports map in its package.json, so under Node ESM a subpath import must carry the file extension (lodash/debounce.js). tsup keeps the specifier verbatim in the ESM output because lodash is external, so the unresolvable form reaches the published artifact.
Contrast @mui/icons-material/X, which is also extensionless in the output but resolves fine - that package does declare an exports map. So this is specific to lodash, not a general problem with the build config.
Impact
Low today, but real:
- Bundler consumers are unaffected - webpack, vite, rollup and Next.js all apply Node-CJS-style resolution to bare specifiers, so Meshery UI and Kanvas do not see this.
- Node ESM consumers are affected - anything doing
import '@sistent/sistent' from a real ESM context (SSR, a script, a test runner in ESM mode, RSC server bundles) fails at load with a message naming lodash, not sistent.
It is the same shape of trap as #1735: the failure surfaces at import time, names a third-party package, and is invisible to CI because the repo always resolves through a bundler or jest's CJS transform.
Suggested fix
Either:
import { debounce } from 'lodash'; - resolves under both module systems. Costs bundle size unless tree-shaking is reliable here.
import debounce from 'lodash/debounce.js'; - smallest change, keeps the subpath, valid for both Node ESM and bundlers.
- Move
lodash from external to bundled for the ESM output in tsup.config.ts.
(2) is the least invasive. Whichever is chosen, it is worth extending the guard added in #1737 (src/__testing__/optionalPeerDependencies.test.ts) or adding a sibling check that actually imports the built dist/index.mjs under Node ESM, so the build output is verified rather than only the source import graph. That would catch this class directly instead of by inspection.
Notes
Pre-existing on master, unrelated to the optional-peer work in #1732/#1737. Found while content-verifying the v0.21.40 tarball; filed separately rather than folded into an unrelated patch release.
Summary
dist/index.mjsemits an extensionless subpath specifier forlodash, which Node's ESM resolver rejects. The ESM build is therefore not loadable by Node directly.Reproduce
npm run build node --input-type=module -e "import('./dist/index.mjs')"Cause
src/custom/SearchBar.tsx:3:lodashships noexportsmap in itspackage.json, so under Node ESM a subpath import must carry the file extension (lodash/debounce.js). tsup keeps the specifier verbatim in the ESM output becauselodashis external, so the unresolvable form reaches the published artifact.Contrast
@mui/icons-material/X, which is also extensionless in the output but resolves fine - that package does declare anexportsmap. So this is specific tolodash, not a general problem with the build config.Impact
Low today, but real:
import '@sistent/sistent'from a real ESM context (SSR, a script, a test runner in ESM mode, RSC server bundles) fails at load with a message naminglodash, not sistent.It is the same shape of trap as #1735: the failure surfaces at import time, names a third-party package, and is invisible to CI because the repo always resolves through a bundler or jest's CJS transform.
Suggested fix
Either:
import { debounce } from 'lodash';- resolves under both module systems. Costs bundle size unless tree-shaking is reliable here.import debounce from 'lodash/debounce.js';- smallest change, keeps the subpath, valid for both Node ESM and bundlers.lodashfrom external to bundled for the ESM output intsup.config.ts.(2) is the least invasive. Whichever is chosen, it is worth extending the guard added in #1737 (
src/__testing__/optionalPeerDependencies.test.ts) or adding a sibling check that actually imports the builtdist/index.mjsunder Node ESM, so the build output is verified rather than only the source import graph. That would catch this class directly instead of by inspection.Notes
Pre-existing on
master, unrelated to the optional-peer work in #1732/#1737. Found while content-verifying the v0.21.40 tarball; filed separately rather than folded into an unrelated patch release.