8000 feat(core): improved configuration loaders by octet-stream · Pull Request #6333 · mikro-orm/mikro-orm · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

feat(core): improved configuration loaders #6333

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

Draft
wants to merge 19 commits into
base: master
Choose a base branch
from

Conversation

octet-stream
Copy link
Contributor
@octet-stream octet-stream commented Jan 12, 2025

Details

This PR implements improves configuration loading with support for new transpilers, like jiti and tsx. It also includes documentation updates, reflecting these changes. This PR also deprecates some of the old CLI settings: useTsNode, preferTs, and alwaysAllowTs in favor of a single new option called loader, and this new option allows to opt-in to a specific transpiler, or use auto-detection (the default), or opt-out to runtime's native import() (when set to either false or native).

Notable changes

  • Implement new loaders: ts-node, jiti, tsx, and native;
  • Add new type-safe ESM utilities:
    • tryModule - it resolves a promise, returned by import() and catches the errors with the ERR_MODULE_NOT_FOUND code, then wraps it into a TryModuleError, so it can be handled later. Unlike existent utilities (Utils.dynamicImport and Utils.tryRequire), the resulting value has correct types (though it only supports the import() - it can be easily modified to support require() function as well);
    • requireDefault - resolves the default member from a module's exports while also providing correct types;
  • Add in-code documentation for CLI Settings interface;
  • Deprecate useTsNode, preferTs, and alwaysAllowTs in favor of loaders;
  • Integrate loaders into ConfigurationLoader class;
  • Add tests for loaders and ConfigurationLoader integration:
    • Add tests for loader option and environment variable;
    • Add tests for ConfigurationLoader.getConfiguration method;
  • Update documentation to reflect the changes;

I also updated git hooks to use local binaries of lint-staged and commitlint, because there's no point to have those installed globally (yarn can pick up both local and global installations), nor to assume everyone has these by default.

* Add new configuration loaders utilities;
* Support new transpilers: jiti and tsx;
* Add in-code documentation for CLI Settings interface;
* Prepend binaries in git hooks with yarn to use local versions;
* Add new common utilities: tryModule and requireDefault;
* Add new error type TryModuleError for internal use only;
* Add tests for these two utilities;
* Add NodeJS namespace to ESLint to prevent false-positives;
Copy link
codecov bot commented Jan 12, 2025

Codecov Report

Attention: Patch coverage is 81.10236% with 24 lines in your changes missing coverage. Please review.

Project coverage is 99.67%. Comparing base (784ee89) to head (501b600).

Files with missing lines Patch % Lines
packages/core/src/utils/loader.ts 67.56% 24 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #6333      +/-   ##
==========================================
- Coverage   99.80%   99.67%   -0.13%     
==========================================
  Files         266      267       +1     
  Lines       19205    19293      +88     
  Branches     4829     4273     -556     
==========================================
+ Hits        19167    19231      +64     
- Misses         38       62      +24     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@B4nan
Copy link
Member
B4nan commented Jan 12, 2025

I also updated git hooks to use local binaries of lint-staged and commitlint, because there's no point to have those installed globally (yarn can pick up both local and global installations), nor to assume everyone has these by default.

I believe those were already resolved to the locally installed versions. I don't have them installed globally and it works just fine.

Deprecate useTsNode, preferTs, and alwaysAllowTs in favor of loaders;

This feels weird to me, at least preferTs should stay as a way to disallow using TS even if supported (= production builds). But I haven't checked the changes yet, so maybe I am missing something. Note that useTsNode is no longer needed since v6.4, and serves only as a way to disallow TS in the CLI (for the very same reason, production builds).

@octet-stream
Copy link
Contributor Author

I believe those were already resolved to the locally installed versions. I don't have them installed globally and it works just fine.

I got an error when I tried to commit for the first time saying it can't find lint-staged (which I don't have globally installed), so I don't think this is the case. The only change I've made was adding yarn before lint-staged and commitlint in git hooks. This fixed the problem.

image

This feels weird to me, at least preferTs should stay as a way to disallow using TS even if supported

This is still supported if the loader option or MIKRO_ORM_CLI_LOADER variable is set to either "native" or false. The option itself defaults to "auto", meaning that Mikro ORM will try to detect whatever of supported transpilers installed. The MIKRO_ORM_CLI_LOADER will override whatever is set in package.json, just like it currently works.

For backward compatibility reasons I'll keep ts-node as the fist option (one the createAutoLoader will try fist), before you can decide whether to deprecate it or not. I think jiti is a good replacement, because it seem to me the most compatible (unlike tsx, which is using esbuild under the hood).

Also, I found that preferTs option is not documented, nor normalized (I don't see a CLI counterpart for this option anywhere). Should I include docs and add CLI option for it in this PR?

@octet-stream
Copy link
Contributor Author

Note that useTsNode is no longer needed since v6.4, and serves only as a way to disallow TS in the CLI (for the very same reason, production builds).

The new loader option can both disable TS detection, or choose a specific transpiler to handle TS files.

For example, when set to tsx - it will try and import it. If it's not installed - it will fail and ask user to add it to project's dependencies :)

@B4nan
Copy link
Member
B4nan commented Jan 12, 2025

Ok good. So the PR as is should be good for 6.x release, no BCs, right?

Also, I found that preferTs option is not documented,

It is mentioned here and here, but feel free to mention it on other places. The thing is, you are not supposed to use this outside of test, and the value is inferred automatically, but having some explicit docs around it won't hurt for sure.

nor normalized (I don't see a CLI counterpart for this option anywhere). Should I include docs and add CLI option for it in this PR?

You mean the settings in package.json? For that we have useTsNode, the value is used as a default for preferTs internally. If you mean env var, yeah, sure, let's add that.

Also, does this work with ESM projects? Will the regular mikro-orm CLI endpoint work? I've added the mikro-orm-esm because I haven't found any way to register the support programmatically with ts-node without using node --loader, I would love to get rid of it in v7.

I got an error when I tried to commit for the first time saying it can't find lint-staged (which I don't have globally installed), so I don't think this is the case. The only change I've made was adding yarn before lint-staged and commitlint in git hooks. This fixed the problem.

Weird, for me it works fine (and I just verified I do not have them installed globally), but I dont mind the changes you did.

@octet-stream
Copy link
Contributor Author

Ok good. So the PR as is should be good for 6.x release, no BCs, right?

Yes, and I will cover my code with test to make sure everything works as expected + since you have integration test for CLI, I should be able to catch potential bugs and regression in the process. But the code itself should behave the same: ts-node is the default, and old flags supported and will take precedence if loader option is not set.

Also, I'm planning to use fixtures for my tests, just like you do for tests against databases, and as I already did in my proposal, so everything will be tested against real configs.

Also, does this work with ESM projects? Will the regular mikro-orm CLI endpoint work?

Everything will be handled by either jiti, or tsx. They offer programmatic API that does not affect the whole runtime, unlike with ts-node, which behaves like loader or require hook. So, yes, a single entry point should be enough, and I already tested it against both CJS and ESM in my proposal. I will port these tests to Mikro ORM too. :)

See:

*/
function loaderNameFromEnv(value?: string): Loaders {
const maybeBoolean = value?.toLowerCase();
if (!maybeBoolean || ['false', 'f', '0', 'no', 'n', ''].includes(maybeBoolean)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we use different logic for reading bools from env vars, I would like to stay consistent with that. its used in this very file inside loadEnvironmentVars:

const bool = (v: string) => ['true', 't', '1'].includes(v.toLowerCase());

i don't think we need to care about y/n or yes/no (or we should respect them universally, not just here). the code should be reused ideally (we can move the current helpers out of there to the top level functions).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we use different logic for reading bools from env vars, I would like to stay consistent with that. its used in this very file inside loadEnvironmentVars

Yes, I saw these. In this case I don't need to convert the value to a boolean. I just need to see if it can be converted. But I agree, that makes sense. So I'll just move these helpers outside of Utils class and and use in my comparison like so:

if (!value || bool(value) === false) {
  // ...
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated this code, but I can't just use bool function for type casting for loader option, because it can be a boolean, or a string.

}

// Return `undefined` if the `value` can be converted to `true`, so behaviour will be the same as in createLoader
if (['true', 't', '1', 'yes', 'y'].includes(maybeBoolean.toLowerCase())) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

Comment on lines 1375 to 1377
*/

export class TryModuleError extends Error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
*/
export class TryModuleError extends Error {
*/
export class TryModuleError extends Error {

also maybe think of a better name? but i guess we can keep this too, it just feels weird to have the Try prefix in an error name.

and move this to the https://github.com/mikro-orm/mikro-orm/blob/678119475cee860dd4684c9f4d903a3d4028b8a3/packages/core/src/errors.ts file


btw why is it internal, do we always catch it internally or can it bubble to the user? if it can, i wouldn't mark it as internal

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw why is it internal, do we always catch it internally or can it bubble to the user? if it can, i wouldn't mark it as internal

It is for internal use only. We will catch it and use its data (that's what is the specifier field for) to display a message asking for ts-node/jiti/tsx installation. Unlike Node.js' errors it can be tested with instanceof and type casting is not needed anymore.

I think tryModule and requireDefault should also be inaccessible from @mikro-orm/core package, since they supposed to use internally.

Copy link
Member
@B4nan B4nan Jan 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think tryModule and requireDefault should also be inaccessible from @mikro-orm/core package, since they supposed to use internally.

Makes sense, as long as it won't be part of the barrel file, it shouldn't be exported. I guess we should rename them to exports.ts or similar, I don't want to use them internally (it can cause issues with cycles), they should be there currently only for this use case.

edit: but you'll have to adjust the barrel file, I think it now reexports this whole file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but you'll have to adjust the barrel file, I think it now reexports this whole file.

Which one? The Utils? Yup, You can see how I access my utils in the tests.

By the way, is the errors.ts also a barrel file? Some of the errors must be part of the public API surface, so you probably re-export them too, and I want TryModuleError class (or whatever the name will be at the end) to be inaccessible outside of @mikro-orm/core, since it's for internal use only.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which one?

export * from './Utils';

By the way, is the errors.ts also a barrel file?

Barrel files reexport things, so in that sense, nope, its not. But we reexported all its contents as part of the upper barrel file.

export * from './errors';

Maybe move all of this into the loaders.ts file and don't export it at all?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, I'll move all these new utilities into loaders.ts, and if you'll ever need tryModule or requireDefault, you'll just change the code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this error to loader.ts. I don't think the name matters quite a lot, but I can rename it when I figure out how to test this error's appearance (I think it can be done by mocks if I throw NodeJS.ErrnoError instead of returning the exports?), sure.

return loader;
}

const tsNode = requireDefault(await tryModule(import('ts-node'), {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this won't be a problem for bundlers, ts-node is not a peer dependency and I believe bundlers will try to bundle it this way. That's why we use the tryRequire which won't suffer from it, since bundlers won't see a literal import of a package, they see just an import of some unknown dependency.

Copy link
Contributor Author
@octet-stream octet-stream Jan 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm. I never though about that. I will see if that is gonna be the problem. Maybe there's a way (universal, hopefully) to ask bundlers to skip bundling some of the dependencies for package authors. Good catch though!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK wrapping the import inside a helper function and passing the module name dynamically is enough.

Copy link
Contributor Author
@octet-stream octet-stream Jan 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, but tryModule is not only catches ERR_MODULE_NOT_FOUND error, it also returns correct types, unlike Utils.tryRequire, which returns any. If there's no way to keep bundlers from bundling these calls - I will figure out another solution how to have both types and keep dependencies from bundling.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you can have both. Either it will break bundlers (and will require config changes to mark those as external in users' projects), or it will be typed to any.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found something for Vite: https://vite.dev/guide/ssr.html#ssr-externals

It will not include @mikro-orm/* packages (as well as any other package from node_modules) to SSR bundle, but that's just Vite.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm gonna rewrite this function as you suggested for backward compatibility, but I'll keep types for better DX. I don't think TS will keep them in .d.ts, so this should not be a problem.

But I think this is something to consider for v7:

  1. Move configuration loader to its own package. I can see that the current ConfigurationLoader class is used in quite a few places. We can also reuse these utilities to implement directory-based discovery and make this package official way do do it (if user's codebase is not using any bundler, see below).
  2. Deprecate and remove MikroORM.init() without arguments - this way the new package will be part of CLI, or user's code if they want to use directory-based discovery.
  3. Write official recipe for directory-based discovery when using MikroORM with bundlers, at least Vite (https://vite.dev/guide/features.html#glob-import) and Webpack (https://webpack.js.org/api/module-methods/#dynamic-expressions-in-import) have their own way to bundle code with dynamic imports. Afaik, it's not even possible to do it with Mikro ORM's own APIs, because bundlers will just ignore utilities, like Utils.tryRequire and Utils.dynamicImport. If you want to support bundlers, then let's make it official :)

Copy link
Contributor Author
@octet-stream octet-stream Jan 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated tryModule implementation so it will accept specifier as the first argument, instead of promise returned by import(), now it shouldn't be a problem. Feel free to close this conversation if you don't have any thoughts on my previous comment.

Copy link
Member
@B4nan B4nan Jan 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deprecate and remove MikroORM.init() without arguments - this way the new package will be part of CLI, or user's code if they want to use directory-based discovery.

There is one use case for the method even without the dynamic config loading - using only env vars. It's not a universal solution, but most things can be configured that way. But it requires folder-based discovery to work in the first place. But I guess people could just do init({}) if they want that behaviour.

Otherwise, I would be fine with telling people to just import the config file and pass it explicitly, it's one additional line, otherwise it only has benefits.

Note that folder-based discovery is one thing, but we still do similar stuff for seeders and migrations. I don't think we can just drop that part, so we won't get rid of those issues completely just by moving the discovery part.

it's not even possible to do it with Mikro ORM's own APIs

You can use bundlers just fine, but you need to configure them properly. I am not sure if that will change with what you are proposing. But I was never a huge fan of bundling on backend, don't have much experience with that.

Copy link
Contributor Author
@octet-stream octet-stream Jan 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that folder-based discovery is one thing, but we still do similar stuff for seeders and migrations. I don't think we can just drop that part, so we won't get rid of those issues completely just by moving the discovery part.

Yes, but aren't they separated packages? Do they responsible for loading migrations and seeders?

But I was never a huge fan of bundling on backend

I couldn't agree more, but I usually use Mikro ORM in full-stack projects, where both backend and frontend are the same app and it's built with one of the so called "meta frameworks", and all of them use one of the bundlers. Like, Qwik, SvelteKit and React Router v7 (ex Remix) use Vite.

@octet-stream
Copy link
Contributor Author

I would love to get rid of it in v7.

I forgot to mention one important thing: As long as we have to support ts-node - this might not work in a single CLI entry point, so in v6 we sure have to keep mikro-orm-esm around. For new loaders, the mikro-orm should work.

Co-authored-by: Martin Adámek <banan23@gmail.com>
@B4nan
Copy link
Member
B4nan commented Jan 12, 2025

so in v6 we sure have to keep mikro-orm-esm around

Removing it as part of v6 would be a BC, so that's out of question anyway.

@octet-stream
Copy link
Contributor Author
octet-stream commented Jan 13, 2025

Now the tests are failing because Jest cannot import tsx/esm/api, this probably because it replaced import with require and Node.js does not support it in this version. Can we fix this somehow in Jest?

Edit: Wait, no, the error occurs when tsc validates tests against test/tsconfig.json configuration. So, the import() is not suppored by Mikro ORM's test suite? I don't have this problem when I just run tests via yarn test, I run tests on Node.js v23

Edit 2: I think we can use dynamic import to get the types (as tsc suggests), but your ESLint config prohibits it :) Can I disable or change the rule for this file?

@B4nan
Copy link
Member
B4nan commented Jan 13, 2025

Can I disable or change the rule for this file?

Which one? We use dynamic imports in the codebase, e.g. here.

@octet-stream
Copy link
Contributor Author

Which one?

This one: https://typescript-eslint.io/rules/consistent-type-imports/

The error says following:

Error: node_modules/jiti/lib/jiti.d.cts(1,24): error TS1479: The current file is a CommonJS module whose imports will produce 'require' calls; however, the referenced file is an ECMAScript module and cannot be imported with 'require'. Consider writing a dynamic 'import("./types.js")' call instead.

So, from what I understand, I need to replace

import type * tsxApi from "tsx/esm/api"

with

Type TsxApi = typeof import("tsx/esm/api") // Except, I will use it right in `tryModule` type parameter

@octet-stream
Copy link
Contributor Author

So, from what I understand, I need to replace

Nope, that didn't help :)

@octet-stream
Copy link
Contributor Author

skipLibCheck helps (I added it to tests/tsconfig.json). Why don't you have this option enabled? At least for tests. It hurts performance when tsc checks everything in node_modules, and I don't see you test any .d.ts files in tests.

@B4nan
Copy link
Member
B4nan commented Jan 13, 2025

Why don't you have this option enabled?

Because I want to see if we do something wrong when integrating 3rd party libraries. AFAIK you can end up with issues without this, that you won't see but people can see if they don't use skipLibsCheck in their projects.

I am fine with having that disabled for tests.

@octet-stream
Copy link
Contributor Author

Because I want to see if we do something wrong when integrating 3rd party libraries.

I mean, it's not like you can do about 3rd parties.

AFAIK you can end up with issues without this, that you won't see but people can see if they don't use skipLibsCheck in their projects.

The documentation says this: https://www.typescriptlang.org/tsconfig/#skipLibCheck

I'm not sure what they mean by

TypeScript will type check the code you specifically refer to in your app’s source code.

Will it verify public-facing types from 3rd party libraries, or just the source code?

Anyway. Turns out tsc will also fail when I try and build the packages, with the same error. But at the same time the loader.ts is compiled, I can see the result in dist directory and as I said, there there's no jiti and tsx type declarations in the resulting loader.d.ts file. Too sad TS still complains about these anyway during compilation. I should probably just use any and be done with that (maybe even reuse Utils.dynamicImport). @ts-ignore doesn't help, of course, because it tries to check 3rd party .d.ts file.

@octet-stream
Copy link
Contributor Author
octet-stream commented Jan 13, 2025

Also, I think tsc will apply same tsconfig.json for 3rd parties as in mikro orm which might cause the problem in the first place - 3rd parties may have different configs, but their code is will valid. tsc looks at their .d.cts file, which imports ./types.js file as type-only import and thinks this is ES module. Weird. Ok, I can just use any, if you want to keep skipLibCheck disabled. But then we will not be able to catch errors if jiti or tsx change their public API - afaik the types I import will still be validated, tsc will just skip what's inside the imported module. At least I will see the errors if I try to import or use something that doesn't exist in the package I'm referencing in my code (no matter whether skipLibCheck disabled or not).

Edit: Found this discussed on stack overflow: https://stackoverflow.com/questions/52311779/usage-of-the-typescript-compiler-argument-skiplibcheck

Enabling --skipLibCheck can help work around these issues. Turning it on will prevent Typescript from type-checking the entire imported libraries. Instead, Typescript will only type-check the code you use against these types. This means that as long as you aren't using the incompatible parts of imported libraries, they'll compile just fine.

@octet-stream
Copy link
Contributor Author
octet-stream commented Jan 13, 2025

I have this error when I'm using imports in my tests (I'm trying to import .mts file):

image

So, Jest does not support esm by default?

Also, this error with mts files:

image

tsc can't pick up mikro orm typings in esm for some reason (even if I add package.json with {type: "module"} and configure tsc, just for fixtures). I don't see such problem when I install it from npm and use in my esm projects (for example - I don't have this problem in my proposal's repo). Weird.

I'll probably skip tests for esm for now, since Mikro ORM seem to be configured as CJS package, but they should work.

@octet-stream
Copy link
Contributor Author

I believe this is also Jest-related issue. I get it only with tsx, though.

image

This probably related: jestjs/jest#9580

I will skip tsx tests for now, and see if I can do anything about it. The loader should still work though. I am not much familiar with Jest, so any help from you will be appreciated.

@@ -39,6 +67,9 @@ export class ConfigurationLoader {
*/
static async getConfiguration<D extends IDatabaseDriver = IDatabaseDriver, EM extends D[typeof EntityManagerType] & EntityManager = EntityManager>(validate: boolean, options?: Partial<Options>): Promise<Configuration<D, EM>>;
static async getConfiguration<D extends IDatabaseDriver = IDatabaseDriver, EM extends D[typeof EntityManagerType] & EntityManager = EntityManager>(contextName: boolean | string = 'default', paths: string[] | Partial<Options> = ConfigurationLoader.getConfigPaths(), options: Partial<Options> = {}): Promise<Configuration<D, EM>> {
const settings = ConfigurationLoader.getSettings();
const basePath = options.baseDir ?? process.cwd();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what is the baseDir option for, but the projectRoot argument is meant to be configurable (for tests and for use), so I had to get it from somewhere and not just re-use process.cwd().

@octet-stream
Copy link
Contributor Author

@B4nan I might need your help with ConfigurationLoader.getConfiguration() testing. I just have no idea how to test it against real config file, because my test case always fails validation at Configuration class saying I should provide driver option. I even added test for loaders + Configuration class to make sure that returned file, and it works, but not for getConfiguration (even with the same config file).

Also, I've tried to pass base path by overriding process.cwd for my test case (as you can see in the code) and by setting basePath option - the result is the same. My initial though was that merge helper doesn't work properly and wipes out driver for some reason if I set basePath, but it doesn't seem to be the case.

I know you test against mocks, but I want to make sure my loaders integrated properly so I won't break anything in v6, so I run my tests against real config files.

@B4nan
Copy link
Member
B4nan commented Feb 10, 2025

I wonder if it would be better to target v7 here, I've already set up the branch and I am almost there with ESM rewrite using vitest instead of jest.

@octet-stream
Copy link
Contributor Author

Maybe, I don't mind. But for v7 this PR will probably be useless, except for the loaders.ts module, well, if you would agree moving configuration loader and folder-based discovery out of core module.

@B4nan
Copy link
Member
B4nan commented Feb 11, 2025

Why useless? It adds support for other TS support providers, or did I miss something?

if you would agree moving configuration loader and folder-based discovery out of core module.

I am not completely opposed to doing that but so far I haven't seen a good enough reason.

@octet-stream
Copy link
Contributor Author

Why useless? It adds support for other TS support providers, or did I miss something?

I meant, it would probably need to be rewritten, because it might not fit in its current state in a future, and as I said - it would depend on whether or not it will be put into a separate package. The loaders implementation is completed thought, no matter how it will be integrated - it tested and it should work.

I am not completely opposed to doing that but so far I haven't seen a good enough reason.

Well, as I already said, I think it might help to improve support for bundlers, if we clear the core package from dynamic import and things like node:fs (or fs-extra) usage, plus we can avoid tricks with like you mentioned in your previous comments and have dynamic imports properly typed, like I did in my proposal repo, because we move all Node.js specific stuff to CLI, and to a separate package for those who don't care about bundlers. Have to say bundlers not a huge concern for me, I'm fine eight way as long as I can help to replace ts-node with more modern solutions. :)

@octet-stream
Copy link
Contributor Author

Btw, do we still need ts-node support if we move this to v7 instead?

@octet-stream
Copy link
Contributor Author
octet-stream commented Feb 14, 2025

I just found out that jiti having problems when it encounters class properties without initializer: unjs/jiti#57

So, I guess this pr is stuck anyway until and if they fix the problem. tsx does not have this problem, but then again - they don't support decorators metadata.

The issue is quite old, so I don't expect maintainers will respond, and if they don't - I will open an issue there. I'll wait until the fix arrives before moving forward with the pr.

@B4nan
Copy link
Member
B4nan commented Feb 16, 2025

I started testing out the ESM rewrite (#6403) and the ts-node solution we have now is not working at all, so there is your answer - ts-node is going out from v7 right now :] I just swapped it with @swc-node/register and it looks good, works fine when registered dynamically, so no need for the ESM bin script. I will only make a simple replacement for now so I can unblock the ESM PR, I would still like to see support for the other solutions you mentioned, as long as it can all stay optional, I am all in for making things less opinionated.

@octet-stream
Copy link
Contributor Author

Glad to hear that. I'll remove ts-node support then, when we will move this PR forward. Hope jiti lans PR with fix for the issue I was talking about in my previous comment, otherwise the only two loaders left will be tsx and native. Or maybe I can replace ts-node loader with swc (as I initially proposed, in addition to other options), as far as I can tell, the implementation will be the same

const supported = await Utils.tryImport({
module: '@swc-node/register/esm-register',
warning: '@swc-node/register not installed, support for working with TS files might not work',
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants
0