Ts-node: Problems with pnpm due to removal of realpath function

Created on 26 Aug 2019  Â·  6Comments  Â·  Source: TypeStrong/ts-node

Issue https://github.com/TypeStrong/ts-node/issues/797 was resolved in commit https://github.com/TypeStrong/ts-node/commit/9691206def28405d4e53c5a7753f96d15be46e79 by removing the realpath option from the host service parameter for the TypeScript language server. However, this breaking change is not compatible with the package manager pnpm, which makes extensive use of symlinks in node_modules.

This is a simple example to reproduce this problem:

pnpm init -y
pnpm install --save ts-node typescript stellar-sdk @types/node 

Then create a file index.ts with the content:

import * as stellar from "stellar-sdk";
console.log(stellar.Network);

The TypeScript compiler will run without any problems, i.e., executing the following command will finish successfully:

./node_modules/.bin/tsc index.ts --noEmit

However, when running

./node_modules/.bin/ts-node index.ts

then this will yield the error message:

TSError: ⨯ Unable to compile TypeScript:


2 console.log(stellar.Network);
                      ~~~~~~~

Reason

The package stellar-sdk has another dependency stellar-base. The class Network is defined in stellar-base and re-exported by stellar-sdk. pnpm will structure node_modules as follows (arrows indicate symlinks):

 |
 +-- stellar-sdk -> .registry.npmjs.org/stellar-sdk/2.3.0/node_modules/stellar-sdk
 |
 +-- .registry.npmjs.org
     |
     +-- stellar-sdk/2.3.0/node_modules
     |   |
     |   +-- stellar-base -> ../../../stellar-base/1.1.2/node_modules/stellar-base
     |   |
     |   +-- stellar-sdk (actual package content)
     |
     +-- stellar-base/1.1.2/node_modules
         |
         +-- stellar-base (actual package content)

When running ts-node the TypeScript language server is not able to load stellar-base as symlinks are not correctly resolved: TypeScript will first resolve the module name stellar-sdk found in index.ts to <project>/node_modules/stellar-sdk/lib/index.d.ts but then is unable to resolve the real path of this file (see here and here). When reading <project>/node_modules/stellar-sdk/lib/index.d.ts, it finds a reference to stellar-base and tries to resolve it but the module resolution algorithm will not be able to find a package stellar-base inside a node_modules folder that is a parent (or grandparent) directory of <project>/node_modules/stellar-sdk/lib/index.d.ts.

Observe that stellar-base can be found if <project>/node_modules/stellar-sdk/lib/index.d.ts is correctly resolved to <project>/node_modules/.registry.npmjs.org/stellar-sdk/2.3.0/node_modules/stellar-sdk/lib

Most helpful comment

I run into similar issues with @types/express - which reexports @types/express-serve-static-core...

All 6 comments

I run into similar issues with @types/express - which reexports @types/express-serve-static-core...

I can confirm the same issue that @grogi is seeing. A quick fix is to have the package directly depend on @types/express-serve-static-core.

@abalmos This is resolved on master (changing it was a breaking change pending 9.x). Would you like to try it and let me know if it works for you?

@blakeembrey I tried master and now get a new error:

TypeError: Unable to compile file from external library: ../../packages/oada-config/src/index.ts

However, that path is in my pnpm workspace and ts-node 8.x handles it correctly.

As a side note, pnpm add TypeScript/ts-node fails with errors about missing mocha types.

That’s the reason 9.x hasn’t been released, I haven’t seen any way in the typescript compiler to support project references automatically although there’s some work on it in TS loader. 8.x works (accidentally) on that front because it’s using the language services directly.

I can confirm the same issue that @grogi is seeing. A quick fix is to have the package directly depend on @types/express-serve-static-core.

~Another workaround that worked for me is having typescript as a dependency. You can do away with @types/express-serve-static-core in that case.~

It was a false positive but worked somehow.

You could use a hook instead of adding @types/express-serve-static-core to your package.json.

Your pnpmfile.js would look like this:

"use strict";
module.exports = {
    hooks: { readPackage }
};

function readPackage(pkg) {
    if (pkg.name === "nameOfYourPackage") {
        pkg.devDependencies = {
            ...pkg.devDependencies,
            "@types/express-serve-static-core": "*"
        };
    }

    return pkg;
}

and then do a pnpm i. It will detect the pnpmfile.js and add the dependency to the pnpm-lock.yaml file.

It's a much nicer approach and doesn't clutter your package.json with unecessary dev dependencies.

Was this page helpful?
0 / 5 - 0 ratings