What is the best way to organize my NPM package with separate directories for types and functions?

I am currently working on developing a custom NPM package that will serve as a repository for sharing types and functions across my project. Let's name this project wordle. Given the emphasis on types, it is worth noting that I am using TypeScript for this project. My goal is to be able to import these types and functions in the following manner:

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

I would appreciate it if someone could guide me on how I should structure this NPM package to achieve the desired organization. I have noticed that some developers use @ in their package names (e.g. @wordle-shared), so I am open to incorporating that naming convention if necessary.

Currently, my folder structure looks like this:

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

Answer №1

Have you considered utilizing npm workspaces for your project structure? This approach could help organize your packages in a way that aligns with your requirements, allowing each package to manage its dependencies and interact with others seamlessly.

// ./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

This configuration allows you to access wordle-shared's functionalities in wordle-project-a as needed. If you prefer segregating them into distinct src/ directories, consider setting up a path alias in tsconfig.json.

Answer №2

From what I know, in order for TypeScript to properly load your package, a build step is necessary because it expects to find d.ts files.

One alternative could be using git submodules to directly incorporate the library code into your project instead of deploying and installing it as a package. While I haven't personally tested this method or workspaces, I believe it would seamlessly integrate with TypeScript, eliminating the need to build while still keeping the library versioned.

Here is an example of setting up the package using 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

Afterwards, you can add the shared library as a dependency

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

Make sure to include this compiler option for TypeScript to recognize the types fields in the library's package.json

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Attempting to create a promise for a dropdown menu in React-Select

I am facing an issue here: type Person = { value: string; label: string; }; Furthermore, I have a promise-containing code block that fetches data from an API and transforms it into the appropriate array type for a React component. My intention is to r ...

The button fails to log any text to the developer console

Attempting to verify the functionality of my button by logging a message on the developer console. However, upon clicking the button, the text does not appear in the console. import { Component, EventEmitter, Input, Output } from '@angular/core'; ...

What is the best way to perform type checking for a basic generic function without resorting to using a cumbersome cast

Struggling with TypeScript and trying to understand a specific issue for the past few days. Here is a simplified version: type StrKeyStrVal = { [key: string]: string }; function setKeyVal<T extends StrKeyStrVal>(obj: T, key: keyof T, value: str ...

Storing multiple email addresses in an array using an HTML input element

I have a small React Bootstrap form where I am trying to save multiple email addresses entered by the user into an array. However, when I use onChange={()=> setEmails(e.target.value as any} it stores them in string format like this --> [email p ...

Is the parameter rejecting the use of orderBy for 'startTime'?

Hey there! I'm currently working on an AngularJS project in TypeScript that involves integrating Google API to fetch Google Calendar events. The syntax for making a call is specified in the documentation available at: https://developers.google.com/goo ...

Can a condition be incorporated in a gulpfile to execute a task depending on the size of a file?

Currently, I am utilizing gulp for image compression. However, my requirement is to only compress images exceeding 200kb in size. Can JavaScript be used to loop through a directory and selectively run the minification process on files larger than 200kb? ...

Encountering an issue when trying to generate a build in Angular 5

While attempting to create a build, I encountered the following error: 11 silly lifecycle [email protected]~start: Returned: code: 139 signal: null 11 silly lifecycle [email protected]~start: Returned: code: 139 signal: nul ...

Is there a way to create 32-bit binaries on a 64-bit system using npm?

Currently, I am in the process of creating an application that will be distributed using node-webkit. An issue I have encountered is that node-webkit only provides 32-bit binaries for Windows. Although my operating system is Windows 7 Ultimate 64-bit, npm ...

The post-installation script within the package.json file is a critical component

After transitioning my project from bower to yarn, I encountered the following code snippet: "postinstall": "node -e \"try { require('fs').symlinkSync(require('path').resolve('node_modules/@bower_components'), 'bowe ...

Should the package for icons in the library I'm constructing be categorized under dependencies or devDependencies?

As I embark on creating my inaugural React component library, I find myself incorporating the flowbite and react-icons libraries. Despite familiarizing myself with their distinctions, I'm uncertain about where exactly they should be placed. Are these ...

Leveraging node modules in the browser using browserify - Error: fileType is not recognized

I am currently attempting to utilize the file-type npm package directly in my browser. Despite my efforts, I have encountered an error when trying to run the example code: Uncaught ReferenceError: fileType is not defined (Example code can be found here: ...

Enhance Angular Forms: Style Readonly Fields in Grey and Validate Data Retrieval using Typescript

Is there a way to disable a form and make it greyed out, while still being able to access the values? 1/ Disabling controls with this.roleForm.controls['id'].disable() in Typescript does not allow me to retrieve the values of Id, Name, and Descr ...

"Encountering issues with Firebase deployment related to function-builder and handle-builder while working with TypeScript

I encountered 4 errors while executing firebase deploy with firebase cloud functions. The errors are originating from files that I didn't modify. node_modules/firebase-functions/lib/function-builder.d.ts:64:136 - error TS2707: Generic type 'Req ...

Converting language into class components using ngx-translate in Angular

Seeking to convert the information from a table into my typescript class. The data in the table is sourced from a JSON file within the /assets directory. Is there a method to accomplish this task? How can I categorize translation within a typescript class ...

Getting Session from Next-Auth in API Route: A Step-by-Step Guide

When printing my session from Next Auth in a component like this, I can easily see all of its data. const session = useSession(); // ... <p>{JSON.stringify(session)}</p> I am facing an issue where I need to access the content of the session i ...

Refresh Material-Ui's Selection Options

Is there a way to properly re-render the <option> </option> inside a Material UI select component? My goal is to transfer data from one object array to another using the Material UI select feature. {transferData.map(data => ( <option ...

Concealing the sidebar in React with the help of Ant Design

I want to create a sidebar that can be hidden by clicking an icon in the navigation bar without using classes. Although I may be approaching this incorrectly, I prefer to keep it simple. The error message I encountered is: (property) collapsed: boolean ...

The challenge of validating in Typescript and utilizing type inference

I am currently facing an issue with a function that resembles the one provided below (I have created a simplified example for discussion purposes): interface Variable { someMethod: () => void } const validateVariable(variable: Variable | undefined) { ...

Having trouble locating the TypeScript compiler in Visual Studio 2017?

In an attempt to develop an application in Visual Studio using TypeScript, I meticulously followed the instructions outlined here and proceeded to install the necessary TypeScript compiler for version 2.2 of the project via NPM. npm install typescript ...

Is it possible to use square brackets in conjunction with the "this" keyword to access a class property using an expression?

export class AppComponent implements OnInit { userSubmitted = false; accountSubmitted = false; userForm!: FormGroup; ngOnInit(): void {} onSubmit(type: string): void { this[type + 'Submitted'] = true; if(this[type + 'For ...