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

fix(core): load forge.config.ts with tsx on supported Node versions #3881

Open
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

erickzhao
Copy link
Member

@erickzhao erickzhao commented Mar 13, 2025

Fixes #3872 Fixes #3676 Fixes #3609 Fixes #3780 Fixes #3671

Context

#2993 added support for arbitrary non-JavaScript configuration files using Gulp's interpret and rechoir modules.

Given a list of file extensions supported by interpret, rechoir registers that extension's module loader with Node.js.

For most use-cases, this would load the forge.config.ts config file with ts-node, although any supported Interpret module loader would work (e.g. CoffeeScript, YAML, etc.)

Problem statement

#3872 reported that TypeScript configurations stopped working in Node 23.6, which is the first version where type stripping in Node.js is available unflagged.

Simply using a forge.config.ts file fails to load with Node v23.6 and above, which indicates some sort of failure in the ts-node/interpret/rechoir toolchain.

Solution

ts-node hasn't had a release in over a year and has known issues with ESM compatibility. tsx has grown as a popular alternative to running TypeScript in Node. Note that interpret and rechoir currently don't support tsx as a module loader, either.

tsx comes with its own register() API for both CJS and ESM, but requires at least Node v18.19 or v20.6 because it uses the module.register API under the hood.

This leaves us with an incomplete support matrix between the rechoir and tsx methods, where:

  • Node >=23.6.0 doesn't support our current rechoir loader.
  • Node <18.19.0 & <20.6.0 doesn't support the new tsx loader.
  • ts-node in general has spotty ESM support.

Thankfully, this means that all versions where ts-node is unsupported are supported by tsx.

I wrote a new supportsModuleRegister helper function in core-utils that returns whether or not we can use module.register (and therefore tsx). This splits the code into two paths:

graph TD
    Start["forge.config.ts detected"] --> Decision["supportsModuleRegister?"]
    
    Decision -- Yes --> Register["Use tsx.register() for CommonJS & ESM"]
    Register --> LoadConfig1["Load forge.config.ts"]
    LoadConfig1 --> Unload["Immediately unload"]
    Unload --> End
    
    Decision -- No --> Split["then"]
    
    Split --> OnStart["Start"]
    OnStart --> TsNode["Register ts-node for forge.config.ts"]
    TsNode --> LoadConfig2["Load forge.config.ts"]
    LoadConfig2 --> End
    
    Split --> OnInit["Init"]
    OnInit --> InstallTsNode["Install ts-node for all TypeScript templates"]
    InstallTsNode --> End
Loading

Miscellaneous

  • Moving to tsx also adds support for forge.config.mts and potentially solves ESM-related configuration issues for us.
  • I had some test failures in our slow tests and make tweaks. I'm not sure why this PR triggered them, but they seem reasonable:
  • The startLogic PluginBase function that we don't use as of feat: add preStart hook and port existing startLogic impls #3720 now fails because we're loading the config via tsx and the function reference equality no longer applies. My hacky workaround is to compare the .toString() value of those functions, but that might be unsatisfactory.

Reviewing this PR

The core set of changes is in:

  • packages/api/core/src/util/forge-config.ts: Forge config loading business logic
  • packages/utils/core-utils/src/supports-module-register.ts: New utility to check if we can use tsx to load the Forge config
  • packages/template/webpack-typescript/src/WebpackTypeScriptTemplate.ts: Conditionally installs ts-node if supportsModuleRegister is false.
  • packages/template/vite-typescript/src/ViteTypeScriptTemplate.ts: Conditionally installs ts-node if supportsModuleRegister is false.

The rest of the file changes follow from there!

@erickzhao erickzhao requested a review from a team as a code owner March 13, 2025 00:54
@erickzhao erickzhao marked this pull request as draft March 13, 2025 00:54
@erickzhao erickzhao force-pushed the tsx branch 2 times, most recently from 0badb22 to bce9a66 Compare March 14, 2025 18:35
@erickzhao erickzhao marked this pull request as ready for review March 15, 2025 00:01
@erickzhao erickzhao requested a review from a team March 15, 2025 00:01
@erickzhao erickzhao changed the title refactor: replace ts-node with tsx refactor: load forge.config.ts with tsx whenever possible Mar 15, 2025
@erickzhao erickzhao changed the title refactor: load forge.config.ts with tsx whenever possible refactor: load forge.config.ts with tsx on supported Node versions Mar 15, 2025
@erickzhao erickzhao changed the title refactor: load forge.config.ts with tsx on supported Node versions fix: load forge.config.ts with tsx on supported Node versions Mar 15, 2025
@erickzhao erickzhao changed the title fix: load forge.config.ts with tsx on supported Node versions fix(core): load forge.config.ts with tsx on supported Node versions Mar 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants