Skip to content

Commit

Permalink
Remove wasm target (vercel#57437)
Browse files Browse the repository at this point in the history
This PR removes the wasm target for the next-swc build for the next major version.  The main motivation is that Turbopack does not support targeting wasm yet, and it would be a significant amount of work to add. We plan to make Turbopack the default zero-config experience in a minor version, possibly before we are able to support a wasm target, so we need to make this breaking change now. We also plan to make more improvements to the webpack experience with shared Rust code, which we have so far been blocked from implementing because of the current wasm restrictions. We would like to support a wasm target again in the future, but cannot say at this time when that would be.


Closes WEB-1865
  • Loading branch information
padmaia authored Oct 26, 2023
1 parent 6b18f39 commit f412c8a
Show file tree
Hide file tree
Showing 5 changed files with 14 additions and 130 deletions.
58 changes: 0 additions & 58 deletions .github/workflows/build_and_deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -340,65 +340,12 @@ jobs:
name: turbo run summary
path: .turbo/runs

build-wasm:
strategy:
matrix:
target: [web, nodejs]

runs-on:
- 'self-hosted'
- 'linux'
- 'x64'
- 'metal'

steps:
- uses: actions/checkout@v3

- name: Setup node
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_LTS_VERSION }}
check-latest: true
- run: corepack enable

- name: Install Rust
uses: ./.github/actions/setup-rust
with:
targets: wasm32-unknown-unknown

- run: npm i -g turbo@${{ env.TURBO_VERSION }}

- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh

- name: normalize versions
run: node scripts/normalize-version-bump.js

- name: Build
run: turbo run build-wasm -vvv --remote-cache-timeout 90 --summarize -- --target ${{ matrix.target }} --features tracing/release_max_level_info

- name: Add target to folder name
run: '[[ -d "packages/next-swc/crates/wasm/pkg" ]] && mv packages/next-swc/crates/wasm/pkg packages/next-swc/crates/wasm/pkg-${{ matrix.target }} || ls packages/next-swc/crates/wasm'

- name: Upload turbo summary artifact
uses: actions/upload-artifact@v3
with:
name: turbo run summary
path: .turbo/runs

- name: Upload swc artifact
uses: actions/upload-artifact@v3
with:
name: wasm-binaries
path: packages/next-swc/crates/wasm/pkg-*

publishRelease:
if: ${{ needs.build.outputs.isRelease == 'true' }}
name: Potentially publish release
runs-on: ubuntu-latest
needs:
- build
- build-wasm
- build-native
permissions:
contents: write
Expand Down Expand Up @@ -429,11 +376,6 @@ jobs:
name: next-swc-binaries
path: packages/next-swc/native

- uses: actions/download-artifact@v3
with:
name: wasm-binaries
path: packages/next-swc/crates/wasm

- run: npm i -g npm@9.6.7 # need latest version for provenance (pinning to avoid bugs)
- run: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc
- run: ./scripts/publish-native.js
Expand Down
17 changes: 8 additions & 9 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -151,14 +151,14 @@ jobs:
afterBuild: RUST_BACKTRACE=0 NEXT_EXTERNAL_TESTS_FILTERS="$(pwd)/test/turbopack-tests-manifest.json" TURBOPACK=1 node run-tests.js --timings -g ${{ matrix.group }}/5 -c ${TEST_CONCURRENCY} --type integration
secrets: inherit

test-next-swc-wasm:
name: test next-swc wasm
needs: ['build-native', 'build-next']
uses: ./.github/workflows/build_reusable.yml
with:
skipForDocsOnly: 'yes'
afterBuild: rustup target add wasm32-unknown-unknown && curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh && node ./scripts/normalize-version-bump.js && turbo run build-wasm -- --target nodejs --features tracing/release_max_level_info && git checkout . && mv packages/next-swc/crates/wasm/pkg packages/next-swc/crates/wasm/pkg-nodejs && node ./scripts/setup-wasm.mjs && NEXT_TEST_MODE=start TEST_WASM=true node run-tests.js test/production/pages-dir/production/test/index.test.ts test/e2e/streaming-ssr/index.test.ts
secrets: inherit
# test-next-swc-wasm:
# name: test next-swc wasm
# needs: ['build-native', 'build-next']
# uses: ./.github/workflows/build_reusable.yml
# with:
# skipForDocsOnly: 'yes'
# afterBuild: rustup target add wasm32-unknown-unknown && curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh && node ./scripts/normalize-version-bump.js && turbo run build-wasm -- --target nodejs --features tracing/release_max_level_info && git checkout . && mv packages/next-swc/crates/wasm/pkg packages/next-swc/crates/wasm/pkg-nodejs && node ./scripts/setup-wasm.mjs && NEXT_TEST_MODE=start TEST_WASM=true node run-tests.js test/production/pages-dir/production/test/index.test.ts test/e2e/streaming-ssr/index.test.ts
# secrets: inherit

test-unit:
name: test unit
Expand Down Expand Up @@ -258,7 +258,6 @@ jobs:
'test-cargo-integration',
'test-cargo-bench',
'rust-check',
'test-next-swc-wasm',
'test-turbopack-dev',
'test-turbopack-integration',
]
Expand Down
2 changes: 0 additions & 2 deletions contributing/core/building.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,4 @@ pnpm build

By default, the latest canary of the `next-swc` binaries will be installed and used. If you are actively working on Rust code or you need to test out the most recent Rust code that hasn't been published as a canary yet, you can [install Rust](https://www.rust-lang.org/tools/install) and run `pnpm --filter=@next/swc build-native`.

If you want to test out the wasm build locally, you will need to [install wasm-pack](https://rustwasm.github.io/wasm-pack/installer/). Run `pnpm --filter=@next/swc build-wasm --target <wasm_target>` to build and `node ./scripts/setup-wasm.mjs` to copy it into your `node_modules`. Run next with `NODE_OPTIONS='--no-addons'` to force it to use the wasm binary.

If you need to clean the project for any reason, use `pnpm clean`.
1 change: 0 additions & 1 deletion docs/04-architecture/nextjs-compiler.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ We chose to build on SWC for a few reasons:

- **Extensibility:** SWC can be used as a Crate inside Next.js, without having to fork the library or workaround design constraints.
- **Performance:** We were able to achieve ~3x faster Fast Refresh and ~5x faster builds in Next.js by switching to SWC, with more room for optimization still in progress.
- **WebAssembly:** Rust's support for WASM is essential for supporting all possible platforms and taking Next.js development everywhere.
- **Community:** The Rust community and ecosystem are amazing and still growing.

## Supported Features
Expand Down
66 changes: 6 additions & 60 deletions packages/next/src/build/swc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const infoLog = (...args: any[]) => {
* Based on napi-rs's target triples, returns triples that have corresponding next-swc binaries.
*/
export const getSupportedArchTriples: () => Record<string, any> = () => {
const { darwin, win32, linux, freebsd, android } = platformArchTriples
const { darwin, win32, linux } = platformArchTriples

return {
darwin,
Expand All @@ -48,16 +48,6 @@ export const getSupportedArchTriples: () => Record<string, any> = () => {
(triple: { abi: string }) => triple.abi !== 'gnux32'
),
arm64: linux.arm64,
// This target is being deprecated, however we keep it in `knownDefaultWasmFallbackTriples` for now
arm: linux.arm,
},
// Below targets are being deprecated, however we keep it in `knownDefaultWasmFallbackTriples` for now
freebsd: {
x64: freebsd.x64,
},
android: {
arm64: android.arm64,
arm: android.arm,
},
}
}
Expand All @@ -77,7 +67,7 @@ const triples = (() => {

if (rawTargetTriple) {
Log.warn(
`Trying to load next-swc for target triple ${rawTargetTriple}, but there next-swc does not have native bindings support`
`Trying to load next-swc for target triple ${rawTargetTriple}, but this target is not supported`
)
} else {
Log.warn(
Expand Down Expand Up @@ -107,21 +97,6 @@ function checkVersionMismatch(pkgData: any) {
}
}

// These are the platforms we'll try to load wasm bindings first,
// only try to load native bindings if loading wasm binding somehow fails.
// Fallback to native binding is for migration period only,
// once we can verify loading-wasm-first won't cause visible regressions,
// we'll not include native bindings for these platform at all.
const knownDefaultWasmFallbackTriples = [
'x86_64-unknown-freebsd',
'aarch64-linux-android',
'arm-linux-androideabi',
'armv7-unknown-linux-gnueabihf',
'i686-pc-windows-msvc',
// WOA targets are TBD, while current userbase is small we may support it in the future
//'aarch64-pc-windows-msvc',
]

// The last attempt's error code returned when cjs require to native bindings fails.
// If node.js throws an error without error code, this should be `unknown` instead of undefined.
// For the wasm-first targets (`knownDefaultWasmFallbackTriples`) this will be `unsupported_target`.
Expand Down Expand Up @@ -201,21 +176,6 @@ export async function loadBindings(): Promise<Binding> {
}

let attempts: any[] = []
const disableWasmFallback = process.env.NEXT_DISABLE_SWC_WASM
const shouldLoadWasmFallbackFirst =
!disableWasmFallback &&
triples.some(
(triple: any) =>
!!triple?.raw && knownDefaultWasmFallbackTriples.includes(triple.raw)
)

if (shouldLoadWasmFallbackFirst) {
lastNativeBindingsLoadErrorCode = 'unsupported_target'
const fallbackBindings = await tryLoadWasmWithFallback(attempts)
if (fallbackBindings) {
return resolve(fallbackBindings)
}
}

// Trickle down loading `fallback` bindings:
//
Expand All @@ -224,7 +184,6 @@ export async function loadBindings(): Promise<Binding> {
// that host system where generated package lock is not matching to the guest system running on, try to manually
// download corresponding target triple and load it. This won't be triggered if native bindings are failed to load
// with other reasons than `ERR_MODULE_NOT_FOUND`.
// - Lastly, falls back to wasm binding where possible.
try {
return resolve(loadNative())
} catch (a) {
Expand All @@ -242,15 +201,7 @@ export async function loadBindings(): Promise<Binding> {
attempts = attempts.concat(a)
}

// For these platforms we already tried to load wasm and failed, skip reattempt
if (!shouldLoadWasmFallbackFirst && !disableWasmFallback) {
const fallbackBindings = await tryLoadWasmWithFallback(attempts)
if (fallbackBindings) {
return resolve(fallbackBindings)
}
}

logLoadFailure(attempts, true)
logLoadFailure(attempts)
})
return pendingBindings
}
Expand Down Expand Up @@ -279,6 +230,8 @@ async function tryLoadNativeWithFallback(attempts: Array<string>) {
return undefined
}

// We may end up using this function in the future if/when we support wasm builds again
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async function tryLoadWasmWithFallback(attempts: any) {
try {
let bindings = await loadWasm('')
Expand Down Expand Up @@ -331,18 +284,12 @@ function loadBindingsSync() {
attempts = attempts.concat(a)
}

// we can leverage the wasm bindings if they are already
// loaded
if (wasmBindings) {
return wasmBindings
}

logLoadFailure(attempts)
}

let loggingLoadFailure = false

function logLoadFailure(attempts: any, triedWasm = false) {
function logLoadFailure(attempts: any) {
// make sure we only emit the event and log the failure once
if (loggingLoadFailure) return
loggingLoadFailure = true
Expand All @@ -353,7 +300,6 @@ function logLoadFailure(attempts: any, triedWasm = false) {

// @ts-expect-error TODO: this event has a wrong type.
eventSwcLoadFailure({
wasm: triedWasm ? 'failed' : undefined,
nativeBindingsErrorCode: lastNativeBindingsLoadErrorCode,
})
.then(() => lockfilePatchPromise.cur || Promise.resolve())
Expand Down

0 comments on commit f412c8a

Please sign in to comment.