Skip to content

API snapshots: Improve performance of generator script / Jest test - #1877

Open
robhogan wants to merge 4 commits into
mainfrom
pr1877
Open

API snapshots: Improve performance of generator script / Jest test#1877
robhogan wants to merge 4 commits into
mainfrom
pr1877

Conversation

@robhogan

@robhogan robhogan commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator

CI currently frequently fails on extremely slow api-snapshots-test.

I tried previously to fix this by using multiple cores, but that actually made the problem worse in GHA where there's no spare parallelism in a Jest run.

It turns out there are two much better fixes:

  • Share TS compiler state, so TS only compiles the "program" (whole repo) once.
  • Skip a full typecheck during snapshot generation (we do a full type check elsewhere, but this was doing it once per package)

On my macbook this gives 2x better wall time, despite only using one core. On CI I expect it'll be more dramatic than that.

Also - tidy up the output that leaks through Jest by introducing a Logger set only when running the script, not during tests.

Changelog: Internal

Test plan:

Before

yarn jest api-snapshots
yarn run v1.22.22
$ /Users/robhogan/metro/node_modules/.bin/jest api-snapshots
  console.log
    =============


    WARNING: You are currently running a version of TypeScript which is not officially supported by @typescript-eslint/typescript-estree.


    * @typescript-eslint/typescript-estree version: 8.38.0
    * Supported TypeScript versions: >=4.8.4 <5.9.0
    * Your TypeScript version: 6.0.3


    Please only submit bug reports when using the officially supported version.


    =============

      at warnAboutTSVersion (node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree/dist/parseSettings/warnAboutTSVersion.js:78:23)
          at async Promise.all (index 3)

  console.warn
    packages/metro/src/lib/metroSchemeResolver.js [
      {
        ruleId: '@typescript-eslint/no-unused-vars',
        severity: 2,
        message: "'metroSchemeResolver' is defined but only used as a type.",
        line: 16,
        column: 15,
        nodeType: 'Identifier',
        messageId: 'usedOnlyAsType',
        endLine: 16,
        endColumn: 34
      }
    ]

      149 |
      150 |     if (lintResult.messages.length > 0) {
    > 151 |       console.warn(sourceFile, lintResult.messages);
          |               ^
      152 |     }
      153 |
      154 |     const formattedOutput = await prettier.format(lintedOutput, prettierConfig);

      at warn (scripts/generateTypeScriptDefinitions.js:151:15)
      at scripts/generateTypeScriptDefinitions.js:239:11
          at async Promise.all (index 177)
      at generateTsDefsForJsGlobs (scripts/generateTypeScriptDefinitions.js:197:3)
      at generateApiSnapshots (scripts/generateApiSnapshots.js:79:3)
      at Object.<anonymous> (scripts/__tests__/api-snapshots-sync-test.js:17:5)

  buck-worker-tool: 1 snapshot(s) verified in 0.0s
  metro: 1 snapshot(s) verified in 0.0s
  metro-resolver: 1 snapshot(s) verified in 0.0s
  metro-source-map: 1 snapshot(s) verified in 0.0s
  metro-cache: 1 snapshot(s) verified in 0.0s
  metro-babel-transformer: 1 snapshot(s) verified in 0.0s
  ob1: 1 snapshot(s) verified in 0.0s
  metro-config: 1 snapshot(s) verified in 0.0s
  metro-core: 1 snapshot(s) verified in 0.0s
  metro-cache-key: 1 snapshot(s) verified in 0.0s
  metro-file-map: 1 snapshot(s) verified in 0.0s
  metro-transform-worker: 1 snapshot(s) verified in 0.0s
  metro-minify-terser: 1 snapshot(s) verified in 0.0s
  metro-transform-plugins: 1 snapshot(s) verified in 0.0s
  console.warn
    Skipped public entry points without generated TypeScript definitions:
      metro-babel-register "." (no packages/metro-babel-register/types/babel-register.d.ts)
      metro-runtime "./modules/asyncRequire" (no packages/metro-runtime/types/modules/asyncRequire.d.ts)
      metro-runtime "./modules/empty-module" (no packages/metro-runtime/types/modules/empty-module.d.ts)
      metro-runtime "./modules/HMRClient" (no packages/metro-runtime/types/modules/HMRClient.d.ts)
      metro-runtime "./modules/null-module" (no packages/metro-runtime/types/modules/null-module.d.ts)
      metro-runtime "./polyfills/require" (no packages/metro-runtime/types/polyfills/require.d.ts)
      metro-symbolicate "." (no exported API surface)

      135 |
      136 |   if (allSkipped.length > 0) {
    > 137 |     console.warn(
          |             ^
      138 |       'Skipped public entry points without generated TypeScript ' +
      139 |         `definitions:\n  ${allSkipped.join('\n  ')}`,
      140 |     );

      at warn (scripts/generateApiSnapshots.js:137:13)
      at Object.<anonymous> (scripts/__tests__/api-snapshots-sync-test.js:17:5)

Verified 14 public API snapshot(s) across Metro's OSS packages.
 PASS  scripts/__tests__/api-snapshots-sync-test.js (8.993 s)
  ✓ Public API snapshots are in sync (yarn run build-api-snapshots produces no changes) (8530 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        9.022 s, estimated 12 s
Ran all test suites matching /api-snapshots/i.
✨  Done in 9.76s.

After

yarn jest api-snapshots
yarn run v1.22.22
$ /Users/robhogan/metro/node_modules/.bin/jest api-snapshots
 PASS  scripts/__tests__/api-snapshots-sync-test.js
  ✓ Public API snapshots are in sync (yarn run build-api-snapshots produces no changes) (3755 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        4.481 s, estimated 9 s
Ran all test suites matching /api-snapshots/i.
✨  Done in 4.91s.

Stack created with Sapling. Best reviewed with ReviewStack.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Aug 25, 2026
@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Aug 25, 2026
## TS error
Currently, the generated `.d.ts` for this file causes a TS ESLint error:

https://github.com/react/metro/actions/runs/32859032114/job/97838112966

```
yarn run build-ts-defs && yarn lint
...
metro/packages/metro/types/lib/metroSchemeResolver.d.ts
  23:15  error  'metroSchemeResolver' is defined but only used as a type  @typescript-eslint/no-unused-vars

✖ 1 problem (1 error, 0 warnings)

error Command failed with exit code 1.
```

This is ultimately flow-api-translator producing messy output, but we can workaround it in the mean time by using an anonymous default export.

## Windows paths handling

Additionally, CI fails on Windows because both of the new `metroSchemeResolver-test` and `createStaticCrawler-test` hardcode posix paths. Fix that with the usual normalisation pattern.

Test plan:
OSS CI is green on this PR.
@meta-codesync

meta-codesync Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

@vzaidman has imported this pull request. If you are a Meta employee, you can view this in D117379688.

CI currently frequently fails on extremely slow `api-snapshots-test`.

I tried previously to fix this by using multiple cores, but that actually made the problem worse in GHA where there's no spare parallelism in a Jest run.

It turns out there are two much better fixes:
 - Share TS compiler state, so TS only compiles the "program" (whole repo) once.
 - Skip a full typecheck during snapshot generation (we do a full type check elsewhere, but this was doing it once per package)

On my macbook this gives 2x better wall time, despite only using one core. On CI I expect it'll be more dramatic than that.

Also - tidy up the output that leaks through Jest by introducing a `Logger` set only when running the script, not during tests.

Changelog: Internal

Test plan:
## Before
```
yarn jest api-snapshots
yarn run v1.22.22
$ /Users/robhogan/metro/node_modules/.bin/jest api-snapshots
  console.log
    =============


    WARNING: You are currently running a version of TypeScript which is not officially supported by @typescript-eslint/typescript-estree.


    * @typescript-eslint/typescript-estree version: 8.38.0
    * Supported TypeScript versions: >=4.8.4 <5.9.0
    * Your TypeScript version: 6.0.3


    Please only submit bug reports when using the officially supported version.


    =============

      at warnAboutTSVersion (node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree/dist/parseSettings/warnAboutTSVersion.js:78:23)
          at async Promise.all (index 3)

  console.warn
    packages/metro/src/lib/metroSchemeResolver.js [
      {
        ruleId: '@typescript-eslint/no-unused-vars',
        severity: 2,
        message: "'metroSchemeResolver' is defined but only used as a type.",
        line: 16,
        column: 15,
        nodeType: 'Identifier',
        messageId: 'usedOnlyAsType',
        endLine: 16,
        endColumn: 34
      }
    ]

      149 |
      150 |     if (lintResult.messages.length > 0) {
    > 151 |       console.warn(sourceFile, lintResult.messages);
          |               ^
      152 |     }
      153 |
      154 |     const formattedOutput = await prettier.format(lintedOutput, prettierConfig);

      at warn (scripts/generateTypeScriptDefinitions.js:151:15)
      at scripts/generateTypeScriptDefinitions.js:239:11
          at async Promise.all (index 177)
      at generateTsDefsForJsGlobs (scripts/generateTypeScriptDefinitions.js:197:3)
      at generateApiSnapshots (scripts/generateApiSnapshots.js:79:3)
      at Object.<anonymous> (scripts/__tests__/api-snapshots-sync-test.js:17:5)

  buck-worker-tool: 1 snapshot(s) verified in 0.0s
  metro: 1 snapshot(s) verified in 0.0s
  metro-resolver: 1 snapshot(s) verified in 0.0s
  metro-source-map: 1 snapshot(s) verified in 0.0s
  metro-cache: 1 snapshot(s) verified in 0.0s
  metro-babel-transformer: 1 snapshot(s) verified in 0.0s
  ob1: 1 snapshot(s) verified in 0.0s
  metro-config: 1 snapshot(s) verified in 0.0s
  metro-core: 1 snapshot(s) verified in 0.0s
  metro-cache-key: 1 snapshot(s) verified in 0.0s
  metro-file-map: 1 snapshot(s) verified in 0.0s
  metro-transform-worker: 1 snapshot(s) verified in 0.0s
  metro-minify-terser: 1 snapshot(s) verified in 0.0s
  metro-transform-plugins: 1 snapshot(s) verified in 0.0s
  console.warn
    Skipped public entry points without generated TypeScript definitions:
      metro-babel-register "." (no packages/metro-babel-register/types/babel-register.d.ts)
      metro-runtime "./modules/asyncRequire" (no packages/metro-runtime/types/modules/asyncRequire.d.ts)
      metro-runtime "./modules/empty-module" (no packages/metro-runtime/types/modules/empty-module.d.ts)
      metro-runtime "./modules/HMRClient" (no packages/metro-runtime/types/modules/HMRClient.d.ts)
      metro-runtime "./modules/null-module" (no packages/metro-runtime/types/modules/null-module.d.ts)
      metro-runtime "./polyfills/require" (no packages/metro-runtime/types/polyfills/require.d.ts)
      metro-symbolicate "." (no exported API surface)

      135 |
      136 |   if (allSkipped.length > 0) {
    > 137 |     console.warn(
          |             ^
      138 |       'Skipped public entry points without generated TypeScript ' +
      139 |         `definitions:\n  ${allSkipped.join('\n  ')}`,
      140 |     );

      at warn (scripts/generateApiSnapshots.js:137:13)
      at Object.<anonymous> (scripts/__tests__/api-snapshots-sync-test.js:17:5)

Verified 14 public API snapshot(s) across Metro's OSS packages.
 PASS  scripts/__tests__/api-snapshots-sync-test.js (8.993 s)
  ✓ Public API snapshots are in sync (yarn run build-api-snapshots produces no changes) (8530 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        9.022 s, estimated 12 s
Ran all test suites matching /api-snapshots/i.
✨  Done in 9.76s.
```

## After
```
yarn jest api-snapshots
yarn run v1.22.22
$ /Users/robhogan/metro/node_modules/.bin/jest api-snapshots
 PASS  scripts/__tests__/api-snapshots-sync-test.js
  ✓ Public API snapshots are in sync (yarn run build-api-snapshots produces no changes) (3755 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        4.481 s, estimated 9 s
Ran all test suites matching /api-snapshots/i.
✨  Done in 4.91s.
```
@robhogan
robhogan marked this pull request as draft August 25, 2026 16:58
meta-codesync Bot pushed a commit that referenced this pull request Aug 25, 2026
…1878)

Summary:
## TS error
Currently, the generated `.d.ts` for this file causes a TS ESLint error:

https://github.com/react/metro/actions/runs/32859032114/job/97838112966

```
yarn run build-ts-defs && yarn lint
...
metro/packages/metro/types/lib/metroSchemeResolver.d.ts
  23:15  error  'metroSchemeResolver' is defined but only used as a type  typescript-eslint/no-unused-vars

✖ 1 problem (1 error, 0 warnings)

error Command failed with exit code 1.
```

This is ultimately flow-api-translator producing messy output, but we can workaround it in the mean time by using an anonymous default export.

## Windows paths handling

Additionally, CI fails on Windows because both of the new `metroSchemeResolver-test` and `createStaticCrawler-test` hardcode posix paths. Fix that with the usual normalisation pattern.

Pull Request resolved: #1878

Test Plan:
OSS CI is green on this PR.

 ---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/react/metro/pull/1878).
* #1877
* __->__ #1878

Reviewed By: Abbondanzo

Differential Revision: D117379756

Pulled By: vzaidman

fbshipit-source-id: 896b5dc06576523e37aceb111c42b892ca7f5e61
@robhogan
robhogan marked this pull request as ready for review August 26, 2026 07:07
@robhogan

Copy link
Copy Markdown
Collaborator Author

@copilot resolve the merge conflicts on this branch.

Co-authored-by: robhogan <2590098+robhogan@users.noreply.github.com>

Copilot AI commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts on this branch.

Resolved. The conflicts in scripts/generateApiSnapshots.js and scripts/generateTypeScriptDefinitions.js were merged, combining logger (from this branch) with mungeUnderscores (from main) in commit 66aa235.

@robhogan

Copy link
Copy Markdown
Collaborator Author

@vzaidman rebased and ready for re-import :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants