clem
clem

Reputation: 897

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

I'm trying to publish a typescript library on NPM but I can't to have a "good" path after publishing.

I follow several guide on this point but I'm not found a solution.

The problem: So, consider the following structure:

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

After publishing, for instance in an Angular application, I shall type:

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

My question: How can I configure project import to have from '<library name>/Component' instead from '<library name>/dist/Component' please?

Thank you

Upvotes: 37

Views: 12022

Answers (6)

Abdulkadir NURKALEM
Abdulkadir NURKALEM

Reputation: 749

To resolve this, add the following configuration to the package.json file:

"typesVersions": {
  "*": {
    "your_sub_package": [
      "dist/your_sub_package"
    ]
  }
}

Upvotes: -1

y_nk
y_nk

Reputation: 2275

I just found about this question. Sure enough 2018 is far away, but since then tools have evolved. I've been searching for the same clean structure, for which I have a proposed solution as a SO question (actively looking for criticism/feedbacks)

Creating a usable library on npm... with yarn workspaces

Basically the idea being very similar to @clem and @wilcoxmd answers, but backed with yarn workspaces for the automation of the "upper layer".

Upvotes: 0

clem
clem

Reputation: 897

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.

Upvotes: 6

wilcoxmd
wilcoxmd

Reputation: 139

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"
  ],

Upvotes: 9

Ben
Ben

Reputation: 979

This might be a little different than what you were looking for, but I think this is the more standard approach. Instead of trying to import from different directories in your module, just use a single main.ts file to gather everything up for export. Assuming that you have this main.ts file in your lib directory that re-exports everything, you can just configure the package.json to point to the generated JS.

Folder structure:

dist
 |- main.js
 |- main.d.ts
 |- all other generates files
lib
 |- main.ts
...

package.json:

{
    ...
    "main": "./dist/main.js",
    "types": "./dist/main.d.ts",
    ...
}

In this example, if you have the following in your main.ts:

export const testValue = 5;

You could import it in other code that depends on this library by using import { testValue } from '<library>';

Check out the typescript docs for more info about this.

Upvotes: 4

Joe Clay
Joe Clay

Reputation: 35837

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.

Upvotes: 3

Related Questions