Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apply rootDir/outDir when resolving imports #603

Open
4 of 6 tasks
JavaScriptBach opened this issue Jun 27, 2024 · 3 comments
Open
4 of 6 tasks

Apply rootDir/outDir when resolving imports #603

JavaScriptBach opened this issue Jun 27, 2024 · 3 comments
Labels
bug Something isn't working pending triage

Comments

@JavaScriptBach
Copy link

Acknowledgements

  • I read the documentation and searched existing issues to avoid duplicates
  • I understand this is a bug tracker and anything other than a proven bug will be closed
  • I understand this is a free project and relies on community contributions
  • I read and understood the Contribution guide

Minimal reproduction URL

https://github.com/JavaScriptBach/ts-repo-structure

Problem & expected behavior (under 200 words)

The Problem

I have a Typescript monorepo with source files in <package>/src/*.ts and js files outputted to <package>/dist/*.js. Each package also uses imports and exports in the package.json to control entry points and allow for bare imports. A small repro is linked below.

This configuration works perfectly in Typescript and Node, but not in tsx.

  • Typescript's language server in VSCode is able to evaluate these imports, highlight suggestions, link correctly to references etc even before anything is compiled
  • Typescript is able to compile the code
  • Node.js is able to run the compiled code
  • However, tsx is NOT able to run this code before it's compiled.

I think the key missing section is here. It looks like we did some extension remapping in #59, but I think we also need handle rootDir and outDir to have full parity with Typescript.

If the package.json is part of the local project, an additional remapping step is performed in order to find the input TypeScript implementation file that will eventually produce the output JavaScript or declaration file path that was resolved from "imports". Without this step, any compilation that resolves an "imports" path would be referencing output files from the previous compilation instead of other input files that are intended to be included in the current compilation. This remapping uses the outDir/declarationDir and rootDir from the tsconfig.json, so using "imports" usually requires an explicit rootDir to be set.

Repro

  1. Check out https://github.com/JavaScriptBach/ts-repo-structure and run yarn
  2. Run npx tsx a/src/a.ts
node:internal/modules/cjs/loader:1068
  const err = new Error(`Cannot find module '${request}'`);
              ^

Error: Cannot find module '/Users/philliphuang/ts-repo-structure/node_modules/b/dist/a.js'
    at createEsmNotFoundErr (node:internal/modules/cjs/loader:1068:15)
    at finalizeEsmResolution (node:internal/modules/cjs/loader:1061:15)
    at resolveExports (node:internal/modules/cjs/loader:538:14)
    at Module._findPath (node:internal/modules/cjs/loader:607:31)
    at Module._resolveFilename (node:internal/modules/cjs/loader:1033:27)
    at resolve (/Users/philliphuang/ts-repo-structure/node_modules/tsx/dist/register-BujtrvNV.cjs:1:3084)
    at resolveRequest (/Users/philliphuang/ts-repo-structure/node_modules/tsx/dist/register-BujtrvNV.cjs:1:2618)
    at Function._resolveFilename (/Users/philliphuang/ts-repo-structure/node_modules/tsx/dist/register-BujtrvNV.cjs:1:3400)
    at Module._load (node:internal/modules/cjs/loader:893:27)
    at Module.require (node:internal/modules/cjs/loader:1113:19) {
  code: 'MODULE_NOT_FOUND',
  path: '/Users/philliphuang/ts-repo-structure/node_modules/b/package.json'
}

Bugs are expected to be fixed by those affected by it

  • I'm interested in working on this issue

Compensating engineering work will speed up resolution and support the project

  • I'm willing to offer $10 for financial support
@privatenumber
Copy link
Owner

When I run tsc --noEmit in your repro, TypeScript emits these errors:

a/src/a.ts:2:17 - error TS2307: Cannot find module 'b/a' or its corresponding type declarations.

2 import foo from "b/a";
                  ~~~~~

a/src/a.ts:3:17 - error TS2307: Cannot find module 'b/c' or its corresponding type declarations.

3 import bar from "b/c";
                  ~~~~~

a/src/a.ts:5:29 - error TS2307: Cannot find module 'a/b' or its corresponding type declarations.

5 import myLocalFunction from "a/b";
                              ~~~~~

a/src/a.ts:6:55 - error TS2307: Cannot find module '#a/c' or its corresponding type declarations.

6 import { myPrivateFunction, myPrivateFunction2 } from "#a/c";
                                                        ~~~~~~


Found 4 errors in the same file, starting at: a/src/a.ts:2

With --traceResolution:

======== Resolving module 'b/a' from '~/Desktop/ts-repo-structure/a/src/a.ts'. ========
Module resolution kind is not specified, using 'Node16'.
Resolving in CJS mode with conditions 'require', 'types', 'node'.
File '~/Desktop/ts-repo-structure/a/src/package.json' does not exist according to earlier cached lookups.
File '~/Desktop/ts-repo-structure/a/package.json' exists according to earlier cached lookups.
Loading module 'b/a' from 'node_modules' folder, target file types: TypeScript, JavaScript, Declaration, JSON.
Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration.
Directory '~/Desktop/ts-repo-structure/a/src/node_modules' does not exist, skipping all lookups in it.
Directory '~/Desktop/ts-repo-structure/a/node_modules' does not exist, skipping all lookups in it.
Found 'package.json' at '~/Desktop/ts-repo-structure/node_modules/b/package.json'.
Using 'exports' subpath './*' with target './dist/a.js'.
File name '~/Desktop/ts-repo-structure/node_modules/b/dist/a.js' has a '.js' extension - stripping it.
Export specifier './a' does not exist in package.json scope at path '~/Desktop/ts-repo-structure/node_modules/b'.
Directory '~/Desktop/ts-repo-structure/node_modules/@types' does not exist, skipping all lookups in it.
Directory '~/Desktop/node_modules' does not exist, skipping all lookups in it.
Directory '~/node_modules' does not exist, skipping all lookups in it.
Directory '/Users/node_modules' does not exist, skipping all lookups in it.
Directory '/node_modules' does not exist, skipping all lookups in it.
Searching all ancestor node_modules directories for fallback extensions: JavaScript, JSON.
Directory '~/Desktop/ts-repo-structure/a/src/node_modules' does not exist, skipping all lookups in it.
Directory '~/Desktop/ts-repo-structure/a/node_modules' does not exist, skipping all lookups in it.
File '~/Desktop/ts-repo-structure/node_modules/b/package.json' exists according to earlier cached lookups.
Using 'exports' subpath './*' with target './dist/a.js'.
File name '~/Desktop/ts-repo-structure/node_modules/b/dist/a.js' has a '.js' extension - stripping it.
Export specifier './a' does not exist in package.json scope at path '~/Desktop/ts-repo-structure/node_modules/b'.
Directory '~/Desktop/node_modules' does not exist, skipping all lookups in it.
Directory '~/node_modules' does not exist, skipping all lookups in it.
Directory '/Users/node_modules' does not exist, skipping all lookups in it.
Directory '/node_modules' does not exist, skipping all lookups in it.
======== Module name 'b/a' was not resolved. ========

Am I missing something?

@gaastonsr
Copy link

gaastonsr commented Aug 29, 2024

If I understand the repro correctly, it doesn't make sense to compile the files at the root level, since it's a monorepo and each workspace inside should be compiled independently since they are independent projects in the same repo.

In this case before you compile (or type check) the files in the workspace a you need to compile first the workspace b because the tsconfig.json of a says that it should only include src/**/*.ts in the compilation and it should treat b as an external dependency.

Leaving aside the compilation process, it's important to note that when #a/c is imported Typescript can locate the file without issues even though in the package.json file it's pointing to the dist directory.

@JavaScriptBach
Copy link
Author

Yes, what @gaastonsr said is correct. In this example a is a workspace that depends on b. It is set up using project references so when a is compiled using tsc -b, the workspaces will get built in the right order.

If you open this project in an IDE (e.g. VSCode with the Typescript extension), all the language servers work and the resulting compiled code also runs in Node.js. The ask here is that tsx also learns how to run code written with this setup as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working pending triage
Projects
None yet
Development

No branches or pull requests

3 participants