Open lukasIO opened 2 years ago
Oh yeah, oops! I'll add this
Are people expecting this to follow/work with the "extends"
key?
Right now, I'm expecting to only support a tsconfig.json
file in the process.cwd()
root. Perhaps I'd listen in on tsc's -p/--project
flag, but that would only set the initial tsconfig.json
... I'm not particularly incline to resolve the closest tsconfig.json
per every file loaded β that would be a big perf hit.
If "extends"
is defined, it could point to another tsconfig file that has "paths"
defined within it. Would also have to follow "extends"
recursively until there aren't any more.
Perhaps we can use https://github.com/dominikg/tsconfck to resolve and parse the tsconfig? Itβs currently used in Vite and implements the TypeScript behaviour well. cc @dominikg
Thanks for tagging me. I should check if "paths" content is actually correctly handled when they are taken from an extended config. Usually relative pathlike values in tsconfig files are rebased to the file they are defined in, but with paths, it's a key/value pair and the value can actually be an array.
tsconfck does handle paths
the same way as typescript itself.
There are a couple of minor differences in tsconfck output, but they should not affect the results of esbuild
compilerOptions.baseUrl
is absolute instead of relative files
is omitted instead of showing a list of matching filesextends
is keptExample output of tsconfck and it's tsc equivalent in https://github.com/dominikg/tsconfck/tree/main/tests/fixtures/parse/valid/with_extends/paths
tsconfck parse import-foo.ts
{
"extends": "../tsconfig.base",
"compilerOptions": {
"types": [
"foo"
],
"strictNullChecks": true,
"baseUrl": "/home/dominikg/develop/tsconfck/tests/fixtures/parse/valid/with_extends/paths",
"paths": {
"$lib": [
"*",
"./lib"
],
"$src": [
"./src"
]
},
"noImplicitAny": true
},
"include": [
"../src/**/*",
"../lib/**/*"
],
"watchOptions": {
"watchFile": "useFsEvents",
"watchDirectory": "useFsEvents",
"fallbackPolling": "dynamicPriority"
},
"exclude": [
"../../**/foo/*"
]
}
tsc --showConfig
{
"compilerOptions": {
"types": [
"foo"
],
"strictNullChecks": true,
"noImplicitAny": true,
"baseUrl": "..",
"paths": {
"$lib": [
"*",
"./lib"
],
"$src": [
"./src"
]
}
},
"watchOptions": {
"watchFile": "usefsevents",
"watchDirectory": "usefsevents",
"fallbackPolling": "dynamicpriority"
},
"files": [
"./import-foo.ts",
"../lib/foo.ts"
],
"include": [
"../src/**/*",
"../lib/**/*"
],
"exclude": [
"../../**/foo/*"
]
}
Right now, I'm expecting to only support a
tsconfig.json
file in theprocess.cwd()
root.
This is not particularly useful when using shebangs in general as the tsconfig.json
would be in the path with the script not the path the script is being run from.
e.g. I'm currently using ts-node
at the moment with it's TS_NODE_PROJECT
env var, but having tsconfig
auto detected would be considerably more useful than having to deal with the awkward wrapper scripts I'm currently doing.
I'm not particularly incline to resolve the closest
tsconfig.json
per every file loaded β that would be a big perf hit.
Packages need to do this for their package.json
already so I'm not sure why this would be any more expensive for tsconfig.json
. Optionally you could make a requirement to link tsconfig.json
from the package.json
to hint that it is required.
What packages have to do and what tsm has to do/is doing are completely separate. Right now, tsm only looks at each file as it's loaded. At most it's checking fs existence during path resolution, but no extra/unnecessary file reads beyond the transformation step itself.
hey π , thank you for this super fast testing tool! I'm lacking the background knowledge to see a work around in the above conversation. Is there a work around or a solution for this? :)
No workaround. But implementing it with tsconfck would be just a couple of lines. the tsconfig needs to be set on esbuild transform call here https://github.com/lukeed/tsm/blob/73b8c77cf9f2cc8142522a685f0ffa46e6a75a52/src/loader.ts#L118, as tsconfigRaw iirc.
Thank you for your tip @dominikg! I'm struggling with it tough. Is this going into the right direction?
import { parse } from "tsconfck";
...
export const transformSource: Transform = async function ( source, context, xform) {
let options = await toOptions(context.url);
if (options == null) return xform(source, context, xform);
const {
tsconfigFile, // full path to found tsconfig
tsconfig, // tsconfig object including merged values from extended configs
extended, // separate unmerged results of all tsconfig files that contributed to tsconfig
solution, // solution result if tsconfig is part of a solution
referenced, // referenced tsconfig results if tsconfig is a solution
} = await parse(context.url);
// TODO: decode SAB/U8 correctly
esbuild = esbuild || await import('esbuild');
let result = await esbuild.transform(source.toString(), {
...options,
sourcefile: context.url,
format: context.format === "module" ? "esm" : "cjs",
tsconfigRaw: tsconfig,
});
return { source: result.code };
};
You don't need to define the unused constants and if there is a chance this code runs multiple times if sourcefile imports other files, using the cache feature of tsconfck might be a good idea.
Not 100% sure if this location is the best to do it or if it should be in toOptions, maybe @lukeed has a preference on that
NDNts monorepo is currently using @k-foss/ts-esnode but I found myself adding more and more monkeypatches to make it work with recent Node versions.
I'm looking to switch to tsm but the lack of paths
is the first blocker.
Are people expecting this to follow/work with the "extends" key?
My use case do not require this feature.
However, I hope I can customize which tsconfig.json
is loaded via TS_CONFIG_PATH
environment variable.
This would allow me to prepare a special tsconfig.json
that contains all the necessary paths
.
Is that ENV a known/standard variable? I was planning on doing a --tsm-tsconfig
flag and have that be it. Only left I have left to investigate is whether or not each file actually has to search for its closest tsconfig file.
TS_CONFIG_PATH
is not a standard.
It's just what @k-foss/ts-esnode uses to locate a tsconfig.json
file.
https://github.com/K-FOSS/TS-ESNode/pull/64
Having --tsm-tsconfig
flag is OK.
In my use case, I can provide an absolute path, so that there's no searching involved.
This will be a great edition to this package.
I do use extended tsconfig.json
as part of my monorepo to maintain consistency for source path alias.
As a workaround I have been using require hooks
from module-alias. This works with uvu command line -- uvu -r tsm -r module-alias/register tests
where my tests are using path alias.
However it does not work when I use it directly with node
-- node --loader tsm -r module-alias/register src/m1/a.ts
where a.ts
is using path-alias
.
Hopefully, I wont have to use module-alias
if support for path-alias
is baked in.
what is the status on this issue?
I'm currently using tsm to help migrate a codebase with some dumb issues (TL;DR mjs scripts in a repo that's stuck with "type": "commonjs"
due to the framework I'm using for the frontend and I regret not doing a monorepo) that currently prevent me from compiling stuff with tsc and cannot run anything without these path aliases working. Could this be implemented anytime soon?
Edit: just tested basePath as a workaround and that is also not currently supported but very related to this (I think the aliases even depend on it?)
I recently switched to tsx
for running TypeScript files like DB-migrations and other stuff
@ivanhofer I tried tsx and it can't seem to resolve the relative paths (mjs file importing from "../../../foobar/cache.ts"
) that tsm was able to understand after I rewrote all my path aliases.
It seems that easy and painless migration of mjs to typescript remains a myth. Not that I can fault tsm and tsx entirely for that, the esm support of typescript is incomplete and confusing (I've had tsc tell me to rename my file to cache.mts
and then complain that I cannot import from a *.mts
file as that's an "unsupported file extension" even after I had added "**/*.mts"
to the include array in my tsconfig).
tsx
uses another ENV variable to customise tsconfig name. They do not however resolve it per file, but rather only one time.
https://github.com/esbuild-kit/esm-loader/blob/develop/src/utils.ts#L12
Any update on this issue?
Hi,
in my tsconfig file i have paths set up like this
If I import a module for testing (using loadr, tsm and uvu) the resolution fails as soon as the module/file that I import has a reference to
$lib
with the following error:Error [ERR_MODULE_NOT_FOUND]: Cannot find package '$lib' imported from /path/to/lib/utils.ts