Skip to main content
All writing

Package exports and eslint-plugin-import

10 February 20251 min read172 words

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

Get new posts by email

Occasional notes on platform engineering, AI agents and frontend architecture. No spam, unsubscribe anytime.