Directly mapping packages to Typescript source code in the package.json files of a monorepo

How can I properly configure the package.json file in an npm monorepo to ensure that locally referenced packages resolve directly to their .ts files for IDE and build tooling compatibility (such as vscode, tsx, ts-node, vite, jest, tsc, etc.)?

I want to avoid local Typescript tasks (such as bundling, ts-jest testing, debugging) resolving to transpiled .js files in the dist folder or the .d.ts artifacts. These files may be out of date if the author forgets to rebuild after editing .ts files in src, or doesn't have a watch procedure in place. Ideally, these tasks should resolve directly to the original .ts files.

To better understand how to achieve this, I have created a sample monorepo at this link, focusing on how to point to Typescript source files within an npm-compatible package.json (not pnpm). You can view the example package.json for "@starter/multiply" and "@starter/sum" from the same repo to see how local resolutions work in various tools.

In the past, I relied on pnpm's tooling, which allows the "main" field of package.json to be overridden during publishing. The "main" field was set to "src/index.ts" during development and changed to "dist/index.cjs" later in the release process.

However, I am now exploring ways to achieve similar results with npm, as it does not support overriding the main field through publishConfig. I am unsure if there is a npm postpack step where I could script changes to the tar to set "main" permanently to "src/index.ts" locally and switch to .js before publishing.

The reference npm monorepo I provided has functioning tests, cached build tasks, and sourcemapping for debugging. However, the loaded source is not the .ts files even within the monorepo. Instead, main resolves to src/index.mjs, which imports from dist/index.js with sourcemapping back to src/index.ts. This leads to issues when the background build isn't rerun, resulting in outdated .js files.

I have raised a related ticket at https://github.com/microsoft/TypeScript/issues/51750 to suggest a solution, but I am curious if there are conventional approaches or tricks that others are using.

Answer №1

After reviewing the changes made in this commit, it appears that the configuration now meets the necessary requirements.

The package.json file contains correct references to transpiled source files (such as ./dist/index.cjs and ./dist/index.mjs) for npm publishing, with no mention of index.ts.

Upon navigating to packages/multiply, the expected outcome is achieved. It seems that tsc successfully recognizes the package's src/index.ts (located next to src/index.mjs). This suggests that any tool using tsc should be able to do the same.

packages/multiply]$ npx tsc --traceResolution | grep '@starter/sum' | more
======== Resolving module '@starter/sum' from '/home/cefn/Documents/github/starter/packages/multiply/src/index.ts'. ========
======== Module name '@starter/sum' was successfully resolved to '/home/cefn/Documents/github/starter/packages/sum/src/index.ts'. ========

This success can likely be attributed to the top-level shared tsconfig.json's paths resolution at this location. However, there may still be exceptions or issues if tools like esbuild or jest do not adhere to this resolution and opt for node's package.json resolutions instead.

Although promising, I will refrain from marking this as the definitive answer just yet. There could be valuable insights and potential challenges shared by others regarding exceptions and possible problems.

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

const error = new TypeError(`${calculateRelativePath(cwd, fileName)}: Skipping emission of file`);

Hey there! I have a typescript code snippet that looks like this: import { getConnection } from "typeorm"; import { GraphQLClient } from "graphql-request"; import got from "got"; import database from "./utils/database&quo ...

Creating a null array of a specific size can easily be accomplished in Typescript

When I use the splice method to add elements to an array at a specified index, I find myself creating a null array first in order to achieve this. If I use an empty array instead, the elements do not get pushed to the specific instance that I intended. Cur ...

What is the best way to set up webpack to exclude a non-existent asset in my scss files?

I am encountering an issue while compiling my scss file. Within the .scss file, I have the following code: body { background-image: url("/static/background.webp"); } The error message I'm seeing is as follows: error in . ...

Invoke index functions within a component

I have a widget/component written in Angular 4 within the index.html file. Before and after this angular app, there are various HTML elements due to the nature of it being an additional component for the website. The head section of the index file include ...

Group data by two fields with distinct values in MongoDB

I have developed a Typescript Node.js application and I am looking to organize documents by two fields, "one_id" and "two_id", based on a specific "one_id" value. Below is the data within my collection: { "_id":"5a8b2953007a1922f00124fd", "one_id ...

Typescript: Implementing a generic function with the flexibility of an optional parameter

Having some difficulty writing a generic function with an optional parameter type Action<TParameters = undefined> = (parameters: TParameters) => void const A: Action = () => console.log('Hi :)') // This works as expected const B: ...

Difficulties with managing button events in a Vue project

Just getting started with Vue and I'm trying to set up a simple callback function for button clicks. The callback is working, but the name of the button that was clicked keeps showing as "undefined." Here's my HTML code: <button class="w ...

Create a conditional statement based on the properties of an object

In one of my Typescript projects, I am faced with the task of constructing a dynamic 'if' statement based on the data received from an object. The number of conditions in this 'if' statement should match the number of properties present ...

The implementation of the new package is causing a disruption in my project

I've encountered an issue while trying to integrate bcryptjs into my application. Although I successfully installed it, the development environment crashes upon startup. The project is currently built on angular v6, and after running npm install to do ...

Adding TypeScript definition file to an npm package: A step-by-step guide

Is it possible to include typescript definitions (.d.ts files) in a pure javascript project without using TypeScript itself? I'm struggling to find any information on how to do this directly in the package.json. ...

What could be causing the global npm package to not be utilized for module dependencies?

My typescript and ts-node are already installed globally. In my package.json file, I have the necessary configurations to run tests with npm test. Everything works fine since ts-node and typescript are installed as local modules. { "name": "two_sum", ...

The absence of the NPM fs module in Laravel 5.4 combined with Laravel Mix

It recently dawned on me that Laravel 5.4 does not come with the fs module, which I happen to need. I require this module for file reading purposes. However, it appears that https://www.npmjs.com/package/fs is now deprecated? Is there a workaround to ins ...

Encountering difficulties installing npm, react, and node.js on Mac's terminal

I am having trouble running npm install on my Mac terminal and VSTS code. Below are the commands I am trying to run: npm install -g vsts-npm-auth --registry false vsts-npm-auth -config .npmrc An error is occurring here. I am encountering a format erro ...

Navigating through async functions in an Express.js router

Encountered a lint error indicating that Promises cannot be returned in places where a void is expected. Both functions [validateJWT, getUser] are async functions. Any suggestions on how to resolve this issue without compromising the linter guidelines by u ...

Utilize the power of relative import by including the complete filename

When working on my TypeScript project, I have noticed that to import ./foo/index.ts, there are four different ways to do it: import Foo from './foo' // ❌ import Foo from './foo/index' // ❌ import Foo from './foo/i ...

When the next() function of bcrypt.hash() is called, it does not activate the save method in mongoose

Attempting to hash a password using the .pre() hook: import * as bcrypt from 'bcrypt'; // "bcrypt": "^1.0.2" (<any>mongoose).Promise = require('bluebird'); const user_schema = new Schema({ email: { type: String, required: tru ...

React with TypeScript presents an unusual "Unexpected token parsing error"

Recently, I encountered an issue with my helper function that was originally written in JavaScript and was functioning perfectly. However, as soon as I introduced TypeScript into the mix, strange behaviors started to surface. Here is the snippet of code fr ...

What are the best scenarios for creating a constructor in Angular 2 using Typescript?

Check out these sample constructors I found in the Angular 2 documentation: export class AppComponent implements OnInit { title = 'Tour of heroes'; heroes: Hero[]; selectedHero: Hero; constructor(private heroService: HeroService ...

Eliminate the need for 'any' in TypeScript code by utilizing generics and partials to bind two parameters

I'm working with TypeScript and have the following code snippet: type SportJournal = { type: 'S', sport: boolean, id: string} type ArtJournal = { type: 'A', art: boolean, id: string} type Journal = SportJournal | ArtJournal; type J ...

How can you make sure that VS Code always utilizes relative paths for auto imports in TypeScript?

VS Code has been automatically importing everything using Node-like non-relative paths relative to baseUrl, which is not the desired behavior. Is there a way to instruct VS Code to import everything with relative paths, excluding Node modules? Removing t ...