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

Issue with Next.js: Router.push not causing page to refresh

I'm currently developing a next.js page called /page/data/[dataId] (this page is accessed when a user clicks on a link from the page /page/data, where I fetch the list of items through an API). When a user clicks on a button, I make an API call to de ...

Encountering a strange log and receiving errno -2 while trying to npm install

While attempting to install pm2 using the "npm install -g" command, I encountered an unusual error. The "-g" option seems to be mistakenly attached to the present working directory, resulting in an ENOENT (no such file or directory) issue. Has anyone els ...

Tackling the challenge of merging PDF files and designing a Table of Contents feature reminiscent of Acrobat in Node.js and JavaScript

I am currently implementing the following code snippet: const pdfmerger = require('pdfmerger') var pdfStream = pdfmerger(array_of_pdf_paths) var writeStream = fs.createWriteStream(final_pdf_path) pdfStream.pipe(writeStream) pdfmerger(array_of_pd ...

Error encountered in MDAVSCLI: EPERM, operation not allowed on 'C:WindowsCSCv2.0.6'

After successfully installing VS tools for Cordova on VS2013 with all default settings, I encountered a node error while attempting to build and run the default "BlankCordovaApp" template. 1>MDAVSCLI : error : EPERM, operation not permitted 'C:&b ...

Tips for resolving Electron npm audit fix errors?

This particular inquiry stems from a discussion on Why do renderer fs.existsSync, fs.readfileSync (declared in preload.js) return 'undefined'?, where the issue of method '.toString('base64')' failing due to prototype pollution ...

Having issues with installing serialport using npm

Encountering warnings while attempting to install serialport: sudo npm install serialport --save npm WARN EPACKAGEJSON <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e6879482938f8889a6d7c8d6c8d6">[email protected]< ...

What are the drawbacks of relying on a dependent dependency in software development?

In a recent discussion on Stack Overflow, it was suggested that the best practice is to install packages from sub-dependencies for future use in the app, rather than directly from the dependencies node_modules folder. However, my scenario is a bit unique. ...

Iterating through an array with ngFor to display each item based on its index

I'm working with an ngFor loop that iterates through a list of objects known as configs and displays data for each object. In addition to the configs list, I have an array in my TypeScript file that I want to include in the display. This array always ...

What is TS's method of interpreting the intersection between types that have the same named function properties but different signatures (resulting in an error when done

When working with types in Typescript, I encountered an interesting scenario. Suppose we have a type A with two properties that are functions. Now, if we define a type B as the intersection of type A with another type that has the same function properties ...

Error TS2339: The 'selectpicker' property is not found on the 'JQuery<HTMLElement>' type

Recently, I integrated the amazing bootstrap-select Successfully imported bootstrap-select into my project with the following: <!-- Latest compiled and minified CSS --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstra ...

The type 'string | undefined' cannot be assigned to type 'string'

I am facing a challenge in comparing two arrays, where one array is sourced from a third-party AWS service and its existence cannot be guaranteed. Despite my efforts to handle potential errors by incorporating return statements in my function calls, I con ...

What is the best way to pass props to a styled component (e.g., Button) in Material-UI

One of my tasks involves creating a customized button by utilizing the Button component with styled components. export const CustomButton = styled(Button)({ borderRadius: "17px", fontWeight: 300, fontSize: ".8125rem", height: &q ...

Comparing Yeoman's Angular generator to using Grunt `serve` and `http

After creating an Angular project using Yeoman, I ran grunt serve and everything looked great. However, when I tried viewing the project by running http-server, the page displayed without any formatting or images. Do you have any idea why this happened? ...

Incorporate a visual element into an Angular Library Component Template using an image asset

Currently, I am working with Angular 10 and aiming to develop a component library that includes images and stylesheets. My main goal is to be able to access these images from the component templates defined in the HTML template. Although I have limited ex ...

Setting up TypeScript to function with Webpack's resolve.modules

Imagine having a webpack configuration that looks like this: resolve: { extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'], modules: ['my_modules', 'node_modules'], }, You have a ...

Angular8: Adjusting Activity Status After Leaving Page

When performing activities like upload, download, delete, and edit, I display statuses such as 'upload started' or 'upload completed'. This works perfectly when staying on the same page. However, there are instances where a user may nav ...

Changes on services do not affect the Angular component

Currently facing an issue with my Angular assignment where changing an element's value doesn't reflect in the browser, even though the change is logged in the console. The task involves toggling the status of a member from active to inactive and ...

Error occurred during the file watch process in PhpStorm after saving the CSSO file

Following the advice in the official PhpStorm documentation, I have implemented a CSS minifier. However, upon attempting to use it, I encountered the following error: cmd.exe /D /C call C:\Users\douglas\AppData\Roaming\npm\css ...

Guide on sending JSON object to Angular custom components

I have implemented a custom element in Angular 7 using the CUSTOM_ELEMENTS_SCHEMA. My app.module.ts code is as follows: export class AppModule { constructor(private injector: Injector) {} ngDoBootstrap() { this.registerCustomElements( ...

Utilize a function to wrap the setup and teardown code in Jest

I am attempting to streamline some common setup and teardown code within a function as shown below: export function testWithModalLifecycle() { beforeEach(() => { const modalRootDom = document.createElement('div') modalRootDom.id = M ...