Add `exports` field to package.json for ESM subpath resolution

#482 · closed · 0 comments

View on GitHub ↗

kucheruk

### Summary `[email protected]` does not declare an `exports` field in `package.json`. The package exposes `main.js`, `renderer.js`, `preload.js`, and `node.js` as top-level entry points and documents them as `electron-log/main`, `electron-log/renderer`, etc. — but without an `exports` map, Node's ESM resolver does **not** add the `.js` extension automatically for subpath imports. As a result, projects with `"type": "module"` (or ESM-output bundlers) must write `electron-log/main.js` instead of `electron-log/main`, contradicting the README. ### Reproduction ```bash mkdir esm-repro && cd esm-repro npm init -y npm pkg set type=module npm i [email protected] node --input-type=module -e "import log from 'electron-log/main'; console.log(typeof log)" ``` Result on Node 18+/20+/22: ``` node:internal/modules/esm/resolve:... Cannot find module '.../node_modules/electron-log/main' imported from ... code: 'ERR_MODULE_NOT_FOUND' ``` Adding `.js`: ```bash node --input-type=module -e "import log from 'electron-log/main.js'; console.log(typeof log)" # object ``` Same behavior is observed when an Electron app's main process is bundled as ESM (e.g. `electron-vite` with `"type": "module"`), which is becoming the default after Electron 28+ ESM support. ### Why this matters - README and `.d.ts` files imply bare-subpath imports (`electron-log/main`) work. - CJS resolver auto-extends `.js`, so existing CJS users see no error — but any ESM user must add `.js`. This causes confusing errors only in production bundles. - Adding a minimal `exports` map preserves the current resolution for both CJS and ESM consumers, removes the `.js` workaround, and keeps `package.json` `"main"` / `"browser"` intact for legacy resolution. ### Proposed fix Add an `exports` field that mirrors the current top-level entry files: ```json "exports": { ".": { "types": "./src/index.d.ts", "default": "./src/index.js" }, "./main": { "types": "./main.d.ts", "import": "./main.js", "require": "./main.js" }, "./renderer": { "types": "./renderer.d.ts", "import": "./renderer.js", "require": "./renderer.js" }, "./preload": { "import": "./preload.js", "require": "./preload.js" }, "./node": { "types": "./node.d.ts", "import": "./node.js", "require": "./node.js" }, "./package.json": "./package.json" } ``` `./package.json` is included because `src/main/getNameAndVersion.js` reads the host project's `package.json` via `require('<app>/package.json')`; keeping it in `exports` is harmless and matches Node guidance for libraries that re-resolve their own `package.json`. This is purely additive — current CJS users keep working through the `"require"` condition, and there is no breaking change to existing subpath behavior **with** the `.js` extension. I am happy to open a PR with this change (no source changes, only `package.json`). Let me know if you'd like a different shape (e.g. omit `"./node"`, or use a single `"default"` condition). ### Environment - electron-log: 5.4.3 - Node: 20.x, 22.x - Project: ESM (`"type": "module"`) Electron app bundled by `electron-vite`

Comments