Skip to content

chore(typescript): change moduleResolution #1605

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

Open
wants to merge 28 commits into
base: master
Choose a base branch
from

Conversation

alexandre-abrioux
Copy link
Member

@alexandre-abrioux alexandre-abrioux commented Apr 14, 2025

In this PR, I'm proposing to change TypeScript's module and moduleResolution to the latest recommended versions (see the section below for TypeScript recommendations). This would allow us to use ESM features in CommonJS, and forbid us to use non-ESM compatible imports, which should ease the transition to ESM later on. We would also gain:

  • support for require(esm): allows to import ESM modules synchronously in CommonJS, without the need for await import()
  • support package.json's new exports property, which allows importing part of a module with import {} from module/part. e.g. dotenv/config. This change is required for chore(WIP): migrate to @noble/curves and eciesjs #1236

TypeScript Documentation

module

https://www.typescriptlang.org/docs/handbook/modules/reference.html#commonjs

commonjs

You probably shouldn’t use this. Use node16, node18, or nodenext to emit CommonJS modules

moduleResolution

https://www.typescriptlang.org/docs/handbook/modules/reference.html#node10-formerly-known-as-node

node10 (formerly known as node)

--moduleResolution node ... should no longer be used.

Issue to address before merge

Summary by CodeRabbit

  • New Features

    • Improved validation format support by integrating ajv-formats for enhanced data validation.
    • Jest test execution now adapts to available system resources for better performance during testing.
  • Bug Fixes

    • Updated test assertions to match new validation error message formats.
  • Chores

    • Upgraded multiple dependencies across packages, including TypeScript, tslib, dotenv, ajv, and ts-jest, for improved compatibility and security.
    • Updated TypeScript configuration for modern module resolution and interoperability.
    • Refined type imports and type aliasing to reduce reliance on internal module paths.
    • Clarified type-only exports across various modules to improve type safety and code clarity.

Copy link
Contributor

coderabbitai bot commented Apr 14, 2025

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This update applies a broad set of dependency version bumps across multiple package.json files throughout the repository, notably upgrading TypeScript, tslib, ts-jest, and several other libraries. The TypeScript compiler configuration (tsconfig.json) is updated to use the "nodenext" module system and enables "esModuleInterop" and "isolatedModules". The CircleCI configuration is adjusted to set a JEST_MAX_WORKERS environment variable for concurrent Jest test runs. Jest's configuration is made responsive to this environment variable. Several internal type imports are refactored to avoid reliance on internal or legacy paths by deriving types from GraphQLClient prototypes. The Ajv JSON schema validator integration is updated to use ajv-formats, affecting both code and test expectations. Additionally, multiple export statements are changed to type-only exports for clarity and correctness.

Changes

File(s) Change Summary
.circleci/config.yml, jest.config.js CircleCI test job sets JEST_MAX_WORKERS to '50%'; Jest config conditionally uses maxWorkers from env var.
tsconfig.json Changed TypeScript module system and resolution to "nodenext"; enabled esModuleInterop and isolatedModules.
package.json, packages/*/package.json Updated TypeScript, tslib, ts-jest, and other dependencies/devDependencies to newer versions.
packages/data-format/package.json, packages/data-format/src/index.ts, packages/data-format/test/test.ts Upgraded ajv, added ajv-formats, updated import style, and adjusted test error assertions to match new Ajv error messages.
packages/payment-detection/src/thegraph/client.ts, packages/payment-detection/src/thegraph/superfluid.ts, packages/thegraph-data-access/src/subgraph-client.ts, packages/thegraph-data-access/src/types.ts Replaced direct imports of RequestConfig from internal graphql-request paths with local type aliases derived from GraphQLClient prototype. Changed some imports to use import type.
packages/data-access/src/index.ts, packages/payment-detection/src/index.ts, packages/payment-processor/src/payment/index.ts, packages/payment-processor/src/payment/swap-any-to-erc20.ts, packages/request-client.js/src/index.ts, packages/types/src/data-access-types.ts, packages/types/src/extensions/pn-any-fee-reference-based-types.ts, packages/types/src/extensions/pn-any-reference-based-types.ts, packages/types/src/extensions/pn-any-stream-reference-based-types.ts, packages/types/src/extensions/pn-any-to-any-conversion-types.ts Changed multiple exports to type-only exports; added explicit type exports for some interfaces; reordered imports and exports for clarity.
* (all other files) No changes to exported/public entities; only dependency version updates or minor internal refactors.

Sequence Diagram(s)

sequenceDiagram
    participant CircleCI
    participant Jest
    participant Lerna

    CircleCI->>Jest: Set JEST_MAX_WORKERS='50%'
    Lerna->>Jest: Run 2 Jest commands concurrently
    Jest->>Jest: Use maxWorkers from env if set
Loading
sequenceDiagram
    participant Validator
    participant Ajv
    participant ajv-formats

    Validator->>Ajv: Create Ajv instance
    Validator->>ajv-formats: addFormats(Ajv)
    Validator->>Ajv: Add meta schema, address schema
    Validator->>Ajv: Validate data
Loading

Possibly related PRs


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@@ -52,7 +52,7 @@
"npm-package-json-lint": "5.1.0",
"prettier": "2.8.8",
"prettier-plugin-solidity": "1.0.0-beta.19",
"typescript": "5.1.3"
"typescript": "5.8.3"
Copy link
Member Author

@alexandre-abrioux alexandre-abrioux Apr 14, 2025

Choose a reason for hiding this comment

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

Updated Typescript to support loading ES modules in CommonJS synchronously (without await import()):
https://nodejs.org/api/modules.html#loading-ecmascript-modules-using-require

This is needed to support the latest version of graphql-request used in the payment-detection package.

"@graphql-codegen/typescript-graphql-request": "6.0.1",
"@graphql-codegen/typescript-graphql-request": "6.2.0",
Copy link
Member Author

Choose a reason for hiding this comment

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

Fixes the generated GraphQL code that previously contained imports not compatible with latest module resolution.

import { getSdk as getNearSdk } from './generated/graphql-near';
import { RequestConfig } from 'graphql-request/src/types';
Copy link
Member Author

@alexandre-abrioux alexandre-abrioux Apr 14, 2025

Choose a reason for hiding this comment

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

This import is not compatible with ESM. We can't do such type of imports anymore, as graphql-request/src/types is not an exported module.

"dotenv": "8.2.0",
"dotenv": "16.5.0",
Copy link
Member Author

@alexandre-abrioux alexandre-abrioux Apr 14, 2025

Choose a reason for hiding this comment

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

There was an issue with how dotenv exported their types in older versions, resulting in error

TS7016: Could not find a declaration file for module dotenv.

@nkoreli
Copy link
Contributor

nkoreli commented Apr 15, 2025

@alexandre-abrioux:
we updated hinkal/common to 0.2.12 and were able to built the project without the errors.

@alexandre-abrioux
Copy link
Member Author

Thanks a lot @nkoreli 🙏

import * as AJV from 'ajv';
import { Ajv } from 'ajv';
Copy link
Member Author

@alexandre-abrioux alexandre-abrioux Apr 17, 2025

Choose a reason for hiding this comment

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

With the old version (v6) of Avj there was a TypeScript issue, but only during tests. I fixed it by updating Avj to v8 and handling the breaking changes. This was before I found out that ts-jest needs isolatedModules=true to support module=nodenext.

Later, I tested again with Ajv v6, this time with isolatedModules=true, and it also works. But I figured I would keep this change since I went through the trouble of updating it.

"module": "commonjs",
"module": "nodenext",
"moduleResolution": "nodenext",
"esModuleInterop": true,
Copy link
Member Author

@alexandre-abrioux alexandre-abrioux Apr 17, 2025

Choose a reason for hiding this comment

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

esModuleInterop=true is now the default with module=nodenext: https://www.typescriptlang.org/tsconfig/#esModuleInterop ; but we still specify it so that other tools (IDE, eslint, ts-jest) are all aligned with it.

For instance, there was an issue with ts-jest showing warnings when this field was not set, which was also fixed by updating the ts-jest package later on: kulshekhar/ts-jest#4266 ; but I kept esModuleInterop=true for clarity.

Comment on lines +122 to +125
environment:
# Lerna starts 2 Jest commands at the same time (see above --concurrency=2),
# so we use 50% of our CPU cores on each
JEST_MAX_WORKERS: '50%'
Copy link
Member Author

@alexandre-abrioux alexandre-abrioux Apr 17, 2025

Choose a reason for hiding this comment

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

This change is not mandatory.

While fiddling with our TS config, I had some issues with the CI, especially before I found out that we had to activate isolatedModules=true for ts-jest to work with module=nodenext (see explanation in the tsconfig.json file). At this point, ts-jest was consuming a considerable amount of RAM during tests. The job highlighted above (test-unit) constantly consumed 100% of the RAM and failed with timeouts or out-of-memory errors.

While digging, I found that configuring Jest to only use 4 workers (50% of CPU cores) instead of 8 (default 100% CPU cores) completely stabilized the tests, even with this buggy ts-jest config consuming a lot of memory.

After enabling isolatedModules=true, I could have reverted that change, because ts-jest was back to consuming a normal amount of memory. However this change seems to improve test time quite a bit:

In the end, even if this change is not mandatory, I have kept it as it made our pipeline faster.

Side note that confirms this: Adobe dev team advises in their blog using a maximum of 50% CPU cores for Jest workers, especially on small machines like CI runners, so as to leave some room for Jest to spawn NodeJS processes.

Here, I have only modified the configuration for this specific test-unit job, which was causing me issues, but the new JEST_MAX_WORKERS environment variable I introduced could be extended later on to other jobs if needed, to reduce potential flakiness or increase CI speed.

"module": "nodenext",
"moduleResolution": "nodenext",
"esModuleInterop": true,
"isolatedModules": true,
Copy link
Member Author

@alexandre-abrioux alexandre-abrioux Apr 17, 2025

Choose a reason for hiding this comment

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

ts-jest requires isolatedModules=true with module=nodenext, see:
https://kulshekhar.github.io/ts-jest/docs/guides/esm-support/#using-hybrid-module-values

This does not change the emitted JS files; it only adds warnings when using TypeScript features that are not compatible with single-module transpilation.

@@ -3,6 +3,6 @@ export { CombinedDataAccess } from './combined-data-access';
export { DataAccessWrite } from './data-write';
export { DataAccessRead } from './data-read';
export { PendingStore } from './pending-store';
export { DataAccessBaseOptions } from './types';
export type { DataAccessBaseOptions } from './types';
Copy link
Member Author

@alexandre-abrioux alexandre-abrioux Apr 17, 2025

Choose a reason for hiding this comment

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

needed when exporting types with isolatedModules=true

@alexandre-abrioux alexandre-abrioux marked this pull request as ready for review April 17, 2025 21:58
@alexandre-abrioux alexandre-abrioux marked this pull request as draft April 17, 2025 21:59
@alexandre-abrioux alexandre-abrioux marked this pull request as ready for review April 17, 2025 22:47
@alexandre-abrioux alexandre-abrioux requested review from MantisClone, aimensahnoun and yomarion and removed request for kevindavee, leoslr and yomarion April 17, 2025 22:48
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