rsnext/packages/next-swc
Benjamin Woodruff 5017a41c75
feat(turbopack): Attempt to detect and warn about slow file IO (#66057)
We'd like to warn users if they have particularly slow file IO, so that they can correct the problem themselves, and don't send us reports of poor performance.

- Feature request: https://vercel.slack.com/archives/C03KAR5DCKC/p1716051650641529
- Tweet about how Bun does this: https://x.com/jarredsumner/status/1637549427677364224
- Bun implementation: 06a9aa80c3/src/install/install.zig (L3038)

**Why 100ms?** Bun used to use 10ms, found it too noisy, and switched to 100ms.

This benchmark should run non-blocking in the background and should not meaningfully slow down server startup (even on slow disks).

## Simulated Testing

I looked around and found https://github.com/schoentoon/slowpokefs/. It hasn't been updated in 10 years, but still seems to build fine.

In a nextjs project directory, turn `.next` into an artifically slow mount point:

```
fusermount -uz .next; rm -rf .next .next.real && mkdir .next .next.real && ~/slowpokefs/slowpokefs -m 50 -M 50 --no-slow-read -F .next.real .next
```

<img width="695" alt="Screenshot 2024-05-21 at 4 14 58 PM" src="https://github.com/vercel/next.js/assets/180404/217d7692-33cf-42b7-bbf7-5a530b9e0df1">

Run `pnpm dev --turbo` and see that the warning is generated.

## "Real World" Testing

The following tests are from a linux VM using virtiofs to connect to a 5400 RPM USB 2.0 HDD with APFS:

Only the .next is on an HDD (bind mount):
Otherwise idle disk: `4.86ms 4.44ms 5.31ms`
Otherwise busy disk (copying files): `69.34ms 53.75ms 25.12ms`

The whole project directory is on the HDD (more realistic):
Otherwise idle disk: `20.29ms 35.61ms 48.12ms`
Otherwise busy disk (copying files): `131.40ms 21.71ms 87.33ms`

Most of the time the threshold was not reached, but the 131.40ms test did trigger the warning!

Fixes PACK-3087
2024-05-23 09:52:33 -07:00
..
crates feat(turbopack): Attempt to detect and warn about slow file IO (#66057) 2024-05-23 09:52:33 -07:00
native Extract next-swc Rust code into its own package (#31635) 2021-11-21 12:59:56 +01:00
package.json v14.3.0-canary.79 2024-05-23 14:45:18 +00:00
README.md chore: fix some typos (#64276) 2024-04-10 04:04:52 +00:00
turbo.json next-swc-napi: Enable "plugin" feature by default (#66006) 2024-05-22 11:09:04 -07:00

@next/swc

This package is responsible for swc compilation customized for next.js

Development

Run tests

cargo test

# Update snapshots and fixtures for tests
UPDATE=1 cargo test

Format code before submitting code

cargo fmt

Build the binary to integrate with next.js

pnpm build-native

Build wasm bindings to integrate with next.js

pnpm build-wasm

napi bindings feature matrix

Due to platform differences napi bindings selectively enables supported features. See below tables for the currently enabled features.

arch\platform Linux(gnu) Linux(musl) Darwin Win32
ia32 a,b,d,e
x64 a,b,d,e,f a,b,d,e,f a,b,d,e,f a,b,d,e,f
aarch64 a,d,e,f a,d,e,f a,b,d,e,f a,b,c,e
  • a: turbo_tasks_malloc,
  • b: turbo_tasks_malloc_custom_allocator,
  • c: native-tls,
  • d: rustls-tls,
  • e: image-extended (webp)
  • f: plugin

Package hierarchies

@next/swc consist of multiple rust packages to enable features. See below for the high level hierarchies.

flowchart TD
    C(next-custom-transforms) --> A(napi)
    C(next-custom-transforms) --> B(wasm)
    D(next-core) --> A(napi)
    E(next-build) --> A(napi)
    F(next-api) --> A(napi)
    C(next-custom-transforms) --> D
    D(next-core) --> F(next-api)
    D(next-core) --> E(next-build)
  • next-custom-transforms: provides next-swc specific SWC transform visitors. Turbopack, and the plain next-swc bidnings (transform) use these transforms. Since this is a bottom package can be imported in any place (turbopack / next-swc / wasm), it is important package do not contain specific dependencies. For example, using Turbopack's VC in this package will cause build failures to wasm bindings.
  • next-core: Implements Turbopack features for the next.js core functionality. This is also the place where Turbopack-specific transform providers (implementing CustomTransformer) lives, which wraps swc's transformer in the next-custom-transforms.
  • next-api: Binding interface to the next.js provides a proper next.js functionality using next-core.
  • napi / wasm: The actual binding interfaces, napi for the node.js and wasm for the wasm. Note wasm bindings cannot import packages using turbopack's feature.

To add new swc transforms

  1. Implements a new visitor in next-custom-transforms. It is highly encouraged to use VisitMut instead of Fold for the performance reasons.
  2. Implements a new CustomTransformer under packages/next-swc/crates/next-core/src/next_shared/transforms to make Turbopack's ecma transform plugin, then adjust corresponding rules in packages/next-swc/crates/next-core/src/(next_client|next_server)/context.rs.