Package exports and eslint-plugin-import

Posted 10 February 2025 · 1 min read

Tags:

I was recently creating a new npm package with multiple entrypoints. Using Vite library mode I configured the entry points:

import { defineConfig } from "vite";

export default defineConfig({
  build: {
    lib: {
      entry: {
        "library": "src/index.ts",
        "some-import": "src/some-import.ts",
      },
      name: "library",
    },
  },
});

I then added the exports field to the package's package.json file:

{
  "name": "library",
  "main": "./dist/library.cjs",
  "module": "./dist/library.js",
  "types": "./dist/library.d.ts",
  "exports": {
    ".": {
      "types": "./dist/library.d.ts",
      "import": "./dist/library.js",
      "require": "./dist/library.cjs",
      "default": "./dist/library.cjs"
    },
    "./some-import": {
      "types": "./dist/some-import.d.ts",
      "import": "./dist/some-import.js",
      "require": "./dist/some-import.cjs",
      "default": "./dist/some-import.cjs"
    }
  }
}

I then tried using this package in another project, and although TypeScript was able to resolve the module I was seeing errors from eslint:

error  Unable to resolve path to module 'library/some-import'  import/no-unresolved

I found this eslint-plugin-import issue with recommendations to switch to eslint-import-resolver-typescript, but I didn't want to force other projects to change their configuration just to use this package.

I also saw that in this same project we were importing msw/browser without any complaints from eslint, so I decided to look at how msw was configured.

// No complaints from eslint!
import { setupWorker } from "msw/browser";

msw's root package.json matched my own, but there was also a browser directory in the root of the package with another package.json:

// node_modules/msw/browser/package.json
{
  "main": "../lib/browser/index.js",
  "module": "../lib/browser/index.mjs",
  "types": "../lib/browser/index.d.ts"
}

This was the key to getting this working, helping the resolver treat msw/browser as a separate package which resolved correctly. I added an extra package.json to my own library in library/some-import/package.json:

{
  "main": "../dist/some-import.cjs",
  "module": "../dist/some-import.js",
  "types": "../dist/some-import.d.ts"
}

And everything worked as expected! I hope this helps you if you're running into similar issues.


Related posts

Mock server-sent events (SSE) with msw

Published · 2 min read

Mock Service Worker supports mocking SSE

Dynamically load remoteEntry.js files

Published · 2 min read

Control loading Webpack Module Federation remoteEntry.js files to improve peformance

Exclude node_modules with Webpack

Published · 2 min read

Avoid bundling dependencies when building a library

Subscribe via RSS to get new posts delivered to your feed reader, or browse posts by tag.


Thanks for reading

I'm Alex O'Callaghan and this is my personal website where I write about software development and do my best to learn in public. I currently work at Mintel as a Principal Engineer working primarily with React, TypeScript & Python.

I've been leading one of our platform teams maintaining a collection of shared libraries, services and a micro-frontend architecture.

I'm from London and you can find me on a few different social media platforms: