Home > other >  How do I structure my NPM package to contain subfolders for types and functions?
How do I structure my NPM package to contain subfolders for types and functions?

Time:01-27

I am trying to create a NPM package that can be used locally to share types and functions in the rest of my project. Let's call my project wordle. As you could probably tell by the mention of types, this is a TypeScript project. Ideally I want to be able to import types and functions in the following way:

import { Move } from "wordle-shared/types";
import { getValidWords } from "wordle-shared/utils"

Can someone explain how I would need to structure this NPM package to achieve the desired structure? I've seen people use @ in their package name (e.g. @wordle-shared), if this is required, that is fine.

So far I have the following folder structure

wordle-shared
├── src
│   ├── types
│   └── utils
├── package.json
├── tsconfig.json
├── .gitignore

CodePudding user response:

Can't comment yet, but have you tried npm workspaces? It would result in a structure similar to what you described. Each package manages their own dependencies and can import from eachother.

// ./wordle/package.json
{
    "name": "wordle",
    "workspaces": [
        "wordle-shared",
        "wordle-project-a",
    ]
}
.
├── node_modules
│   ├── .package-lock.json
│   ├── wordle-project-a -> ../wordle-project-a
│   └── wordle-shared -> ../wordle-shared
├── package.json
├── package-lock.json
├── wordle-project-a
│   ├── package.json
│   └── src
│       └── index.ts
└── wordle-shared
    ├── package.json
    ├── types
    │   └── index.ts
    └── util
        └── index.ts

With this setup, you can use wordle-shared's exports in wordle-project-a as you described. If you insist on keeping them in a separate src/ directory, you can set up a path alias in tsconfig.json.

CodePudding user response:

To my knowledge, there needs to be a build step for TS to load your package correctly, because it will be looking for d.ts files.

You could maybe use git submodules to inject the library code directly in your project instead of deploying it and installing it as a package. I never tried it, nor did I try workspaces, but I think it would be transparent to TS, then you would not have to build and the library would still be versioned.

Here is one way to do it as a package with tsc:

wordle-shared
├── src
│   ├── types.ts
│   └── utils.ts
├── dist
│   ├── types.d.ts
│   └── utils.js
│   └── utils.d.ts
├── package.json
├── tsconfig.json
├── .gitignore
// wordle-shared package.json
{
    "type": "module",
    "version": "1.0.0",
    "exports": {
        "./utils": {
            "import": "./dist/utils.js",
            "types": "./dist/utils.d.ts"
        }, "./types": {
            "types": "./dist/types.d.ts"
        }
    }
}
// wordle-shared tsconfing.json
{
    "compilerOptions": {
        "outDir": "./dist",
    },
    "include": ["src"],
}
// .gitignore
node_modules
dist

Then you can add the shared library as a dependency

// wordle package.json
{
  "dependencies": {
    "wordle-shared": "^1.0.0",
  }
}

You will need this compiler option for TS to detect the types fields in the library package.json

// wordle tsconfing.json
{
    "compilerOptions": {
        "moduleResolution": "nodenext"
    },
}
  • Related