Incorrect mapping resolution: an absolute to a relative path without the baseUrl parameter
Minimal repo to reproduce this issue
Project Structure
/
└── project
├── custom
│ └── index.ts
├── main.ts
├── package.json // `rollup --config` as `build` script
├── tsconfig.json
└── rollup.config.js
Code Snippets
// ./custom/index.ts
export default function() { return 'hello world' }
// ./main.ts
export { default as func } from 'custom'
// ./tsconfig.json
{
"compilerOptions": {
// "baseUrl": "./", // [1]
"paths": { "custom": [ "./custom/index.ts" ] }
}
}
// ./rollup.config.js
export default {
input: './main.ts',
output: { dir: './dist' },
plugins: [
typescriptPaths({
// absolute: false, // [2]
preserveExtensions: true,
}),
esbuild(),
],
}
Error Messages
❎ ~[1] [2]~
[!] Error: Could not load
/project/project/custom/index.ts(imported by main.ts):
- ENOENT: no such file or directory, open
'project/project/custom/index.ts'
Explanation: Duplicated project root
❎ ~[1]~ [2] absolute: false in plugin configuration
[!] Error: Could not load
project/custom/index.ts(imported by main.ts):
- ENOENT: no such file or directory, open
'project/custom/index.ts'
Explanation: Missing leading slash
✅ [1] ~[2]~ "baseUrl": "./" in typescirpt configuration
No erros, output file:
// ./dist/main.js
function index() { return "hello world"; }
export { index as func };
I was under the assumption that baseUrl is required to use paths but seems like that changed at some point after this plugin was published, see https://github.com/microsoft/TypeScript/issues/31869.
I haven't worked on this for a while, do you happen to have a suggestion for a fix?
I've tried making some changes. Ignore the orphan commits that reference this discussion, it's all my sloppiness.
I updated the test configuration to support this case with the least changes, but in general, I was surprised that the plugin code is so convoluted and tested with just node's assert, which provide terrible DX.
For example, it seems to me that at least the tests don't cover the case where the configuration in a submodule references files relative to its own location. In the case of this plugin's code, it's as if we changed the first path-alias to:
"@foobar": ["./foo/bar"]in the case of missingbaseUrlor to"@foobar": ["foo/bar"]in the case of"baseUrl": "."
Compare with:
"@foobar": ["./test/foo/bar"]or"@foobar": ["foo/bar"]with"baseUrl": "test",
...which only works if you run the test with the node test command.
In my case, I ran into this issue for a monorepo that starts a build by referencing scripts from package.json each subrepo have with npm workspaces, yarn2 workspaces, or pnpm workspaces with the pnpm --recursive run build command.
The subrepo's build scripts runs tsc for each subrepo from within, which resolves abbreviations from its configuration relative to its own location in the subrepo as well. In this case, ./test/foo/bar will not work correctly, and ./foo/bar will work normally.
I understand that this sounds confusing, and you probably won't have the time to organize tests for it. I don't have enough time to help with this either.
Furthermore, I have written this to provide clarity to myself and others if they encounter a similar issue. You should skip this reasoning, and you can close the problem, since everything is already working well for me. Thanks for the plugin.
I added the monorepo example to a separate branch. It uses the npm workspaces model mentioned in previous comments.
You can see two new scripts in the root package.json
test:mono- runs correctlytest:mono-error- runs with an error, for the reasons described above
main.ts:1:21 - error TS2307: Cannot find module '@foobar' or its corresponding type declarations. 1 export { foo } from '@foobar'
I mean, that passing "syntetic" tests from ./test/index.js doesn't guarantee a successful compilation against tsc.
These are not full-fledged integration tests, at the same time there are no tests of separate functions like getTsConfig, escapeRegex.
All this makes it difficult to add reliable support for new features, such as a missing baseUrl. And the lack of tests of individual functions makes it difficult to understand how the plugin's code works (tests as documentation).
I was surprised that the plugin code is so convoluted
Not sure what you mean, the actual implementation is less than 60 lines of code? 🤷🏻♂️
tested with just node's
assert, which provide terrible DX
At the time I wrote a few tests just for myself so assert was sufficient. Could rewrite it with the new Node.js test runner but I don't have the motivation for it currently.
the tests don't cover the case where the configuration in a submodule references files relative to its own location
Yeah, I'm not even sure what you mean by "configuration in a submodule" 😅
Thanks for the PR, will have a look when I find some time.