How to publish TypeScript modules on NPM without "dist" in import?

I found a pretty clean solution that doesn't require copying your package.json into your dist or publishing from dist.

You can structure your project as:

package.json (for entire project)
src
 | secondary-package-name
   |- index.ts
secondary-package-name
 |- package.json (for secondary-module-name)
dist
 |- generated files

the package.json for your secondary module just needs to contain

{
  "name": "package/secondary-package-name",
  "private": true,
  "main": "../dist/secondary-package-name/index.js"
}

to point back to your dist

You should then be able to reference exports from the secondary package like so:

import { someFn } from "package/secondary-package-name"

provided it is exported from the index.ts file in that directory

You'll also need to make sure the files field of your main package.json includes:

"files": [
    "dist",
    "secondary-package-name"
  ],

The vast majority of module bundling tools follow Node's module resolution rules, which effectively say that if you specify a path after a library name, it will resolve that relative to the module's node_modules folder. You can't override this, and it's almost certainly never going to change for backward compatibility reasons.

Without asking for your users to configure their module bundler, the only way this can be achieved is by publishing your package with the directory structure matching that which you wish to expose to your users. You could use scripts/NPM hooks (e.g. prepublish and postpublish) to automate this.


On suggestions of @joe-clay, I found a solution.

My new structure is the following:

dist
 |- Alls files generated after tsc build
 |- package.json
 |- LICENSE
 |- README.md
src
 |- All TS files of library (source)
CHANGELOG.md
LICENSE
README.md
tsconfig.json

The dist directory is published on NPM with README.md and LICENSE file for NPM package page.

The root directory is the entry point on Github with README.md, LICENSE and CHANGELOG.md for development process on Github.

tsconfig.json is placed on the root because I don't find a solution to have correct build if located inside dist directory.

In package.json, I add the script "build": "cd ../ && tsc" in order to be able to execute npm run build inside dist directory.

With this structure, library development and NPM publishing works fine.

And I can use this import from my application:

import {Component} from '<library name>/Component';

Thank you again.