diff --git a/.cargo/config.toml b/.cargo/config.toml index bba8420a7806..a23f330880d6 100755 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -55,6 +55,10 @@ rustflags = [ "-C", "link-args=/DEFAULTLIB:ucrt.lib" ] + +[target.wasm32-wasip1-threads] +rustflags = ["--cfg", "tokio_unstable"] + [target.x86_64-pc-windows-msvc] rustflags = ["-C", "target-feature=+crt-static"] [target.i686-pc-windows-msvc] diff --git a/Cargo.toml b/Cargo.toml index d720cbd5b7ec..d7a296abb159 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,7 +76,7 @@ smol_str = { version = "0.3.0" } stacker = { version = "0.1.17" } sugar_path = { version = "1.2.0", features = ["cached_current_dir"] } syn = { version = "2.0.95" } -tokio = { version = "1.42.0", features = ["rt-multi-thread", "rt"] } +tokio = { version = "1.42.0", features = ["rt", "rt-multi-thread"] } # don't include debug & trace in release binary to save release binary size tracing = { version = "0.1.41", features = ["max_level_trace", "release_max_level_info"] } tracing-subscriber = { version = "0.3.19" } @@ -387,6 +387,14 @@ lto = "thin" split-debuginfo = "off" strip = false +[profile.release-wasi] +codegen-units = 16 +debug = 'full' +inherits = "release" +lto = "thin" +opt-level = "s" +strip = "none" + # the following lints rules are from https://github.com/biomejs/biome/blob/4bd3d6f09642952ee14445ed56af81a73796cea1/Cargo.toml#L7C1-L75C1 [workspace.lints.rust] diff --git a/crates/node_binding/Cargo.toml b/crates/node_binding/Cargo.toml index b4a6b44bd0f0..2d7c5a00feff 100644 --- a/crates/node_binding/Cargo.toml +++ b/crates/node_binding/Cargo.toml @@ -55,7 +55,7 @@ rustc-hash = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } swc_core = { workspace = true, default-features = false, features = ["ecma_transforms_react"] } -tokio = { workspace = true, features = ["rt", "macros", "test-util", "parking_lot", "tracing"] } +tokio = { workspace = true, features = ["rt", "rt-multi-thread", "macros", "test-util", "tracing"] } rayon = { workspace = true } rspack_loader_lightningcss = { workspace = true } @@ -103,7 +103,7 @@ rspack_plugin_web_worker_template = { workspace = true } rspack_plugin_worker = { workspace = true } [target.'cfg(not(target_family = "wasm"))'.dependencies] -tokio = { workspace = true, features = ["rt-multi-thread"] } +tokio = { workspace = true, features = ["parking_lot"] } rspack_tracing = { workspace = true, features = ["otel"] } diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index b2f8f49d4581..3d469963ac43 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -2510,6 +2510,22 @@ export interface RegisterJsTaps { registerRsdoctorPluginAssetsTaps: (stages: Array) => Array<{ function: ((arg: JsRsdoctorAssetPatch) => Promise); stage: number; }> } +/** + * Shutdown the tokio runtime manually. + * + * This is required for the wasm target with `tokio_unstable` cfg. + * In the wasm runtime, the `park` threads will hang there until the tokio::Runtime is shutdown. + */ +export declare function shutdownAsyncRuntime(): void + +/** + * Start the async runtime manually. + * + * This is required when the async runtime is shutdown manually. + * Usually it's used in test. + */ +export declare function startAsyncRuntime(): void + export interface ThreadsafeNodeFS { writeFile: (name: string, content: Buffer) => Promise removeFile: (name: string) => Promise diff --git a/crates/node_binding/build.rs b/crates/node_binding/build.rs index bbfc9e4b9e1e..f30eebcbda25 100644 --- a/crates/node_binding/build.rs +++ b/crates/node_binding/build.rs @@ -1,3 +1,4 @@ fn main() { + println!("cargo::rustc-check-cfg=cfg(tokio_unstable)"); napi_build::setup(); } diff --git a/crates/node_binding/package.json b/crates/node_binding/package.json index 4593abb45eef..5948467e6998 100644 --- a/crates/node_binding/package.json +++ b/crates/node_binding/package.json @@ -18,7 +18,8 @@ "build:ci": "node scripts/build.js --profile ci", "build:profiling": "node scripts/build.js --profile profiling", "build:release": "node scripts/build.js --profile release", - "build:wasm": "DISABLE_PLUGIN=1 RUST_TARGET=wasm32-wasip1-threads node scripts/build.js", + "build:dev:wasm": "DISABLE_PLUGIN=1 RUST_TARGET=wasm32-wasip1-threads node scripts/build.js", + "build:release:wasm": "DISABLE_PLUGIN=1 RUST_TARGET=wasm32-wasip1-threads node scripts/build.js --profile release-wasi", "move-binding": "node scripts/move-binding", "test": "tsc -p tsconfig.type-test.json" }, diff --git a/crates/node_binding/rspack.wasi-browser.js b/crates/node_binding/rspack.wasi-browser.js index 5bef411f5aae..d2f977a979fe 100644 --- a/crates/node_binding/rspack.wasi-browser.js +++ b/crates/node_binding/rspack.wasi-browser.js @@ -96,3 +96,5 @@ export const JsRspackSeverity = __napiModule.exports.JsRspackSeverity export const RawRuleSetConditionType = __napiModule.exports.RawRuleSetConditionType export const registerGlobalTrace = __napiModule.exports.registerGlobalTrace export const RegisterJsTapKind = __napiModule.exports.RegisterJsTapKind +export const shutdownAsyncRuntime = __napiModule.exports.shutdownAsyncRuntime +export const startAsyncRuntime = __napiModule.exports.startAsyncRuntime diff --git a/crates/node_binding/rspack.wasi.cjs b/crates/node_binding/rspack.wasi.cjs index e8c604e1940c..8cb7995d3fbe 100644 --- a/crates/node_binding/rspack.wasi.cjs +++ b/crates/node_binding/rspack.wasi.cjs @@ -121,3 +121,5 @@ module.exports.JsRspackSeverity = __napiModule.exports.JsRspackSeverity module.exports.RawRuleSetConditionType = __napiModule.exports.RawRuleSetConditionType module.exports.registerGlobalTrace = __napiModule.exports.registerGlobalTrace module.exports.RegisterJsTapKind = __napiModule.exports.RegisterJsTapKind +module.exports.shutdownAsyncRuntime = __napiModule.exports.shutdownAsyncRuntime +module.exports.startAsyncRuntime = __napiModule.exports.startAsyncRuntime diff --git a/crates/node_binding/src/lib.rs b/crates/node_binding/src/lib.rs index 2f93da2c5f0b..4f47d8d4da53 100644 --- a/crates/node_binding/src/lib.rs +++ b/crates/node_binding/src/lib.rs @@ -448,3 +448,23 @@ pub fn cleanup_global_trace() { *state = TraceState::Off; }); } + +#[napi] +/// Shutdown the tokio runtime manually. +/// +/// This is required for the wasm target with `tokio_unstable` cfg. +/// In the wasm runtime, the `park` threads will hang there until the tokio::Runtime is shutdown. +pub fn shutdown_async_runtime() { + #[cfg(all(target_family = "wasm", tokio_unstable))] + napi::bindgen_prelude::shutdown_async_runtime(); +} + +#[napi] +/// Start the async runtime manually. +/// +/// This is required when the async runtime is shutdown manually. +/// Usually it's used in test. +pub fn start_async_runtime() { + #[cfg(all(target_family = "wasm", tokio_unstable))] + napi::bindgen_prelude::start_async_runtime(); +} diff --git a/crates/rspack_fs/src/native_fs.rs b/crates/rspack_fs/src/native_fs.rs index 05a282901fdd..2c52b4ce3ff0 100644 --- a/crates/rspack_fs/src/native_fs.rs +++ b/crates/rspack_fs/src/native_fs.rs @@ -224,8 +224,31 @@ impl ReadableFileSystem for NativeFileSystem { } fn canonicalize(&self, path: &Utf8Path) -> Result { - let path = dunce::canonicalize(path)?; - Ok(path.assert_utf8()) + // Comes from rspack_resolver + use std::path::Component; + let mut path_buf = path.to_path_buf(); + loop { + let link = fs::read_link(&path_buf)?; + path_buf.pop(); + for component in link.components() { + match component { + Component::ParentDir => { + path_buf.pop(); + } + Component::Normal(seg) => { + path_buf.push(seg.to_string_lossy().trim_end_matches('\0')); + } + Component::RootDir => { + path_buf = Utf8PathBuf::from("/"); + } + Component::CurDir | Component::Prefix(_) => {} + } + } + if !fs::symlink_metadata(&path_buf)?.is_symlink() { + break; + } + } + Ok(path_buf) } async fn async_read(&self, file: &Utf8Path) -> Result> { diff --git a/crates/rspack_regex/src/napi.rs b/crates/rspack_regex/src/napi.rs index 09606fd7341b..2bac50683a78 100644 --- a/crates/rspack_regex/src/napi.rs +++ b/crates/rspack_regex/src/napi.rs @@ -28,8 +28,8 @@ impl FromNapiValue for RspackRegex { let global = env.get_global()?; let object_prototype_to_string = global .get_named_property_unchecked::("Object")? - .get_named_property::("prototype")? - .get_named_property::("toString")?; + .get_named_property_unchecked::("prototype")? + .get_named_property_unchecked::("toString")?; let js_string = object_prototype_to_string .apply(&js_object, env.get_undefined()?.into_unknown())? diff --git a/package.json b/package.json index f1a048ace79e..a688361de860 100644 --- a/package.json +++ b/package.json @@ -12,12 +12,14 @@ "check-dependency-version": "pnpx check-dependency-version-consistency@5 . --ignore-dep chalk --ignore-package webpack-test --ignore-package webpack-examples", "build:js": "pnpm --filter \"@rspack/core\" build:force && pnpm --parallel --filter \"@rspack/*\" --filter \"create-rspack\" --filter \"!@rspack/core\" build", "build:cli:dev": "npm run build:binding:dev && npm run build:js", + "build:cli:dev:wasm": "pnpm --filter @rspack/binding build:dev:wasm && npm run build:js", "build:cli:release": "npm run build:binding:release && npm run build:js", "build:cli:release:all": "pnpm --filter @rspack/binding build:release:all && npm run build:js", "build:cli:release:arm64": "pnpm --filter @rspack/binding build:release:arm64 && npm run build:js", "build:cli:release:x64": "pnpm --filter @rspack/binding build:release:x64 && npm run build:js", "build:cli:release:linux": "pnpm --filter @rspack/binding build:release:linux && npm run build:js", "build:cli:release:win": "pnpm --filter @rspack/binding build:release:win && npm run build:js", + "build:cli:release:wasm": "pnpm --filter @rspack/binding build:release:wasm && npm run build:js", "test:js": "pnpm -r run test", "format:rs": "cargo fmt --all", "format:js": "pnpm run format-ci:js --write",