Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/actions/docker-build/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ inputs:
required: false
default: ""
type: string
plugin:
required: false
default: true
type: boolean

runs:
using: composite
Expand All @@ -46,7 +50,7 @@ runs:
echo "Corepack version: $(corepack --version)"
corepack enable

RUST_TARGET=${{ inputs.target }} pnpm build:binding:${{ inputs.profile }}
RUST_TARGET=${{ inputs.target }} ${{ inputs.plugin == 'false' && 'DISABLE_PLUGIN=1' || '' }} pnpm build:binding:${{ inputs.profile }}
${{ inputs.post }}
'
if [[ ! -n "$CARGO_HOME" ]]; then
Expand Down
16 changes: 14 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,18 @@ jobs:
skipable: ${{ needs.check-changed.outputs.changed != 'true' }}
full-install: false

test-wasm:
name: Test WASM
needs: [get-runner-labels, check-changed]
uses: ./.github/workflows/reusable-build.yml
with:
target: wasm32-wasip1-threads
profile: "ci"
runner: ${{ needs.get-runner-labels.outputs.LINUX_RUNNER_LABELS }}
skipable: ${{ needs.check-changed.outputs.changed != 'true' }}
full-install: false
test: false

cargo-deny:
name: Check license of dependencies
runs-on: ubuntu-latest
Expand Down Expand Up @@ -147,7 +159,7 @@ jobs:
- name: Lint js
if: steps.changes.outputs.src == 'true'
run: pnpm run lint-ci:js

- name: Prettier
if: steps.changes.outputs.src == 'true'
run: pnpm run format-ci:js
Expand All @@ -165,7 +177,7 @@ jobs:
echo "===================================="
pnpm build:js
pnpm api-extractor:ci

- name: Documentation coverage check
if: steps.changes.outputs.src == 'true'
run: pnpm doc-coverage
Expand Down
27 changes: 24 additions & 3 deletions .github/workflows/reusable-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -201,10 +201,33 @@ jobs:
- name: Upload artifact
id: upload-artifact
uses: ./.github/actions/artifact/upload
if: ${{ steps.check_cache.outputs.exists != 'true' && !inputs.skipable }}
if: ${{ inputs.target != 'wasm32-wasip1-threads' && steps.check_cache.outputs.exists != 'true' && !inputs.skipable }}
with:
name: bindings-${{ inputs.target }}
path: crates/node_binding/*.node
try-local-cache: ${{ inputs.profile == 'ci' }}
mv-when-local: true

# WASM
- name: Build wasm32-wasip1-threads with linux in Docker
if: ${{ inputs.target == 'wasm32-wasip1-threads' && steps.check_cache.outputs.exists != 'true' && !inputs.skipable }}
uses: ./.github/actions/docker-build
with:
image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian
target: ${{ inputs.target }}
profile: ${{ inputs.profile }}
plugin: false
pre: unset CC_x86_64_unknown_linux_gnu && unset CC # for jemallocator to compile

- name: Upload wasm artifact
id: upload-wasm-artifact
uses: ./.github/actions/artifact/upload
if: ${{ inputs.target == 'wasm32-wasip1-threads' && steps.check_cache.outputs.exists != 'true' && !inputs.skipable }}
with:
name: bindings-wasm32-wasi
path: crates/node_binding/rspack.wasm32-wasi.wasm
try-local-cache: ${{ inputs.profile == 'ci' }}
mv-when-local: true

e2e:
name: E2E Testing
Expand Down Expand Up @@ -359,8 +382,6 @@ jobs:
github-token: ${{ secrets.GITHUB_TOKEN }}
sha: ${{ github.sha }}



bench:
name: Bench
if: ${{ inputs.bench && !inputs.skipable }}
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ npm/**/*.node
!npm/darwin-arm64/
!npm/darwin-x64/
!npm/linux-x64-gnu/
!npm/wasm32-wasi
!npm/win32-x64-msvc/

# Precompiled config schema
Expand Down
27 changes: 5 additions & 22 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ indoc = { version = "2.0.5" }
insta = { version = "1.42.0" }
itertools = { version = "0.14.0" }
json = { version = "0.12.4" }
lightningcss = { version = "1.0.0-alpha.63" }
lightningcss = { version = "1.0.0-alpha.64" }
linked_hash_set = { version = "0.1.5" }
mimalloc = { version = "0.2.3", package = "mimalloc-rspack" }
mime_guess = { version = "2.0.5" }
Expand Down
3 changes: 2 additions & 1 deletion crates/node_binding/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/*.node
/*.node
/*.wasm
7 changes: 6 additions & 1 deletion crates/node_binding/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,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", "rt-multi-thread", "macros", "test-util", "parking_lot"] }
tokio = { workspace = true, features = ["rt", "macros", "test-util", "parking_lot"] }


rspack_loader_lightningcss = { workspace = true }
Expand Down Expand Up @@ -103,6 +103,11 @@ rspack_plugin_wasm = { workspace = true }
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"] }

rspack_tracing = { workspace = true, features = ["otel"] }


[build-dependencies]
napi-build = { workspace = true }
19 changes: 19 additions & 0 deletions crates/node_binding/binding.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,25 @@ switch (platform) {
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
}

if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) {
try {
nativeBinding = require('./rspack.wasi.cjs')
} catch (e) {
if (process.env.NAPI_RS_FORCE_WASI) {
loadError = e
}
}
if (!nativeBinding) {
try {
nativeBinding = require('@rspack/binding-wasm32-wasi')
} catch (e) {
if (process.env.NAPI_RS_FORCE_WASI) {
loadError = e
}
}
}
}

if (!nativeBinding) {
if (loadError) {
throw loadError
Expand Down
1 change: 1 addition & 0 deletions crates/node_binding/browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from '@rspack/binding-wasm32-wasi'
26 changes: 25 additions & 1 deletion crates/node_binding/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,39 @@
"repository": "web-infra-dev/rspack",
"devDependencies": {
"@napi-rs/cli": "3.0.0-alpha.73",
"@napi-rs/wasm-runtime": "^0.2.7",
"emnapi": "^1.3.1",
"typescript": "^5.7.3"
},
"napi": {
"binaryName": "rspack"
"binaryName": "rspack",
"packageName": "@rspack/binding",
"targets": [
"x86_64-apple-darwin",
"x86_64-pc-windows-msvc",
"x86_64-unknown-linux-gnu",
"x86_64-unknown-linux-musl",
"x86_64-unknown-freebsd",
"i686-pc-windows-msvc",
"armv7-unknown-linux-gnueabihf",
"aarch64-unknown-linux-gnu",
"aarch64-apple-darwin",
"aarch64-unknown-linux-musl",
"aarch64-pc-windows-msvc",
"wasm32-wasip1-threads"
],
"wasm": {
"initialMemory": 16384,
"browser": {
"fs": true
}
}
},
"optionalDependencies": {
"@rspack/binding-darwin-arm64": "workspace:*",
"@rspack/binding-darwin-x64": "workspace:*",
"@rspack/binding-linux-x64-gnu": "workspace:*",
"@rspack/binding-wasm32-wasi": "workspace:*",
"@rspack/binding-win32-x64-msvc": "workspace:*"
}
}
94 changes: 94 additions & 0 deletions crates/node_binding/rspack.wasi-browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import {
instantiateNapiModuleSync as __emnapiInstantiateNapiModuleSync,
getDefaultContext as __emnapiGetDefaultContext,
WASI as __WASI,
createOnMessage as __wasmCreateOnMessageForFsProxy,
} from '@napi-rs/wasm-runtime'
import { memfs } from '@napi-rs/wasm-runtime/fs'
import __wasmUrl from './rspack.wasm32-wasi.wasm?url'

export const { fs: __fs, vol: __volume } = memfs()

const __wasi = new __WASI({
version: 'preview1',
fs: __fs,
preopens: {
'/': '/',
},
})

const __emnapiContext = __emnapiGetDefaultContext()

const __sharedMemory = new WebAssembly.Memory({
initial: 16384,
maximum: 65536,
shared: true,
})

const __wasmFile = await fetch(__wasmUrl).then((res) => res.arrayBuffer())

const {
instance: __napiInstance,
module: __wasiModule,
napiModule: __napiModule,
} = __emnapiInstantiateNapiModuleSync(__wasmFile, {
context: __emnapiContext,
asyncWorkPoolSize: 4,
wasi: __wasi,
onCreateWorker() {
const worker = new Worker(new URL('./wasi-worker-browser.mjs', import.meta.url), {
type: 'module',
})
worker.addEventListener('message', __wasmCreateOnMessageForFsProxy(__fs))

return worker
},
overwriteImports(importObject) {
importObject.env = {
...importObject.env,
...importObject.napi,
...importObject.emnapi,
memory: __sharedMemory,
}
return importObject
},
beforeInit({ instance }) {
for (const name of Object.keys(instance.exports)) {
if (name.startsWith('__napi_register__')) {
instance.exports[name]()
}
}
},
})
export const Dependency = __napiModule.exports.Dependency
export const EntryDataDto = __napiModule.exports.EntryDataDto
export const EntryDataDTO = __napiModule.exports.EntryDataDTO
export const EntryDependency = __napiModule.exports.EntryDependency
export const EntryOptionsDto = __napiModule.exports.EntryOptionsDto
export const EntryOptionsDTO = __napiModule.exports.EntryOptionsDTO
export const JsChunk = __napiModule.exports.JsChunk
export const JsChunkGraph = __napiModule.exports.JsChunkGraph
export const JsChunkGroup = __napiModule.exports.JsChunkGroup
export const JsCompilation = __napiModule.exports.JsCompilation
export const JsCompiler = __napiModule.exports.JsCompiler
export const JsContextModuleFactoryAfterResolveData = __napiModule.exports.JsContextModuleFactoryAfterResolveData
export const JsContextModuleFactoryBeforeResolveData = __napiModule.exports.JsContextModuleFactoryBeforeResolveData
export const JsDependencies = __napiModule.exports.JsDependencies
export const JsDependenciesBlock = __napiModule.exports.JsDependenciesBlock
export const JsEntries = __napiModule.exports.JsEntries
export const JsExportsInfo = __napiModule.exports.JsExportsInfo
export const JsModule = __napiModule.exports.JsModule
export const JsModuleGraph = __napiModule.exports.JsModuleGraph
export const JsModuleGraphConnection = __napiModule.exports.JsModuleGraphConnection
export const JsResolver = __napiModule.exports.JsResolver
export const JsResolverFactory = __napiModule.exports.JsResolverFactory
export const JsStats = __napiModule.exports.JsStats
export const RawExternalItemFnCtx = __napiModule.exports.RawExternalItemFnCtx
export const BuiltinPluginName = __napiModule.exports.BuiltinPluginName
export const cleanupGlobalTrace = __napiModule.exports.cleanupGlobalTrace
export const formatDiagnostic = __napiModule.exports.formatDiagnostic
export const JsLoaderState = __napiModule.exports.JsLoaderState
export const JsRspackSeverity = __napiModule.exports.JsRspackSeverity
export const RawRuleSetConditionType = __napiModule.exports.RawRuleSetConditionType
export const registerGlobalTrace = __napiModule.exports.registerGlobalTrace
export const RegisterJsTapKind = __napiModule.exports.RegisterJsTapKind
Loading
Loading