Turobpack: Next.rs API (part 1) (#52259)
### What? Creates a NAPI api for Next.rs to be used in Next.js ### Why? ### How? Co-authored-by: Alex Kirszenberg <1621758+alexkirsz@users.noreply.github.com>
This commit is contained in:
parent
88084e6b7a
commit
ca1129c463
32 changed files with 2206 additions and 112 deletions
88
Cargo.lock
generated
88
Cargo.lock
generated
|
@ -412,7 +412,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "auto-hash-map"
|
name = "auto-hash-map"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
@ -3367,6 +3367,23 @@ version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
|
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "next-api"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"futures",
|
||||||
|
"indexmap",
|
||||||
|
"next-core",
|
||||||
|
"once_cell",
|
||||||
|
"serde",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
|
"turbo-tasks",
|
||||||
|
"turbopack-binding",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "next-build"
|
name = "next-build"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -3519,6 +3536,7 @@ dependencies = [
|
||||||
"napi",
|
"napi",
|
||||||
"napi-build",
|
"napi-build",
|
||||||
"napi-derive",
|
"napi-derive",
|
||||||
|
"next-api",
|
||||||
"next-build",
|
"next-build",
|
||||||
"next-core",
|
"next-core",
|
||||||
"next-dev",
|
"next-dev",
|
||||||
|
@ -3581,7 +3599,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "node-file-trace"
|
name = "node-file-trace"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -7241,7 +7259,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbo-tasks"
|
name = "turbo-tasks"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"auto-hash-map",
|
"auto-hash-map",
|
||||||
|
@ -7272,7 +7290,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbo-tasks-build"
|
name = "turbo-tasks-build"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cargo-lock",
|
"cargo-lock",
|
||||||
|
@ -7284,7 +7302,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbo-tasks-bytes"
|
name = "turbo-tasks-bytes"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
@ -7299,7 +7317,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbo-tasks-env"
|
name = "turbo-tasks-env"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"dotenvs",
|
"dotenvs",
|
||||||
|
@ -7313,7 +7331,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbo-tasks-fetch"
|
name = "turbo-tasks-fetch"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
@ -7330,7 +7348,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbo-tasks-fs"
|
name = "turbo-tasks-fs"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"auto-hash-map",
|
"auto-hash-map",
|
||||||
|
@ -7360,7 +7378,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbo-tasks-hash"
|
name = "turbo-tasks-hash"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base16",
|
"base16",
|
||||||
"hex",
|
"hex",
|
||||||
|
@ -7372,7 +7390,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbo-tasks-macros"
|
name = "turbo-tasks-macros"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"convert_case 0.6.0",
|
"convert_case 0.6.0",
|
||||||
|
@ -7386,7 +7404,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbo-tasks-macros-shared"
|
name = "turbo-tasks-macros-shared"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -7396,7 +7414,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbo-tasks-malloc"
|
name = "turbo-tasks-malloc"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"mimalloc",
|
"mimalloc",
|
||||||
]
|
]
|
||||||
|
@ -7404,7 +7422,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbo-tasks-memory"
|
name = "turbo-tasks-memory"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"auto-hash-map",
|
"auto-hash-map",
|
||||||
|
@ -7427,7 +7445,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbo-tasks-testing"
|
name = "turbo-tasks-testing"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"auto-hash-map",
|
"auto-hash-map",
|
||||||
|
@ -7440,7 +7458,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbopack"
|
name = "turbopack"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-recursion",
|
"async-recursion",
|
||||||
|
@ -7470,7 +7488,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbopack-bench"
|
name = "turbopack-bench"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"chromiumoxide",
|
"chromiumoxide",
|
||||||
|
@ -7500,7 +7518,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbopack-binding"
|
name = "turbopack-binding"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"auto-hash-map",
|
"auto-hash-map",
|
||||||
"mdxjs",
|
"mdxjs",
|
||||||
|
@ -7542,7 +7560,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbopack-build"
|
name = "turbopack-build"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
@ -7562,7 +7580,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbopack-cli-utils"
|
name = "turbopack-cli-utils"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap 4.1.11",
|
"clap 4.1.11",
|
||||||
|
@ -7586,7 +7604,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbopack-core"
|
name = "turbopack-core"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
@ -7614,7 +7632,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbopack-create-test-app"
|
name = "turbopack-create-test-app"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap 4.1.11",
|
"clap 4.1.11",
|
||||||
|
@ -7627,7 +7645,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbopack-css"
|
name = "turbopack-css"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
@ -7649,7 +7667,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbopack-dev"
|
name = "turbopack-dev"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
@ -7673,7 +7691,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbopack-dev-server"
|
name = "turbopack-dev-server"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-compression",
|
"async-compression",
|
||||||
|
@ -7709,7 +7727,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbopack-ecmascript"
|
name = "turbopack-ecmascript"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
@ -7742,7 +7760,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbopack-ecmascript-plugins"
|
name = "turbopack-ecmascript-plugins"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
@ -7765,7 +7783,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbopack-ecmascript-runtime"
|
name = "turbopack-ecmascript-runtime"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"indoc",
|
"indoc",
|
||||||
|
@ -7782,7 +7800,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbopack-env"
|
name = "turbopack-env"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
@ -7798,7 +7816,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbopack-image"
|
name = "turbopack-image"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64 0.21.0",
|
"base64 0.21.0",
|
||||||
|
@ -7818,7 +7836,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbopack-json"
|
name = "turbopack-json"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -7833,7 +7851,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbopack-mdx"
|
name = "turbopack-mdx"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"mdxjs",
|
"mdxjs",
|
||||||
|
@ -7848,7 +7866,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbopack-node"
|
name = "turbopack-node"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-stream",
|
"async-stream",
|
||||||
|
@ -7883,7 +7901,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbopack-static"
|
name = "turbopack-static"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -7899,7 +7917,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbopack-swc-utils"
|
name = "turbopack-swc-utils"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"swc_core",
|
"swc_core",
|
||||||
"turbo-tasks",
|
"turbo-tasks",
|
||||||
|
@ -7910,7 +7928,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "turbopack-test-utils"
|
name = "turbopack-test-utils"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.2#4022f2b0e5bf6183b813f3ff32267d24f058cc82"
|
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
|
|
@ -5,6 +5,7 @@ members = [
|
||||||
"packages/next-swc/crates/core",
|
"packages/next-swc/crates/core",
|
||||||
"packages/next-swc/crates/napi",
|
"packages/next-swc/crates/napi",
|
||||||
"packages/next-swc/crates/wasm",
|
"packages/next-swc/crates/wasm",
|
||||||
|
"packages/next-swc/crates/next-api",
|
||||||
"packages/next-swc/crates/next-build",
|
"packages/next-swc/crates/next-build",
|
||||||
"packages/next-swc/crates/next-core",
|
"packages/next-swc/crates/next-core",
|
||||||
"packages/next-swc/crates/next-dev",
|
"packages/next-swc/crates/next-dev",
|
||||||
|
@ -26,6 +27,7 @@ lto = true
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
# Workspace crates
|
# Workspace crates
|
||||||
|
next-api = { path = "packages/next-swc/crates/next-api", default-features = false }
|
||||||
next-build = { path = "packages/next-swc/crates/next-build", default-features = false }
|
next-build = { path = "packages/next-swc/crates/next-build", default-features = false }
|
||||||
next-core = { path = "packages/next-swc/crates/next-core", default-features = false }
|
next-core = { path = "packages/next-swc/crates/next-core", default-features = false }
|
||||||
next-dev = { path = "packages/next-swc/crates/next-dev", default-features = false, features = [
|
next-dev = { path = "packages/next-swc/crates/next-dev", default-features = false, features = [
|
||||||
|
@ -42,11 +44,11 @@ swc_core = { version = "0.79.13" }
|
||||||
testing = { version = "0.33.20" }
|
testing = { version = "0.33.20" }
|
||||||
|
|
||||||
# Turbo crates
|
# Turbo crates
|
||||||
turbopack-binding = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230713.2" }
|
turbopack-binding = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230713.3" }
|
||||||
# [TODO]: need to refactor embed_directory! macro usages, as well as resolving turbo_tasks::function, macros..
|
# [TODO]: need to refactor embed_directory! macro usages, as well as resolving turbo_tasks::function, macros..
|
||||||
turbo-tasks = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230713.2" }
|
turbo-tasks = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230713.3" }
|
||||||
# [TODO]: need to refactor embed_directory! macro usage in next-core
|
# [TODO]: need to refactor embed_directory! macro usage in next-core
|
||||||
turbo-tasks-fs = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230713.2" }
|
turbo-tasks-fs = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230713.3" }
|
||||||
|
|
||||||
# General Deps
|
# General Deps
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ napi = { version = "2", default-features = false, features = [
|
||||||
napi-derive = "2"
|
napi-derive = "2"
|
||||||
next-swc = { version = "0.0.0", path = "../core" }
|
next-swc = { version = "0.0.0", path = "../core" }
|
||||||
next-dev = { workspace = true }
|
next-dev = { workspace = true }
|
||||||
|
next-api = { workspace = true }
|
||||||
next-build = { workspace = true }
|
next-build = { workspace = true }
|
||||||
next-core = { workspace = true }
|
next-core = { workspace = true }
|
||||||
turbo-tasks = { workspace = true }
|
turbo-tasks = { workspace = true }
|
||||||
|
|
|
@ -49,6 +49,7 @@ use turbopack_binding::swc::core::{
|
||||||
pub mod app_structure;
|
pub mod app_structure;
|
||||||
pub mod mdx;
|
pub mod mdx;
|
||||||
pub mod minify;
|
pub mod minify;
|
||||||
|
pub mod next_api;
|
||||||
pub mod parse;
|
pub mod parse;
|
||||||
pub mod transform;
|
pub mod transform;
|
||||||
pub mod turbopack;
|
pub mod turbopack;
|
||||||
|
@ -116,6 +117,7 @@ static REGISTER_ONCE: Once = Once::new();
|
||||||
|
|
||||||
fn register() {
|
fn register() {
|
||||||
REGISTER_ONCE.call_once(|| {
|
REGISTER_ONCE.call_once(|| {
|
||||||
|
::next_api::register();
|
||||||
next_core::register();
|
next_core::register();
|
||||||
include!(concat!(env!("OUT_DIR"), "/register.rs"));
|
include!(concat!(env!("OUT_DIR"), "/register.rs"));
|
||||||
});
|
});
|
||||||
|
|
57
packages/next-swc/crates/napi/src/next_api/endpoint.rs
Normal file
57
packages/next-swc/crates/napi/src/next_api/endpoint.rs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
use napi::{bindgen_prelude::External, JsFunction};
|
||||||
|
use next_api::route::{Endpoint, EndpointVc, WrittenEndpoint};
|
||||||
|
use turbopack_binding::turbopack::core::error::PrettyPrintError;
|
||||||
|
|
||||||
|
use super::utils::{subscribe, NapiDiagnostic, NapiIssue, RootTask, VcArc};
|
||||||
|
|
||||||
|
#[napi(object)]
|
||||||
|
pub struct NapiWrittenEndpoint {
|
||||||
|
pub server_entry_path: String,
|
||||||
|
pub server_paths: Vec<String>,
|
||||||
|
pub issues: Vec<NapiIssue>,
|
||||||
|
pub diagnostics: Vec<NapiDiagnostic>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&WrittenEndpoint> for NapiWrittenEndpoint {
|
||||||
|
fn from(written_endpoint: &WrittenEndpoint) -> Self {
|
||||||
|
Self {
|
||||||
|
server_entry_path: written_endpoint.server_entry_path.clone(),
|
||||||
|
server_paths: written_endpoint.server_paths.clone(),
|
||||||
|
issues: vec![],
|
||||||
|
diagnostics: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub async fn endpoint_write_to_disk(
|
||||||
|
#[napi(ts_arg_type = "{ __napiType: \"Endpoint\" }")] endpoint: External<VcArc<EndpointVc>>,
|
||||||
|
) -> napi::Result<NapiWrittenEndpoint> {
|
||||||
|
let turbo_tasks = endpoint.turbo_tasks().clone();
|
||||||
|
let endpoint = **endpoint;
|
||||||
|
let written = turbo_tasks
|
||||||
|
.run_once(async move { endpoint.write_to_disk().strongly_consistent().await })
|
||||||
|
.await
|
||||||
|
.map_err(|e| napi::Error::from_reason(PrettyPrintError(&e).to_string()))?;
|
||||||
|
// TODO peek_issues and diagnostics
|
||||||
|
Ok((&*written).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi(ts_return_type = "{ __napiType: \"RootTask\" }")]
|
||||||
|
pub fn endpoint_changed_subscribe(
|
||||||
|
#[napi(ts_arg_type = "{ __napiType: \"Endpoint\" }")] endpoint: External<VcArc<EndpointVc>>,
|
||||||
|
func: JsFunction,
|
||||||
|
) -> napi::Result<External<RootTask>> {
|
||||||
|
let turbo_tasks = endpoint.turbo_tasks().clone();
|
||||||
|
let endpoint = **endpoint;
|
||||||
|
subscribe(
|
||||||
|
turbo_tasks,
|
||||||
|
func,
|
||||||
|
move || async move {
|
||||||
|
endpoint.changed().await?;
|
||||||
|
// TODO peek_issues and diagnostics
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
|_ctx| Ok(vec![()]),
|
||||||
|
)
|
||||||
|
}
|
3
packages/next-swc/crates/napi/src/next_api/mod.rs
Normal file
3
packages/next-swc/crates/napi/src/next_api/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
pub mod endpoint;
|
||||||
|
pub mod project;
|
||||||
|
pub mod utils;
|
198
packages/next-swc/crates/napi/src/next_api/project.rs
Normal file
198
packages/next-swc/crates/napi/src/next_api/project.rs
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use napi::{bindgen_prelude::External, JsFunction};
|
||||||
|
use next_api::{
|
||||||
|
project::{Middleware, ProjectOptions, ProjectVc},
|
||||||
|
route::{EndpointVc, Route},
|
||||||
|
};
|
||||||
|
use turbo_tasks::TurboTasks;
|
||||||
|
use turbopack_binding::{
|
||||||
|
turbo::tasks_memory::MemoryBackend, turbopack::core::error::PrettyPrintError,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::utils::{serde_enum_to_string, subscribe, NapiDiagnostic, NapiIssue, RootTask, VcArc};
|
||||||
|
use crate::register;
|
||||||
|
|
||||||
|
#[napi(object)]
|
||||||
|
pub struct NapiProjectOptions {
|
||||||
|
/// A root path from which all files must be nested under. Trying to access
|
||||||
|
/// a file outside this root will fail. Think of this as a chroot.
|
||||||
|
pub root_path: String,
|
||||||
|
|
||||||
|
/// A path inside the root_path which contains the app/pages directories.
|
||||||
|
pub project_path: String,
|
||||||
|
|
||||||
|
/// Whether to watch he filesystem for file changes.
|
||||||
|
pub watch: bool,
|
||||||
|
|
||||||
|
/// The contents of next.config.js, serialized to JSON.
|
||||||
|
pub next_config: String,
|
||||||
|
|
||||||
|
/// An upper bound of memory that turbopack will attempt to stay under.
|
||||||
|
pub memory_limit: Option<f64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<NapiProjectOptions> for ProjectOptions {
|
||||||
|
fn from(val: NapiProjectOptions) -> Self {
|
||||||
|
ProjectOptions {
|
||||||
|
root_path: val.root_path,
|
||||||
|
project_path: val.project_path,
|
||||||
|
watch: val.watch,
|
||||||
|
next_config: val.next_config,
|
||||||
|
memory_limit: val.memory_limit.map(|m| m as _),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi(ts_return_type = "{ __napiType: \"Project\" }")]
|
||||||
|
pub async fn project_new(options: NapiProjectOptions) -> napi::Result<External<VcArc<ProjectVc>>> {
|
||||||
|
register();
|
||||||
|
let turbo_tasks = TurboTasks::new(MemoryBackend::new(
|
||||||
|
options
|
||||||
|
.memory_limit
|
||||||
|
.map(|m| m as usize)
|
||||||
|
.unwrap_or(usize::MAX),
|
||||||
|
));
|
||||||
|
let options = options.into();
|
||||||
|
let project = turbo_tasks
|
||||||
|
.run_once(async move { ProjectVc::new(options).resolve().await })
|
||||||
|
.await
|
||||||
|
.map_err(|e| napi::Error::from_reason(PrettyPrintError(&e).to_string()))?;
|
||||||
|
Ok(External::new_with_size_hint(
|
||||||
|
VcArc::new(turbo_tasks, project),
|
||||||
|
100,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi(object)]
|
||||||
|
#[derive(Default)]
|
||||||
|
struct NapiRoute {
|
||||||
|
/// The relative path from project_path to the route file
|
||||||
|
pub pathname: String,
|
||||||
|
|
||||||
|
/// The type of route, eg a Page or App
|
||||||
|
pub r#type: &'static str,
|
||||||
|
|
||||||
|
// Different representations of the endpoint
|
||||||
|
pub endpoint: Option<External<VcArc<EndpointVc>>>,
|
||||||
|
pub html_endpoint: Option<External<VcArc<EndpointVc>>>,
|
||||||
|
pub rsc_endpoint: Option<External<VcArc<EndpointVc>>>,
|
||||||
|
pub data_endpoint: Option<External<VcArc<EndpointVc>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NapiRoute {
|
||||||
|
fn from_route(
|
||||||
|
pathname: String,
|
||||||
|
value: Route,
|
||||||
|
turbo_tasks: &Arc<TurboTasks<MemoryBackend>>,
|
||||||
|
) -> Self {
|
||||||
|
let convert_endpoint =
|
||||||
|
|endpoint: EndpointVc| Some(External::new(VcArc::new(turbo_tasks.clone(), endpoint)));
|
||||||
|
match value {
|
||||||
|
Route::Page {
|
||||||
|
html_endpoint,
|
||||||
|
data_endpoint,
|
||||||
|
} => NapiRoute {
|
||||||
|
pathname,
|
||||||
|
r#type: "page",
|
||||||
|
html_endpoint: convert_endpoint(html_endpoint),
|
||||||
|
data_endpoint: convert_endpoint(data_endpoint),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Route::PageApi { endpoint } => NapiRoute {
|
||||||
|
pathname,
|
||||||
|
r#type: "page-api",
|
||||||
|
endpoint: convert_endpoint(endpoint),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Route::AppPage {
|
||||||
|
html_endpoint,
|
||||||
|
rsc_endpoint,
|
||||||
|
} => NapiRoute {
|
||||||
|
pathname,
|
||||||
|
r#type: "app-page",
|
||||||
|
html_endpoint: convert_endpoint(html_endpoint),
|
||||||
|
rsc_endpoint: convert_endpoint(rsc_endpoint),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Route::AppRoute { endpoint } => NapiRoute {
|
||||||
|
pathname,
|
||||||
|
r#type: "app-route",
|
||||||
|
endpoint: convert_endpoint(endpoint),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Route::Conflict => NapiRoute {
|
||||||
|
pathname,
|
||||||
|
r#type: "conflict",
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi(object)]
|
||||||
|
struct NapiMiddleware {
|
||||||
|
pub endpoint: External<VcArc<EndpointVc>>,
|
||||||
|
pub runtime: String,
|
||||||
|
pub matcher: Option<Vec<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NapiMiddleware {
|
||||||
|
fn from_middleware(
|
||||||
|
value: &Middleware,
|
||||||
|
turbo_tasks: &Arc<TurboTasks<MemoryBackend>>,
|
||||||
|
) -> Result<Self> {
|
||||||
|
Ok(NapiMiddleware {
|
||||||
|
endpoint: External::new(VcArc::new(turbo_tasks.clone(), value.endpoint)),
|
||||||
|
runtime: serde_enum_to_string(&value.config.runtime)?,
|
||||||
|
matcher: value.config.matcher.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi(object)]
|
||||||
|
struct NapiEntrypoints {
|
||||||
|
pub routes: Vec<NapiRoute>,
|
||||||
|
pub middleware: Option<NapiMiddleware>,
|
||||||
|
pub issues: Vec<NapiIssue>,
|
||||||
|
pub diagnostics: Vec<NapiDiagnostic>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi(ts_return_type = "{ __napiType: \"RootTask\" }")]
|
||||||
|
pub fn project_entrypoints_subscribe(
|
||||||
|
#[napi(ts_arg_type = "{ __napiType: \"Project\" }")] project: External<VcArc<ProjectVc>>,
|
||||||
|
func: JsFunction,
|
||||||
|
) -> napi::Result<External<RootTask>> {
|
||||||
|
let turbo_tasks = project.turbo_tasks().clone();
|
||||||
|
let project = **project;
|
||||||
|
subscribe(
|
||||||
|
turbo_tasks.clone(),
|
||||||
|
func,
|
||||||
|
move || async move {
|
||||||
|
let entrypoints = project.entrypoints();
|
||||||
|
let entrypoints = entrypoints.strongly_consistent().await?;
|
||||||
|
// TODO peek_issues and diagnostics
|
||||||
|
Ok(entrypoints)
|
||||||
|
},
|
||||||
|
move |ctx| {
|
||||||
|
let entrypoints = ctx.value;
|
||||||
|
Ok(vec![NapiEntrypoints {
|
||||||
|
routes: entrypoints
|
||||||
|
.routes
|
||||||
|
.iter()
|
||||||
|
.map(|(pathname, &route)| {
|
||||||
|
NapiRoute::from_route(pathname.clone(), route, &turbo_tasks)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
middleware: entrypoints
|
||||||
|
.middleware
|
||||||
|
.as_ref()
|
||||||
|
.map(|m| NapiMiddleware::from_middleware(m, &turbo_tasks))
|
||||||
|
.transpose()?,
|
||||||
|
issues: vec![],
|
||||||
|
diagnostics: vec![],
|
||||||
|
}])
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
137
packages/next-swc/crates/napi/src/next_api/utils.rs
Normal file
137
packages/next-swc/crates/napi/src/next_api/utils.rs
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
use std::{future::Future, ops::Deref, sync::Arc};
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Context, Result};
|
||||||
|
use napi::{
|
||||||
|
bindgen_prelude::{External, ToNapiValue},
|
||||||
|
threadsafe_function::{ThreadSafeCallContext, ThreadsafeFunction, ThreadsafeFunctionCallMode},
|
||||||
|
JsFunction, JsObject, NapiRaw, NapiValue, Status,
|
||||||
|
};
|
||||||
|
use serde::Serialize;
|
||||||
|
use turbo_tasks::{NothingVc, TaskId, TurboTasks};
|
||||||
|
use turbopack_binding::{
|
||||||
|
turbo::tasks_memory::MemoryBackend, turbopack::core::error::PrettyPrintError,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A helper type to hold both a Vc operation and the TurboTasks root process.
|
||||||
|
/// Without this, we'd need to pass both individually all over the place
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct VcArc<T> {
|
||||||
|
turbo_tasks: Arc<TurboTasks<MemoryBackend>>,
|
||||||
|
/// The Vc. Must be resolved, otherwise you are referencing an inactive
|
||||||
|
/// operation.
|
||||||
|
vc: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> VcArc<T> {
|
||||||
|
pub fn new(turbo_tasks: Arc<TurboTasks<MemoryBackend>>, vc: T) -> Self {
|
||||||
|
Self { turbo_tasks, vc }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn turbo_tasks(&self) -> &Arc<TurboTasks<MemoryBackend>> {
|
||||||
|
&self.turbo_tasks
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Deref for VcArc<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.vc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn serde_enum_to_string<T: Serialize>(value: &T) -> Result<String> {
|
||||||
|
Ok(serde_json::to_value(value)?
|
||||||
|
.as_str()
|
||||||
|
.context("value must serialize to a string")?
|
||||||
|
.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The root of our turbopack computation.
|
||||||
|
pub struct RootTask {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
turbo_tasks: Arc<TurboTasks<MemoryBackend>>,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
task_id: Option<TaskId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for RootTask {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// TODO stop the root task
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub fn root_task_dispose(
|
||||||
|
#[napi(ts_arg_type = "{ __napiType: \"RootTask\" }")] _root_task: External<RootTask>,
|
||||||
|
) -> napi::Result<()> {
|
||||||
|
// TODO(alexkirsz) Implement. Not panicking here to avoid crashing the process
|
||||||
|
// when testing.
|
||||||
|
eprintln!("root_task_dispose not yet implemented");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi(object)]
|
||||||
|
pub struct NapiIssue {}
|
||||||
|
|
||||||
|
#[napi(object)]
|
||||||
|
pub struct NapiDiagnostic {}
|
||||||
|
|
||||||
|
pub struct TurbopackResult<T: ToNapiValue> {
|
||||||
|
pub result: T,
|
||||||
|
pub issues: Vec<NapiIssue>,
|
||||||
|
pub diagnostics: Vec<NapiDiagnostic>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ToNapiValue> ToNapiValue for TurbopackResult<T> {
|
||||||
|
unsafe fn to_napi_value(
|
||||||
|
env: napi::sys::napi_env,
|
||||||
|
val: Self,
|
||||||
|
) -> napi::Result<napi::sys::napi_value> {
|
||||||
|
let result = T::to_napi_value(env, val.result)?;
|
||||||
|
// let issues = ToNapiValue::to_napi_value(env, val.issues)?;
|
||||||
|
// let diagnostics = ToNapiValue::to_napi_value(env, val.diagnostics)?;
|
||||||
|
|
||||||
|
let result = JsObject::from_raw(env, result)?;
|
||||||
|
|
||||||
|
let mut obj = napi::Env::from_raw(env).create_object()?;
|
||||||
|
for key in JsObject::keys(&result)? {
|
||||||
|
obj.set_named_property(&key, result.get_named_property(&key)?)?;
|
||||||
|
}
|
||||||
|
obj.set_named_property("issues", val.issues)?;
|
||||||
|
obj.set_named_property("diagnostics", val.diagnostics)?;
|
||||||
|
|
||||||
|
Ok(obj.raw())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subscribe<T: 'static + Send + Sync, F: Future<Output = Result<T>> + Send, V: ToNapiValue>(
|
||||||
|
turbo_tasks: Arc<TurboTasks<MemoryBackend>>,
|
||||||
|
func: JsFunction,
|
||||||
|
handler: impl 'static + Sync + Send + Clone + Fn() -> F,
|
||||||
|
mapper: impl 'static + Sync + Send + FnMut(ThreadSafeCallContext<T>) -> napi::Result<Vec<V>>,
|
||||||
|
) -> napi::Result<External<RootTask>> {
|
||||||
|
let func: ThreadsafeFunction<T> = func.create_threadsafe_function(0, mapper)?;
|
||||||
|
let task_id = turbo_tasks.spawn_root_task(move || {
|
||||||
|
let handler = handler.clone();
|
||||||
|
let func = func.clone();
|
||||||
|
Box::pin(async move {
|
||||||
|
let result = handler().await;
|
||||||
|
|
||||||
|
let status = func.call(
|
||||||
|
result.map_err(|e| napi::Error::from_reason(PrettyPrintError(&e).to_string())),
|
||||||
|
ThreadsafeFunctionCallMode::NonBlocking,
|
||||||
|
);
|
||||||
|
if !matches!(status, Status::Ok) {
|
||||||
|
let error = anyhow!("Error calling JS function: {}", status);
|
||||||
|
eprintln!("{}", error);
|
||||||
|
return Err(error);
|
||||||
|
}
|
||||||
|
Ok(NothingVc::new().into())
|
||||||
|
})
|
||||||
|
});
|
||||||
|
Ok(External::new(RootTask {
|
||||||
|
turbo_tasks,
|
||||||
|
task_id: Some(task_id),
|
||||||
|
}))
|
||||||
|
}
|
46
packages/next-swc/crates/next-api/Cargo.toml
Normal file
46
packages/next-swc/crates/next-api/Cargo.toml
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
[package]
|
||||||
|
name = "next-api"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "TBD"
|
||||||
|
license = "MPL-2.0"
|
||||||
|
edition = "2021"
|
||||||
|
autobenches = false
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
bench = false
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["custom_allocator", "native-tls"]
|
||||||
|
custom_allocator = ["turbopack-binding/__turbo_tasks_malloc", "turbopack-binding/__turbo_tasks_malloc_custom_allocator"]
|
||||||
|
native-tls = ["next-core/native-tls"]
|
||||||
|
rustls-tls = ["next-core/rustls-tls"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = { workspace = true, features = ["backtrace"] }
|
||||||
|
futures = { workspace = true }
|
||||||
|
indexmap = { workspace = true }
|
||||||
|
next-core = { workspace = true }
|
||||||
|
once_cell = { workspace = true }
|
||||||
|
serde = { workspace = true }
|
||||||
|
tokio = { workspace = true, features = ["full"] }
|
||||||
|
turbopack-binding = { workspace = true, features = [
|
||||||
|
"__turbo_tasks_memory",
|
||||||
|
"__turbo_tasks_env",
|
||||||
|
"__turbo_tasks_fs",
|
||||||
|
"__turbopack",
|
||||||
|
"__turbopack_build",
|
||||||
|
"__turbopack_core",
|
||||||
|
"__turbopack_dev",
|
||||||
|
"__turbopack_env",
|
||||||
|
"__turbopack_cli_utils",
|
||||||
|
"__turbopack_node",
|
||||||
|
"__turbopack_dev_server",
|
||||||
|
]}
|
||||||
|
turbo-tasks = { workspace = true }
|
||||||
|
tracing = { workspace = true }
|
||||||
|
tracing-subscriber = { workspace = true, features = ["env-filter", "json"] }
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
turbopack-binding = { workspace = true, features = [
|
||||||
|
"__turbo_tasks_build"
|
||||||
|
]}
|
5
packages/next-swc/crates/next-api/build.rs
Normal file
5
packages/next-swc/crates/next-api/build.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
use turbopack_binding::turbo::tasks_build::generate_register;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
generate_register();
|
||||||
|
}
|
67
packages/next-swc/crates/next-api/src/app.rs
Normal file
67
packages/next-swc/crates/next-api/src/app.rs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
use next_core::app_structure::Entrypoint;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use turbo_tasks::{trace::TraceRawVcs, CompletionVc};
|
||||||
|
|
||||||
|
use crate::route::{Endpoint, EndpointVc, Route, RouteVc, WrittenEndpointVc};
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub async fn app_entry_point_to_route(entrypoint: Entrypoint) -> RouteVc {
|
||||||
|
match entrypoint {
|
||||||
|
Entrypoint::AppPage { .. } => Route::AppPage {
|
||||||
|
html_endpoint: AppPageEndpoint {
|
||||||
|
ty: AppPageEndpointType::Html,
|
||||||
|
}
|
||||||
|
.cell()
|
||||||
|
.into(),
|
||||||
|
rsc_endpoint: AppPageEndpoint {
|
||||||
|
ty: AppPageEndpointType::Rsc,
|
||||||
|
}
|
||||||
|
.cell()
|
||||||
|
.into(),
|
||||||
|
},
|
||||||
|
Entrypoint::AppRoute { .. } => Route::AppRoute {
|
||||||
|
endpoint: AppRouteEndpoint.cell().into(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
.cell()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Serialize, Deserialize, PartialEq, Eq, Debug, TraceRawVcs)]
|
||||||
|
enum AppPageEndpointType {
|
||||||
|
Html,
|
||||||
|
Rsc,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::value]
|
||||||
|
struct AppPageEndpoint {
|
||||||
|
ty: AppPageEndpointType,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::value_impl]
|
||||||
|
impl Endpoint for AppPageEndpoint {
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
fn write_to_disk(&self) -> WrittenEndpointVc {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
fn changed(&self) -> CompletionVc {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::value]
|
||||||
|
struct AppRouteEndpoint;
|
||||||
|
|
||||||
|
#[turbo_tasks::value_impl]
|
||||||
|
impl Endpoint for AppRouteEndpoint {
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
fn write_to_disk(&self) -> WrittenEndpointVc {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
fn changed(&self) -> CompletionVc {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
13
packages/next-swc/crates/next-api/src/lib.rs
Normal file
13
packages/next-swc/crates/next-api/src/lib.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#![feature(future_join)]
|
||||||
|
#![feature(min_specialization)]
|
||||||
|
|
||||||
|
mod app;
|
||||||
|
mod pages;
|
||||||
|
pub mod project;
|
||||||
|
pub mod route;
|
||||||
|
|
||||||
|
pub fn register() {
|
||||||
|
next_core::register();
|
||||||
|
turbopack_binding::turbopack::build::register();
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/register.rs"));
|
||||||
|
}
|
363
packages/next-swc/crates/next-api/src/pages.rs
Normal file
363
packages/next-swc/crates/next-api/src/pages.rs
Normal file
|
@ -0,0 +1,363 @@
|
||||||
|
use anyhow::{bail, Context, Result};
|
||||||
|
use indexmap::IndexMap;
|
||||||
|
use next_core::{
|
||||||
|
create_page_loader_entry_module, emit_all_assets, get_asset_path_from_pathname,
|
||||||
|
pages_structure::{
|
||||||
|
PagesDirectoryStructure, PagesDirectoryStructureVc, PagesStructure, PagesStructureItem,
|
||||||
|
PagesStructureVc,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use turbo_tasks::{primitives::StringVc, CompletionVc, CompletionsVc, Value};
|
||||||
|
use turbopack_binding::{
|
||||||
|
turbo::tasks_fs::FileSystemPathVc,
|
||||||
|
turbopack::{
|
||||||
|
core::{
|
||||||
|
asset::Asset,
|
||||||
|
changed::{any_content_changed, any_content_changed_of_output_assets},
|
||||||
|
chunk::{ChunkableModule, ChunkingContext},
|
||||||
|
context::AssetContext,
|
||||||
|
file_source::FileSourceVc,
|
||||||
|
output::{OutputAssetVc, OutputAssetsVc},
|
||||||
|
reference_type::{EntryReferenceSubType, ReferenceType},
|
||||||
|
source::SourceVc,
|
||||||
|
},
|
||||||
|
ecmascript::EcmascriptModuleAssetVc,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
project::ProjectVc,
|
||||||
|
route::{Endpoint, EndpointVc, Route, RoutesVc, WrittenEndpoint, WrittenEndpointVc},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub async fn get_pages_routes(
|
||||||
|
project: ProjectVc,
|
||||||
|
page_structure: PagesStructureVc,
|
||||||
|
) -> Result<RoutesVc> {
|
||||||
|
let PagesStructure { api, pages, .. } = *page_structure.await?;
|
||||||
|
let mut routes = IndexMap::new();
|
||||||
|
async fn add_dir_to_routes(
|
||||||
|
routes: &mut IndexMap<String, Route>,
|
||||||
|
dir: PagesDirectoryStructureVc,
|
||||||
|
make_route: impl Fn(StringVc, StringVc, FileSystemPathVc) -> Route,
|
||||||
|
) -> Result<()> {
|
||||||
|
let mut queue = vec![dir];
|
||||||
|
while let Some(dir) = queue.pop() {
|
||||||
|
let PagesDirectoryStructure {
|
||||||
|
ref items,
|
||||||
|
ref children,
|
||||||
|
next_router_path: _,
|
||||||
|
project_path: _,
|
||||||
|
} = *dir.await?;
|
||||||
|
for &item in items.iter() {
|
||||||
|
let PagesStructureItem {
|
||||||
|
next_router_path,
|
||||||
|
project_path,
|
||||||
|
original_path,
|
||||||
|
} = *item.await?;
|
||||||
|
let pathname = format!("/{}", next_router_path.await?.path);
|
||||||
|
let pathname_vc = StringVc::cell(pathname.clone());
|
||||||
|
let original_name = StringVc::cell(format!("/{}", original_path.await?.path));
|
||||||
|
let route = make_route(pathname_vc, original_name, project_path);
|
||||||
|
routes.insert(pathname, route);
|
||||||
|
}
|
||||||
|
for &child in children.iter() {
|
||||||
|
queue.push(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
if let Some(api) = api {
|
||||||
|
add_dir_to_routes(&mut routes, api, |pathname, original_name, path| {
|
||||||
|
Route::PageApi {
|
||||||
|
endpoint: ApiEndpointVc::new(project, pathname, original_name, path).into(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
if let Some(page) = pages {
|
||||||
|
add_dir_to_routes(&mut routes, page, |pathname, original_name, path| {
|
||||||
|
Route::Page {
|
||||||
|
html_endpoint: PageHtmlEndpointVc::new(project, pathname, original_name, path)
|
||||||
|
.into(),
|
||||||
|
data_endpoint: PageDataEndpointVc::new(project, pathname, original_name, path)
|
||||||
|
.into(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
Ok(RoutesVc::cell(routes))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::value]
|
||||||
|
struct PageHtmlEndpoint {
|
||||||
|
project: ProjectVc,
|
||||||
|
pathname: StringVc,
|
||||||
|
original_name: StringVc,
|
||||||
|
path: FileSystemPathVc,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::value_impl]
|
||||||
|
impl PageHtmlEndpointVc {
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
fn new(
|
||||||
|
project: ProjectVc,
|
||||||
|
pathname: StringVc,
|
||||||
|
original_name: StringVc,
|
||||||
|
path: FileSystemPathVc,
|
||||||
|
) -> Self {
|
||||||
|
PageHtmlEndpoint {
|
||||||
|
project,
|
||||||
|
pathname,
|
||||||
|
original_name,
|
||||||
|
path,
|
||||||
|
}
|
||||||
|
.cell()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn source(self) -> Result<SourceVc> {
|
||||||
|
let this = self.await?;
|
||||||
|
Ok(FileSourceVc::new(this.path).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn client_chunks(self) -> Result<OutputAssetsVc> {
|
||||||
|
let this = self.await?;
|
||||||
|
|
||||||
|
let client_module = create_page_loader_entry_module(
|
||||||
|
this.project.pages_client_module_context(),
|
||||||
|
self.source(),
|
||||||
|
this.pathname,
|
||||||
|
);
|
||||||
|
|
||||||
|
let Some(client_module) = EcmascriptModuleAssetVc::resolve_from(client_module).await?
|
||||||
|
else {
|
||||||
|
bail!("expected an ECMAScript module asset");
|
||||||
|
};
|
||||||
|
|
||||||
|
let client_chunking_context = this.project.client_chunking_context();
|
||||||
|
|
||||||
|
let client_entry_chunk = client_module.as_root_chunk(client_chunking_context.into());
|
||||||
|
|
||||||
|
let client_chunks = client_chunking_context.evaluated_chunk_group(
|
||||||
|
client_entry_chunk,
|
||||||
|
this.project
|
||||||
|
.pages_client_runtime_entries()
|
||||||
|
.with_entry(client_module.into()),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(client_chunks)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn ssr_chunk(self) -> Result<OutputAssetVc> {
|
||||||
|
let this = self.await?;
|
||||||
|
let reference_type = Value::new(ReferenceType::Entry(EntryReferenceSubType::Page));
|
||||||
|
|
||||||
|
let ssr_module = this
|
||||||
|
.project
|
||||||
|
.pages_ssr_module_context()
|
||||||
|
.process(self.source(), reference_type.clone());
|
||||||
|
|
||||||
|
let Some(ssr_module) = EcmascriptModuleAssetVc::resolve_from(ssr_module).await? else {
|
||||||
|
bail!("expected an ECMAScript module asset");
|
||||||
|
};
|
||||||
|
|
||||||
|
let asset_path = get_asset_path_from_pathname(&this.pathname.await?, ".js");
|
||||||
|
|
||||||
|
let ssr_entry_chunk_path_string = format!("server/pages{asset_path}");
|
||||||
|
let ssr_entry_chunk_path = this.project.node_root().join(&ssr_entry_chunk_path_string);
|
||||||
|
let ssr_entry_chunk = this.project.ssr_chunking_context().entry_chunk(
|
||||||
|
ssr_entry_chunk_path,
|
||||||
|
ssr_module.into(),
|
||||||
|
this.project.pages_ssr_runtime_entries(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(ssr_entry_chunk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::value_impl]
|
||||||
|
impl Endpoint for PageHtmlEndpoint {
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn write_to_disk(self_vc: PageHtmlEndpointVc) -> Result<WrittenEndpointVc> {
|
||||||
|
let this = self_vc.await?;
|
||||||
|
let ssr_chunk = self_vc.ssr_chunk();
|
||||||
|
let ssr_emit = emit_all_assets(
|
||||||
|
OutputAssetsVc::cell(vec![ssr_chunk]),
|
||||||
|
this.project.node_root(),
|
||||||
|
this.project.client_root().join("_next"),
|
||||||
|
this.project.node_root(),
|
||||||
|
);
|
||||||
|
let client_emit = emit_all_assets(
|
||||||
|
self_vc.client_chunks(),
|
||||||
|
this.project.node_root(),
|
||||||
|
this.project.client_root().join("_next"),
|
||||||
|
this.project.node_root(),
|
||||||
|
);
|
||||||
|
|
||||||
|
ssr_emit.await?;
|
||||||
|
client_emit.await?;
|
||||||
|
|
||||||
|
Ok(WrittenEndpoint {
|
||||||
|
server_entry_path: this
|
||||||
|
.project
|
||||||
|
.node_root()
|
||||||
|
.await?
|
||||||
|
.get_path_to(&*ssr_chunk.ident().path().await?)
|
||||||
|
.context("ssr chunk entry path must be inside the node root")?
|
||||||
|
.to_string(),
|
||||||
|
server_paths: vec![],
|
||||||
|
}
|
||||||
|
.cell())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
fn changed(self_vc: PageHtmlEndpointVc) -> CompletionVc {
|
||||||
|
let ssr_chunk = self_vc.ssr_chunk();
|
||||||
|
CompletionsVc::all(vec![
|
||||||
|
any_content_changed(ssr_chunk.into()),
|
||||||
|
any_content_changed_of_output_assets(self_vc.client_chunks()),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::value]
|
||||||
|
struct PageDataEndpoint {
|
||||||
|
project: ProjectVc,
|
||||||
|
pathname: StringVc,
|
||||||
|
original_name: StringVc,
|
||||||
|
path: FileSystemPathVc,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::value_impl]
|
||||||
|
impl PageDataEndpointVc {
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
fn new(
|
||||||
|
project: ProjectVc,
|
||||||
|
pathname: StringVc,
|
||||||
|
original_name: StringVc,
|
||||||
|
path: FileSystemPathVc,
|
||||||
|
) -> Self {
|
||||||
|
PageDataEndpoint {
|
||||||
|
project,
|
||||||
|
pathname,
|
||||||
|
original_name,
|
||||||
|
path,
|
||||||
|
}
|
||||||
|
.cell()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn source(self) -> Result<SourceVc> {
|
||||||
|
let this = self.await?;
|
||||||
|
Ok(FileSourceVc::new(this.path).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn ssr_data_chunk(self) -> Result<OutputAssetVc> {
|
||||||
|
let this = self.await?;
|
||||||
|
let reference_type = Value::new(ReferenceType::Entry(EntryReferenceSubType::Page));
|
||||||
|
|
||||||
|
let ssr_data_module = this
|
||||||
|
.project
|
||||||
|
.pages_ssr_data_module_context()
|
||||||
|
.process(self.source(), reference_type.clone());
|
||||||
|
|
||||||
|
let Some(ssr_data_module) = EcmascriptModuleAssetVc::resolve_from(ssr_data_module).await?
|
||||||
|
else {
|
||||||
|
bail!("expected an ECMAScript module asset");
|
||||||
|
};
|
||||||
|
|
||||||
|
let asset_path = get_asset_path_from_pathname(&this.pathname.await?, ".js");
|
||||||
|
|
||||||
|
let ssr_data_entry_chunk_path_string = format!("server/pages-data/{asset_path}");
|
||||||
|
let ssr_data_entry_chunk_path = this
|
||||||
|
.project
|
||||||
|
.node_root()
|
||||||
|
.join(&ssr_data_entry_chunk_path_string);
|
||||||
|
let ssr_data_entry_chunk = this.project.ssr_data_chunking_context().entry_chunk(
|
||||||
|
ssr_data_entry_chunk_path,
|
||||||
|
ssr_data_module.into(),
|
||||||
|
this.project.pages_ssr_runtime_entries(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(ssr_data_entry_chunk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::value_impl]
|
||||||
|
impl Endpoint for PageDataEndpoint {
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn write_to_disk(self_vc: PageDataEndpointVc) -> Result<WrittenEndpointVc> {
|
||||||
|
let this = self_vc.await?;
|
||||||
|
let ssr_data_chunk = self_vc.ssr_data_chunk();
|
||||||
|
emit_all_assets(
|
||||||
|
OutputAssetsVc::cell(vec![ssr_data_chunk]),
|
||||||
|
this.project.node_root(),
|
||||||
|
this.project.client_root().join("_next"),
|
||||||
|
this.project.node_root(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(WrittenEndpoint {
|
||||||
|
server_entry_path: this
|
||||||
|
.project
|
||||||
|
.node_root()
|
||||||
|
.await?
|
||||||
|
.get_path_to(&*ssr_data_chunk.ident().path().await?)
|
||||||
|
.context("ssr data chunk entry path must be inside the node root")?
|
||||||
|
.to_string(),
|
||||||
|
server_paths: vec![],
|
||||||
|
}
|
||||||
|
.cell())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn changed(self_vc: PageDataEndpointVc) -> Result<CompletionVc> {
|
||||||
|
let ssr_data_chunk = self_vc.ssr_data_chunk();
|
||||||
|
Ok(any_content_changed(ssr_data_chunk.into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::value]
|
||||||
|
struct ApiEndpoint {
|
||||||
|
project: ProjectVc,
|
||||||
|
pathname: StringVc,
|
||||||
|
original_name: StringVc,
|
||||||
|
path: FileSystemPathVc,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::value_impl]
|
||||||
|
impl ApiEndpointVc {
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
fn new(
|
||||||
|
project: ProjectVc,
|
||||||
|
pathname: StringVc,
|
||||||
|
original_name: StringVc,
|
||||||
|
path: FileSystemPathVc,
|
||||||
|
) -> Self {
|
||||||
|
ApiEndpoint {
|
||||||
|
project,
|
||||||
|
pathname,
|
||||||
|
original_name,
|
||||||
|
path,
|
||||||
|
}
|
||||||
|
.cell()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::value_impl]
|
||||||
|
impl Endpoint for ApiEndpoint {
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
fn write_to_disk(&self) -> WrittenEndpointVc {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
fn changed(&self) -> CompletionVc {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
517
packages/next-swc/crates/next-api/src/project.rs
Normal file
517
packages/next-swc/crates/next-api/src/project.rs
Normal file
|
@ -0,0 +1,517 @@
|
||||||
|
use std::path::MAIN_SEPARATOR;
|
||||||
|
|
||||||
|
use anyhow::{Context, Result};
|
||||||
|
use indexmap::{map::Entry, IndexMap};
|
||||||
|
use next_core::{
|
||||||
|
app_structure::{find_app_dir, get_entrypoints},
|
||||||
|
mode::NextMode,
|
||||||
|
next_client::{
|
||||||
|
get_client_chunking_context, get_client_compile_time_info,
|
||||||
|
get_client_module_options_context, get_client_resolve_options_context,
|
||||||
|
get_client_runtime_entries, ClientContextType,
|
||||||
|
},
|
||||||
|
next_config::NextConfigVc,
|
||||||
|
next_dynamic::NextDynamicTransitionVc,
|
||||||
|
next_server::{
|
||||||
|
get_server_chunking_context, get_server_compile_time_info,
|
||||||
|
get_server_module_options_context, get_server_resolve_options_context,
|
||||||
|
get_server_runtime_entries, ServerContextType,
|
||||||
|
},
|
||||||
|
pages_structure::{find_pages_structure, PagesStructureVc},
|
||||||
|
util::NextSourceConfig,
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use turbo_tasks::{
|
||||||
|
debug::ValueDebugFormat, trace::TraceRawVcs, NothingVc, TaskInput, TransientValue,
|
||||||
|
TryJoinIterExt, Value,
|
||||||
|
};
|
||||||
|
use turbopack_binding::{
|
||||||
|
turbo::{
|
||||||
|
tasks_env::ProcessEnvVc,
|
||||||
|
tasks_fs::{
|
||||||
|
DiskFileSystemVc, FileSystem, FileSystemPathVc, FileSystemVc, VirtualFileSystemVc,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
turbopack::{
|
||||||
|
build::BuildChunkingContextVc,
|
||||||
|
core::{
|
||||||
|
chunk::{ChunkingContext, EvaluatableAssetsVc},
|
||||||
|
compile_time_info::CompileTimeInfoVc,
|
||||||
|
context::AssetContextVc,
|
||||||
|
environment::ServerAddrVc,
|
||||||
|
PROJECT_FILESYSTEM_NAME,
|
||||||
|
},
|
||||||
|
dev::DevChunkingContextVc,
|
||||||
|
ecmascript::chunk::EcmascriptChunkingContextVc,
|
||||||
|
env::dotenv::load_env,
|
||||||
|
node::execution_context::ExecutionContextVc,
|
||||||
|
turbopack::{
|
||||||
|
evaluate_context::node_build_environment,
|
||||||
|
module_options::ModuleOptionsContextVc,
|
||||||
|
resolve_options_context::ResolveOptionsContextVc,
|
||||||
|
transition::{ContextTransitionVc, TransitionsByNameVc},
|
||||||
|
ModuleAssetContextVc,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
app::app_entry_point_to_route,
|
||||||
|
pages::get_pages_routes,
|
||||||
|
route::{EndpointVc, Route},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone, TaskInput)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct ProjectOptions {
|
||||||
|
/// A root path from which all files must be nested under. Trying to access
|
||||||
|
/// a file outside this root will fail. Think of this as a chroot.
|
||||||
|
pub root_path: String,
|
||||||
|
|
||||||
|
/// A path inside the root_path which contains the app/pages directories.
|
||||||
|
pub project_path: String,
|
||||||
|
|
||||||
|
/// The contents of next.config.js, serialized to JSON.
|
||||||
|
pub next_config: String,
|
||||||
|
|
||||||
|
/// Whether to watch the filesystem for file changes.
|
||||||
|
pub watch: bool,
|
||||||
|
|
||||||
|
/// An upper bound of memory that turbopack will attempt to stay under.
|
||||||
|
pub memory_limit: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, TraceRawVcs, PartialEq, Eq, ValueDebugFormat)]
|
||||||
|
pub struct Middleware {
|
||||||
|
pub endpoint: EndpointVc,
|
||||||
|
pub config: NextSourceConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::value]
|
||||||
|
pub struct Entrypoints {
|
||||||
|
pub routes: IndexMap<String, Route>,
|
||||||
|
pub middleware: Option<Middleware>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::value]
|
||||||
|
pub struct Project {
|
||||||
|
/// A root path from which all files must be nested under. Trying to access
|
||||||
|
/// a file outside this root will fail. Think of this as a chroot.
|
||||||
|
root_path: String,
|
||||||
|
|
||||||
|
/// A path inside the root_path which contains the app/pages directories.
|
||||||
|
project_path: String,
|
||||||
|
|
||||||
|
/// Whether to watch the filesystem for file changes.
|
||||||
|
watch: bool,
|
||||||
|
|
||||||
|
/// Next config.
|
||||||
|
next_config: NextConfigVc,
|
||||||
|
|
||||||
|
browserslist_query: String,
|
||||||
|
|
||||||
|
mode: NextMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::value_impl]
|
||||||
|
impl ProjectVc {
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub async fn new(options: ProjectOptions) -> Result<Self> {
|
||||||
|
let next_config = NextConfigVc::from_string(options.next_config);
|
||||||
|
Ok(Project {
|
||||||
|
root_path: options.root_path,
|
||||||
|
project_path: options.project_path,
|
||||||
|
watch: options.watch,
|
||||||
|
next_config,
|
||||||
|
browserslist_query: "last 1 Chrome versions, last 1 Firefox versions, last 1 Safari \
|
||||||
|
versions, last 1 Edge versions"
|
||||||
|
.to_string(),
|
||||||
|
mode: NextMode::Development,
|
||||||
|
}
|
||||||
|
.cell())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn project_fs(self) -> Result<FileSystemVc> {
|
||||||
|
let this = self.await?;
|
||||||
|
let disk_fs = DiskFileSystemVc::new(
|
||||||
|
PROJECT_FILESYSTEM_NAME.to_string(),
|
||||||
|
this.root_path.to_string(),
|
||||||
|
);
|
||||||
|
if this.watch {
|
||||||
|
disk_fs.await?.start_watching_with_invalidation_reason()?;
|
||||||
|
}
|
||||||
|
Ok(disk_fs.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn client_fs(self) -> Result<FileSystemVc> {
|
||||||
|
let virtual_fs = VirtualFileSystemVc::new();
|
||||||
|
Ok(virtual_fs.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn node_fs(self) -> Result<FileSystemVc> {
|
||||||
|
let this = self.await?;
|
||||||
|
let disk_fs = DiskFileSystemVc::new("node".to_string(), this.project_path.clone());
|
||||||
|
disk_fs.await?.start_watching_with_invalidation_reason()?;
|
||||||
|
Ok(disk_fs.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub(super) fn node_root(self) -> FileSystemPathVc {
|
||||||
|
self.node_fs().root().join(".next")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub(super) fn client_root(self) -> FileSystemPathVc {
|
||||||
|
self.client_fs().root()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
fn project_root_path(self) -> FileSystemPathVc {
|
||||||
|
self.project_fs().root()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn project_path(self) -> Result<FileSystemPathVc> {
|
||||||
|
let this = self.await?;
|
||||||
|
let root = self.project_root_path();
|
||||||
|
let project_relative = this.project_path.strip_prefix(&this.root_path).unwrap();
|
||||||
|
let project_relative = project_relative
|
||||||
|
.strip_prefix(MAIN_SEPARATOR)
|
||||||
|
.unwrap_or(project_relative)
|
||||||
|
.replace(MAIN_SEPARATOR, "/");
|
||||||
|
Ok(root.join(&project_relative))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn pages_structure(self) -> Result<PagesStructureVc> {
|
||||||
|
let this: turbo_tasks::ReadRef<Project> = self.await?;
|
||||||
|
let next_router_fs = VirtualFileSystemVc::new().as_file_system();
|
||||||
|
let next_router_root = next_router_fs.root();
|
||||||
|
Ok(find_pages_structure(
|
||||||
|
self.project_path(),
|
||||||
|
next_router_root,
|
||||||
|
this.next_config.page_extensions(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
fn env(self) -> ProcessEnvVc {
|
||||||
|
load_env(self.project_path())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn next_config(self) -> Result<NextConfigVc> {
|
||||||
|
Ok(self.await?.next_config)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
fn execution_context(self) -> ExecutionContextVc {
|
||||||
|
let node_root = self.node_root();
|
||||||
|
|
||||||
|
let node_execution_chunking_context = DevChunkingContextVc::builder(
|
||||||
|
self.project_path(),
|
||||||
|
node_root,
|
||||||
|
node_root.join("chunks"),
|
||||||
|
node_root.join("assets"),
|
||||||
|
node_build_environment(),
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
.into();
|
||||||
|
|
||||||
|
ExecutionContextVc::new(
|
||||||
|
self.project_path(),
|
||||||
|
node_execution_chunking_context,
|
||||||
|
self.env(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn client_compile_time_info(self) -> Result<CompileTimeInfoVc> {
|
||||||
|
let this = self.await?;
|
||||||
|
Ok(get_client_compile_time_info(
|
||||||
|
this.mode,
|
||||||
|
&this.browserslist_query,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn server_compile_time_info(self) -> Result<CompileTimeInfoVc> {
|
||||||
|
let this = self.await?;
|
||||||
|
Ok(get_server_compile_time_info(
|
||||||
|
this.mode,
|
||||||
|
self.env(),
|
||||||
|
// TODO(alexkirsz) Fill this out.
|
||||||
|
ServerAddrVc::empty(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn pages_dir(self) -> Result<FileSystemPathVc> {
|
||||||
|
Ok(if let Some(pages) = self.pages_structure().await?.pages {
|
||||||
|
pages.project_path()
|
||||||
|
} else {
|
||||||
|
self.project_path().join("pages")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
fn pages_transitions(self) -> TransitionsByNameVc {
|
||||||
|
TransitionsByNameVc::cell(
|
||||||
|
[(
|
||||||
|
"next-dynamic".to_string(),
|
||||||
|
NextDynamicTransitionVc::new(self.pages_client_transition()).into(),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
fn pages_client_transition(self) -> ContextTransitionVc {
|
||||||
|
ContextTransitionVc::new(
|
||||||
|
self.client_compile_time_info(),
|
||||||
|
self.pages_client_module_options_context(),
|
||||||
|
self.pages_client_resolve_options_context(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn pages_client_module_options_context(self) -> Result<ModuleOptionsContextVc> {
|
||||||
|
let this = self.await?;
|
||||||
|
Ok(get_client_module_options_context(
|
||||||
|
self.project_path(),
|
||||||
|
self.execution_context(),
|
||||||
|
self.client_compile_time_info().environment(),
|
||||||
|
Value::new(ClientContextType::Pages {
|
||||||
|
pages_dir: self.pages_dir(),
|
||||||
|
}),
|
||||||
|
this.mode,
|
||||||
|
self.next_config(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn pages_client_resolve_options_context(self) -> Result<ResolveOptionsContextVc> {
|
||||||
|
let this = self.await?;
|
||||||
|
Ok(get_client_resolve_options_context(
|
||||||
|
self.project_path(),
|
||||||
|
Value::new(ClientContextType::Pages {
|
||||||
|
pages_dir: self.pages_dir(),
|
||||||
|
}),
|
||||||
|
this.mode,
|
||||||
|
self.next_config(),
|
||||||
|
self.execution_context(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub(super) fn pages_client_module_context(self) -> AssetContextVc {
|
||||||
|
ModuleAssetContextVc::new(
|
||||||
|
self.pages_transitions(),
|
||||||
|
self.client_compile_time_info(),
|
||||||
|
self.pages_client_module_options_context(),
|
||||||
|
self.pages_client_resolve_options_context(),
|
||||||
|
)
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub(super) fn pages_ssr_module_context(self) -> AssetContextVc {
|
||||||
|
ModuleAssetContextVc::new(
|
||||||
|
self.pages_transitions(),
|
||||||
|
self.server_compile_time_info(),
|
||||||
|
self.pages_ssr_module_options_context(),
|
||||||
|
self.pages_ssr_resolve_options_context(),
|
||||||
|
)
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub(super) fn pages_ssr_data_module_context(self) -> AssetContextVc {
|
||||||
|
ModuleAssetContextVc::new(
|
||||||
|
self.pages_transitions(),
|
||||||
|
self.server_compile_time_info(),
|
||||||
|
self.pages_ssr_data_module_options_context(),
|
||||||
|
self.pages_ssr_resolve_options_context(),
|
||||||
|
)
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn pages_ssr_module_options_context(self) -> Result<ModuleOptionsContextVc> {
|
||||||
|
let this = self.await?;
|
||||||
|
Ok(get_server_module_options_context(
|
||||||
|
self.project_path(),
|
||||||
|
self.execution_context(),
|
||||||
|
Value::new(ServerContextType::Pages {
|
||||||
|
pages_dir: self.pages_dir(),
|
||||||
|
}),
|
||||||
|
this.mode,
|
||||||
|
self.next_config(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn pages_ssr_data_module_options_context(self) -> Result<ModuleOptionsContextVc> {
|
||||||
|
let this = self.await?;
|
||||||
|
Ok(get_server_module_options_context(
|
||||||
|
self.project_path(),
|
||||||
|
self.execution_context(),
|
||||||
|
Value::new(ServerContextType::PagesData {
|
||||||
|
pages_dir: self.pages_dir(),
|
||||||
|
}),
|
||||||
|
this.mode,
|
||||||
|
self.next_config(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn pages_ssr_resolve_options_context(self) -> Result<ResolveOptionsContextVc> {
|
||||||
|
let this = self.await?;
|
||||||
|
Ok(get_server_resolve_options_context(
|
||||||
|
self.project_path(),
|
||||||
|
Value::new(ServerContextType::Pages {
|
||||||
|
pages_dir: self.pages_dir(),
|
||||||
|
}),
|
||||||
|
this.mode,
|
||||||
|
self.next_config(),
|
||||||
|
self.execution_context(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub(super) async fn pages_client_runtime_entries(self) -> Result<EvaluatableAssetsVc> {
|
||||||
|
let this = self.await?;
|
||||||
|
let client_runtime_entries = get_client_runtime_entries(
|
||||||
|
self.project_path(),
|
||||||
|
self.env(),
|
||||||
|
Value::new(ClientContextType::Pages {
|
||||||
|
pages_dir: self.pages_dir(),
|
||||||
|
}),
|
||||||
|
this.mode,
|
||||||
|
self.next_config(),
|
||||||
|
self.execution_context(),
|
||||||
|
);
|
||||||
|
Ok(client_runtime_entries.resolve_entries(self.pages_client_module_context()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub(super) async fn pages_ssr_runtime_entries(self) -> Result<EvaluatableAssetsVc> {
|
||||||
|
let this = self.await?;
|
||||||
|
let ssr_runtime_entries = get_server_runtime_entries(
|
||||||
|
self.project_path(),
|
||||||
|
self.env(),
|
||||||
|
Value::new(ServerContextType::Pages {
|
||||||
|
pages_dir: self.pages_dir(),
|
||||||
|
}),
|
||||||
|
this.mode,
|
||||||
|
self.next_config(),
|
||||||
|
);
|
||||||
|
Ok(ssr_runtime_entries.resolve_entries(self.pages_ssr_module_context()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub(super) async fn client_chunking_context(self) -> Result<EcmascriptChunkingContextVc> {
|
||||||
|
let this = self.await?;
|
||||||
|
Ok(get_client_chunking_context(
|
||||||
|
self.project_path(),
|
||||||
|
self.client_root(),
|
||||||
|
self.client_compile_time_info().environment(),
|
||||||
|
this.mode,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub(super) fn server_chunking_context(self) -> BuildChunkingContextVc {
|
||||||
|
get_server_chunking_context(
|
||||||
|
self.project_path(),
|
||||||
|
self.node_root(),
|
||||||
|
self.client_fs().root(),
|
||||||
|
self.server_compile_time_info().environment(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub(super) async fn ssr_chunking_context(self) -> Result<BuildChunkingContextVc> {
|
||||||
|
let ssr_chunking_context = self.server_chunking_context().with_layer("ssr");
|
||||||
|
BuildChunkingContextVc::resolve_from(ssr_chunking_context)
|
||||||
|
.await?
|
||||||
|
.context("with_layer should not change the type of the chunking context")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub(super) async fn ssr_data_chunking_context(self) -> Result<BuildChunkingContextVc> {
|
||||||
|
let ssr_chunking_context = self.server_chunking_context().with_layer("ssr data");
|
||||||
|
BuildChunkingContextVc::resolve_from(ssr_chunking_context)
|
||||||
|
.await?
|
||||||
|
.context("with_layer should not change the type of the chunking context")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub(super) async fn rsc_chunking_context(self) -> Result<BuildChunkingContextVc> {
|
||||||
|
let rsc_chunking_context = self.server_chunking_context().with_layer("rsc");
|
||||||
|
BuildChunkingContextVc::resolve_from(rsc_chunking_context)
|
||||||
|
.await?
|
||||||
|
.context("with_layer should not change the type of the chunking context")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Scans the app/pages directories for entry points files (matching the
|
||||||
|
/// provided page_extensions).
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub async fn entrypoints(self) -> Result<EntrypointsVc> {
|
||||||
|
let this = self.await?;
|
||||||
|
let mut routes = IndexMap::new();
|
||||||
|
if let Some(app_dir) = *find_app_dir(self.project_path()).await? {
|
||||||
|
let app_entrypoints = get_entrypoints(app_dir, this.next_config.page_extensions());
|
||||||
|
routes.extend(
|
||||||
|
app_entrypoints
|
||||||
|
.await?
|
||||||
|
.iter()
|
||||||
|
.map(|(pathname, app_entrypoint)| async {
|
||||||
|
Ok((
|
||||||
|
pathname.clone(),
|
||||||
|
*app_entry_point_to_route(*app_entrypoint).await?,
|
||||||
|
))
|
||||||
|
})
|
||||||
|
.try_join()
|
||||||
|
.await?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for (pathname, page_route) in get_pages_routes(self, self.pages_structure()).await?.iter() {
|
||||||
|
match routes.entry(pathname.clone()) {
|
||||||
|
Entry::Occupied(mut entry) => {
|
||||||
|
*entry.get_mut() = Route::Conflict;
|
||||||
|
}
|
||||||
|
Entry::Vacant(entry) => {
|
||||||
|
entry.insert(*page_route);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO middleware
|
||||||
|
Ok(Entrypoints {
|
||||||
|
routes,
|
||||||
|
middleware: None,
|
||||||
|
}
|
||||||
|
.cell())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emits opaque HMR events whenever a change is detected in the chunk group
|
||||||
|
/// internally known as `identifier`.
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub fn hmr_events(self, _identifier: String, _sender: TransientValue<()>) -> NothingVc {
|
||||||
|
NothingVc::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn project_fs(project_dir: &str, watching: bool) -> Result<FileSystemVc> {
|
||||||
|
let disk_fs =
|
||||||
|
DiskFileSystemVc::new(PROJECT_FILESYSTEM_NAME.to_string(), project_dir.to_string());
|
||||||
|
if watching {
|
||||||
|
disk_fs.await?.start_watching_with_invalidation_reason()?;
|
||||||
|
}
|
||||||
|
Ok(disk_fs.into())
|
||||||
|
}
|
43
packages/next-swc/crates/next-api/src/route.rs
Normal file
43
packages/next-swc/crates/next-api/src/route.rs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use indexmap::IndexMap;
|
||||||
|
use turbo_tasks::CompletionVc;
|
||||||
|
|
||||||
|
#[turbo_tasks::value(shared)]
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum Route {
|
||||||
|
Page {
|
||||||
|
html_endpoint: EndpointVc,
|
||||||
|
data_endpoint: EndpointVc,
|
||||||
|
},
|
||||||
|
PageApi {
|
||||||
|
endpoint: EndpointVc,
|
||||||
|
},
|
||||||
|
AppPage {
|
||||||
|
html_endpoint: EndpointVc,
|
||||||
|
rsc_endpoint: EndpointVc,
|
||||||
|
},
|
||||||
|
AppRoute {
|
||||||
|
endpoint: EndpointVc,
|
||||||
|
},
|
||||||
|
Conflict,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::value_trait]
|
||||||
|
pub trait Endpoint {
|
||||||
|
fn write_to_disk(&self) -> WrittenEndpointVc;
|
||||||
|
fn changed(&self) -> CompletionVc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::value(shared)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct WrittenEndpoint {
|
||||||
|
/// Relative to the root_path
|
||||||
|
pub server_entry_path: String,
|
||||||
|
/// Relative to the root_path
|
||||||
|
pub server_paths: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The routes as map from pathname to route. (pathname includes the leading
|
||||||
|
/// slash)
|
||||||
|
#[turbo_tasks::value(transparent)]
|
||||||
|
pub struct Routes(IndexMap<String, Route>);
|
|
@ -68,7 +68,11 @@ pub async fn get_page_entries(
|
||||||
server_compile_time_info: CompileTimeInfoVc,
|
server_compile_time_info: CompileTimeInfoVc,
|
||||||
next_config: NextConfigVc,
|
next_config: NextConfigVc,
|
||||||
) -> Result<PageEntriesVc> {
|
) -> Result<PageEntriesVc> {
|
||||||
let pages_structure = find_pages_structure(project_root, next_router_root, next_config);
|
let pages_structure = find_pages_structure(
|
||||||
|
project_root,
|
||||||
|
next_router_root,
|
||||||
|
next_config.page_extensions(),
|
||||||
|
);
|
||||||
|
|
||||||
let pages_dir = if let Some(pages) = pages_structure.await?.pages {
|
let pages_dir = if let Some(pages) = pages_structure.await?.pages {
|
||||||
pages.project_path().resolve().await?
|
pages.project_path().resolve().await?
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
"check": "tsc --noEmit"
|
"check": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vercel/turbopack-ecmascript-runtime": "https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230713.2",
|
"@vercel/turbopack-ecmascript-runtime": "https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230713.3",
|
||||||
"@vercel/turbopack-node": "https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-node/js?turbopack-230713.2",
|
"@vercel/turbopack-node": "https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-node/js?turbopack-230713.3",
|
||||||
"anser": "^2.1.1",
|
"anser": "^2.1.1",
|
||||||
"css.escape": "^1.5.1",
|
"css.escape": "^1.5.1",
|
||||||
"next": "*",
|
"next": "*",
|
||||||
|
|
|
@ -16,10 +16,6 @@ const loadNextConfig = async (silent) => {
|
||||||
|
|
||||||
const customRoutes = await loadCustomRoutes(nextConfig)
|
const customRoutes = await loadCustomRoutes(nextConfig)
|
||||||
|
|
||||||
nextConfig.headers = customRoutes.headers
|
|
||||||
nextConfig.rewrites = customRoutes.rewrites
|
|
||||||
nextConfig.redirects = customRoutes.redirects
|
|
||||||
|
|
||||||
// TODO: these functions takes arguments, have to be supported in a different way
|
// TODO: these functions takes arguments, have to be supported in a different way
|
||||||
nextConfig.exportPathMap = nextConfig.exportPathMap && {}
|
nextConfig.exportPathMap = nextConfig.exportPathMap && {}
|
||||||
nextConfig.webpack = nextConfig.webpack && {}
|
nextConfig.webpack = nextConfig.webpack && {}
|
||||||
|
@ -30,7 +26,10 @@ const loadNextConfig = async (silent) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nextConfig
|
return {
|
||||||
|
customRoutes: customRoutes,
|
||||||
|
config: nextConfig,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { loadNextConfig as default }
|
export { loadNextConfig as default }
|
||||||
|
|
|
@ -12,7 +12,7 @@ use turbo_tasks::{
|
||||||
debug::ValueDebugFormat,
|
debug::ValueDebugFormat,
|
||||||
primitives::{StringVc, StringsVc},
|
primitives::{StringVc, StringsVc},
|
||||||
trace::TraceRawVcs,
|
trace::TraceRawVcs,
|
||||||
CompletionVc, CompletionsVc,
|
CompletionVc, CompletionsVc, TaskInput, ValueToString,
|
||||||
};
|
};
|
||||||
use turbopack_binding::{
|
use turbopack_binding::{
|
||||||
turbo::tasks_fs::{DirectoryContent, DirectoryEntry, FileSystemEntryType, FileSystemPathVc},
|
turbo::tasks_fs::{DirectoryContent, DirectoryEntry, FileSystemEntryType, FileSystemPathVc},
|
||||||
|
@ -297,11 +297,11 @@ fn match_metadata_file<'a>(
|
||||||
|
|
||||||
#[turbo_tasks::function]
|
#[turbo_tasks::function]
|
||||||
async fn get_directory_tree(
|
async fn get_directory_tree(
|
||||||
app_dir: FileSystemPathVc,
|
dir: FileSystemPathVc,
|
||||||
page_extensions: StringsVc,
|
page_extensions: StringsVc,
|
||||||
) -> Result<DirectoryTreeVc> {
|
) -> Result<DirectoryTreeVc> {
|
||||||
let DirectoryContent::Entries(entries) = &*app_dir.read_dir().await? else {
|
let DirectoryContent::Entries(entries) = &*dir.read_dir().await? else {
|
||||||
bail!("app_dir must be a directory")
|
bail!("{} must be a directory", dir.to_string().await?);
|
||||||
};
|
};
|
||||||
let page_extensions_value = page_extensions.await?;
|
let page_extensions_value = page_extensions.await?;
|
||||||
|
|
||||||
|
@ -451,7 +451,16 @@ async fn merge_loader_trees(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Copy, Clone, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs, ValueDebugFormat, Debug,
|
Copy,
|
||||||
|
Clone,
|
||||||
|
PartialEq,
|
||||||
|
Eq,
|
||||||
|
Serialize,
|
||||||
|
Deserialize,
|
||||||
|
TraceRawVcs,
|
||||||
|
ValueDebugFormat,
|
||||||
|
Debug,
|
||||||
|
TaskInput,
|
||||||
)]
|
)]
|
||||||
pub enum Entrypoint {
|
pub enum Entrypoint {
|
||||||
AppPage { loader_tree: LoaderTreeVc },
|
AppPage { loader_tree: LoaderTreeVc },
|
||||||
|
|
97
packages/next-swc/crates/next-core/src/emit.rs
Normal file
97
packages/next-swc/crates/next-core/src/emit.rs
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use turbo_tasks::{
|
||||||
|
graph::{AdjacencyMap, GraphTraversal},
|
||||||
|
CompletionVc, CompletionsVc, TryJoinIterExt,
|
||||||
|
};
|
||||||
|
use turbo_tasks_fs::{rebase, FileSystemPathVc};
|
||||||
|
use turbopack_binding::turbopack::core::{
|
||||||
|
asset::Asset,
|
||||||
|
output::{OutputAssetVc, OutputAssetsVc},
|
||||||
|
reference::AssetReference,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Emits all assets transitively reachable from the given chunks, that are
|
||||||
|
/// inside the node root or the client root.
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub async fn emit_all_assets(
|
||||||
|
assets: OutputAssetsVc,
|
||||||
|
node_root: FileSystemPathVc,
|
||||||
|
client_relative_path: FileSystemPathVc,
|
||||||
|
client_output_path: FileSystemPathVc,
|
||||||
|
) -> Result<CompletionVc> {
|
||||||
|
let all_assets = all_assets_from_entries(assets).await?;
|
||||||
|
Ok(CompletionsVc::all(
|
||||||
|
all_assets
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(|asset| async move {
|
||||||
|
if asset.ident().path().await?.is_inside(&*node_root.await?) {
|
||||||
|
return Ok(emit(asset));
|
||||||
|
} else if asset
|
||||||
|
.ident()
|
||||||
|
.path()
|
||||||
|
.await?
|
||||||
|
.is_inside(&*client_relative_path.await?)
|
||||||
|
{
|
||||||
|
// Client assets are emitted to the client output path, which is prefixed with
|
||||||
|
// _next. We need to rebase them to remove that prefix.
|
||||||
|
return Ok(emit_rebase(asset, client_relative_path, client_output_path));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(CompletionVc::immutable())
|
||||||
|
})
|
||||||
|
.try_join()
|
||||||
|
.await?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
fn emit(asset: OutputAssetVc) -> CompletionVc {
|
||||||
|
asset.content().write(asset.ident().path())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
fn emit_rebase(asset: OutputAssetVc, from: FileSystemPathVc, to: FileSystemPathVc) -> CompletionVc {
|
||||||
|
asset
|
||||||
|
.content()
|
||||||
|
.write(rebase(asset.ident().path(), from, to))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Walks the asset graph from multiple assets and collect all referenced
|
||||||
|
/// assets.
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn all_assets_from_entries(entries: OutputAssetsVc) -> Result<OutputAssetsVc> {
|
||||||
|
Ok(OutputAssetsVc::cell(
|
||||||
|
AdjacencyMap::new()
|
||||||
|
.skip_duplicates()
|
||||||
|
.visit(entries.await?.iter().copied(), get_referenced_assets)
|
||||||
|
.await
|
||||||
|
.completed()?
|
||||||
|
.into_inner()
|
||||||
|
.into_reverse_topological()
|
||||||
|
.collect(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Computes the list of all chunk children of a given chunk.
|
||||||
|
async fn get_referenced_assets(
|
||||||
|
asset: OutputAssetVc,
|
||||||
|
) -> Result<impl Iterator<Item = OutputAssetVc> + Send> {
|
||||||
|
Ok(asset
|
||||||
|
.references()
|
||||||
|
.await?
|
||||||
|
.iter()
|
||||||
|
.map(|reference| async move {
|
||||||
|
let primary_assets = reference.resolve_reference().primary_assets().await?;
|
||||||
|
Ok(primary_assets.clone_value())
|
||||||
|
})
|
||||||
|
.try_join()
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.map(|asset| async move { Ok(OutputAssetVc::resolve_from(asset).await?) })
|
||||||
|
.try_join()
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.flatten())
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ pub mod app_structure;
|
||||||
mod babel;
|
mod babel;
|
||||||
mod bootstrap;
|
mod bootstrap;
|
||||||
mod embed_js;
|
mod embed_js;
|
||||||
|
mod emit;
|
||||||
pub mod env;
|
pub mod env;
|
||||||
mod fallback;
|
mod fallback;
|
||||||
pub mod loader_tree;
|
pub mod loader_tree;
|
||||||
|
@ -41,10 +42,11 @@ mod runtime;
|
||||||
mod sass;
|
mod sass;
|
||||||
mod transform_options;
|
mod transform_options;
|
||||||
pub mod url_node;
|
pub mod url_node;
|
||||||
mod util;
|
pub mod util;
|
||||||
mod web_entry_source;
|
mod web_entry_source;
|
||||||
|
|
||||||
pub use app_source::create_app_source;
|
pub use app_source::create_app_source;
|
||||||
|
pub use emit::emit_all_assets;
|
||||||
pub use next_app::unsupported_dynamic_metadata_issue::{
|
pub use next_app::unsupported_dynamic_metadata_issue::{
|
||||||
UnsupportedDynamicMetadataIssue, UnsupportedDynamicMetadataIssueVc,
|
UnsupportedDynamicMetadataIssue, UnsupportedDynamicMetadataIssueVc,
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,7 +26,7 @@ use turbopack_binding::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
embed_js::next_js_file,
|
embed_js::next_js_file,
|
||||||
next_config::{NextConfigVc, RewritesReadRef},
|
next_config::{RewritesReadRef, RewritesVc},
|
||||||
util::get_asset_path_from_pathname,
|
util::get_asset_path_from_pathname,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ use crate::{
|
||||||
#[turbo_tasks::value(shared)]
|
#[turbo_tasks::value(shared)]
|
||||||
pub struct DevManifestContentSource {
|
pub struct DevManifestContentSource {
|
||||||
pub page_roots: Vec<ContentSourceVc>,
|
pub page_roots: Vec<ContentSourceVc>,
|
||||||
pub next_config: NextConfigVc,
|
pub rewrites: RewritesVc,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[turbo_tasks::value_impl]
|
#[turbo_tasks::value_impl]
|
||||||
|
@ -124,7 +124,7 @@ impl DevManifestContentSourceVc {
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let manifest = BuildManifest {
|
let manifest = BuildManifest {
|
||||||
rewrites: this.next_config.rewrites().await?,
|
rewrites: this.rewrites.await?,
|
||||||
sorted_pages,
|
sorted_pages,
|
||||||
routes,
|
routes,
|
||||||
};
|
};
|
||||||
|
|
|
@ -45,6 +45,34 @@ use turbopack_binding::{
|
||||||
|
|
||||||
use crate::{embed_js::next_asset, next_shared::transforms::ModularizeImportPackageConfig};
|
use crate::{embed_js::next_asset, next_shared::transforms::ModularizeImportPackageConfig};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct NextConfigAndCustomRoutesRaw {
|
||||||
|
config: NextConfig,
|
||||||
|
custom_routes: CustomRoutesRaw,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::value]
|
||||||
|
struct NextConfigAndCustomRoutes {
|
||||||
|
config: NextConfigVc,
|
||||||
|
custom_routes: CustomRoutesVc,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct CustomRoutesRaw {
|
||||||
|
rewrites: Rewrites,
|
||||||
|
|
||||||
|
// unsupported
|
||||||
|
headers: Vec<Header>,
|
||||||
|
redirects: Vec<Redirect>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::value]
|
||||||
|
struct CustomRoutes {
|
||||||
|
rewrites: RewritesVc,
|
||||||
|
}
|
||||||
|
|
||||||
#[turbo_tasks::value(serialization = "custom", eq = "manual")]
|
#[turbo_tasks::value(serialization = "custom", eq = "manual")]
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
@ -57,7 +85,6 @@ pub struct NextConfig {
|
||||||
pub images: ImageConfig,
|
pub images: ImageConfig,
|
||||||
pub page_extensions: Vec<String>,
|
pub page_extensions: Vec<String>,
|
||||||
pub react_strict_mode: Option<bool>,
|
pub react_strict_mode: Option<bool>,
|
||||||
pub rewrites: Rewrites,
|
|
||||||
pub transpile_packages: Option<Vec<String>>,
|
pub transpile_packages: Option<Vec<String>>,
|
||||||
pub modularize_imports: Option<IndexMap<String, ModularizeImportPackageConfig>>,
|
pub modularize_imports: Option<IndexMap<String, ModularizeImportPackageConfig>>,
|
||||||
sass_options: Option<serde_json::Value>,
|
sass_options: Option<serde_json::Value>,
|
||||||
|
@ -84,7 +111,6 @@ pub struct NextConfig {
|
||||||
// this is a function in js land
|
// this is a function in js land
|
||||||
generate_build_id: Option<serde_json::Value>,
|
generate_build_id: Option<serde_json::Value>,
|
||||||
generate_etags: bool,
|
generate_etags: bool,
|
||||||
headers: Vec<Header>,
|
|
||||||
http_agent_options: HttpAgentConfig,
|
http_agent_options: HttpAgentConfig,
|
||||||
i18n: Option<I18NConfig>,
|
i18n: Option<I18NConfig>,
|
||||||
on_demand_entries: OnDemandEntriesConfig,
|
on_demand_entries: OnDemandEntriesConfig,
|
||||||
|
@ -93,7 +119,6 @@ pub struct NextConfig {
|
||||||
powered_by_header: bool,
|
powered_by_header: bool,
|
||||||
production_browser_source_maps: bool,
|
production_browser_source_maps: bool,
|
||||||
public_runtime_config: IndexMap<String, serde_json::Value>,
|
public_runtime_config: IndexMap<String, serde_json::Value>,
|
||||||
redirects: Vec<Redirect>,
|
|
||||||
server_runtime_config: IndexMap<String, serde_json::Value>,
|
server_runtime_config: IndexMap<String, serde_json::Value>,
|
||||||
static_page_generation_timeout: f64,
|
static_page_generation_timeout: f64,
|
||||||
swc_minify: bool,
|
swc_minify: bool,
|
||||||
|
@ -486,6 +511,13 @@ pub enum RemoveConsoleConfig {
|
||||||
|
|
||||||
#[turbo_tasks::value_impl]
|
#[turbo_tasks::value_impl]
|
||||||
impl NextConfigVc {
|
impl NextConfigVc {
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub fn from_string(s: String) -> Result<Self> {
|
||||||
|
let config: NextConfig = serde_json::from_str(&s)
|
||||||
|
.with_context(|| format!("failed to parse next.config.js: {}", s))?;
|
||||||
|
Ok(config.cell())
|
||||||
|
}
|
||||||
|
|
||||||
#[turbo_tasks::function]
|
#[turbo_tasks::function]
|
||||||
pub async fn server_component_externals(self) -> Result<StringsVc> {
|
pub async fn server_component_externals(self) -> Result<StringsVc> {
|
||||||
Ok(StringsVc::cell(
|
Ok(StringsVc::cell(
|
||||||
|
@ -545,11 +577,6 @@ impl NextConfigVc {
|
||||||
Ok(StringsVc::cell(self.await?.page_extensions.clone()))
|
Ok(StringsVc::cell(self.await?.page_extensions.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[turbo_tasks::function]
|
|
||||||
pub async fn rewrites(self) -> Result<RewritesVc> {
|
|
||||||
Ok(self.await?.rewrites.clone().cell())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[turbo_tasks::function]
|
#[turbo_tasks::function]
|
||||||
pub async fn transpile_packages(self) -> Result<StringsVc> {
|
pub async fn transpile_packages(self) -> Result<StringsVc> {
|
||||||
Ok(StringsVc::cell(
|
Ok(StringsVc::cell(
|
||||||
|
@ -646,22 +673,41 @@ fn next_configs() -> StringsVc {
|
||||||
|
|
||||||
#[turbo_tasks::function]
|
#[turbo_tasks::function]
|
||||||
pub async fn load_next_config(execution_context: ExecutionContextVc) -> Result<NextConfigVc> {
|
pub async fn load_next_config(execution_context: ExecutionContextVc) -> Result<NextConfigVc> {
|
||||||
|
Ok(load_config_and_custom_routes(execution_context)
|
||||||
|
.await?
|
||||||
|
.config)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
pub async fn load_rewrites(execution_context: ExecutionContextVc) -> Result<RewritesVc> {
|
||||||
|
Ok(load_config_and_custom_routes(execution_context)
|
||||||
|
.await?
|
||||||
|
.custom_routes
|
||||||
|
.await?
|
||||||
|
.rewrites)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[turbo_tasks::function]
|
||||||
|
async fn load_config_and_custom_routes(
|
||||||
|
execution_context: ExecutionContextVc,
|
||||||
|
) -> Result<NextConfigAndCustomRoutesVc> {
|
||||||
let ExecutionContext { project_path, .. } = *execution_context.await?;
|
let ExecutionContext { project_path, .. } = *execution_context.await?;
|
||||||
let find_config_result = find_context_file(project_path, next_configs());
|
let find_config_result = find_context_file(project_path, next_configs());
|
||||||
let config_file = match &*find_config_result.await? {
|
let config_file = match &*find_config_result.await? {
|
||||||
FindContextFileResult::Found(config_path, _) => Some(*config_path),
|
FindContextFileResult::Found(config_path, _) => Some(*config_path),
|
||||||
FindContextFileResult::NotFound(_) => None,
|
FindContextFileResult::NotFound(_) => None,
|
||||||
};
|
};
|
||||||
load_next_config_internal(execution_context, config_file)
|
|
||||||
|
load_next_config_and_custom_routes_internal(execution_context, config_file)
|
||||||
.issue_context(config_file, "Loading Next.js config")
|
.issue_context(config_file, "Loading Next.js config")
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[turbo_tasks::function]
|
#[turbo_tasks::function]
|
||||||
pub async fn load_next_config_internal(
|
async fn load_next_config_and_custom_routes_internal(
|
||||||
execution_context: ExecutionContextVc,
|
execution_context: ExecutionContextVc,
|
||||||
config_file: Option<FileSystemPathVc>,
|
config_file: Option<FileSystemPathVc>,
|
||||||
) -> Result<NextConfigVc> {
|
) -> Result<NextConfigAndCustomRoutesVc> {
|
||||||
let ExecutionContext {
|
let ExecutionContext {
|
||||||
project_path,
|
project_path,
|
||||||
chunking_context,
|
chunking_context,
|
||||||
|
@ -709,11 +755,24 @@ pub async fn load_next_config_internal(
|
||||||
.await
|
.await
|
||||||
.context("Evaluation of Next.js config failed")?
|
.context("Evaluation of Next.js config failed")?
|
||||||
else {
|
else {
|
||||||
return Ok(NextConfig::default().cell());
|
return Ok(NextConfigAndCustomRoutes {
|
||||||
|
config: NextConfig::default().cell(),
|
||||||
|
custom_routes: CustomRoutes {
|
||||||
|
rewrites: Rewrites::default().cell(),
|
||||||
|
}
|
||||||
|
.cell(),
|
||||||
|
}
|
||||||
|
.cell());
|
||||||
};
|
};
|
||||||
let next_config: NextConfig = parse_json_with_source_context(val.to_str()?)?;
|
let next_config_and_custom_routes: NextConfigAndCustomRoutesRaw =
|
||||||
|
parse_json_with_source_context(val.to_str()?)?;
|
||||||
|
|
||||||
if let Some(turbo) = next_config.experimental.turbo.as_ref() {
|
if let Some(turbo) = next_config_and_custom_routes
|
||||||
|
.config
|
||||||
|
.experimental
|
||||||
|
.turbo
|
||||||
|
.as_ref()
|
||||||
|
{
|
||||||
if turbo.loaders.is_some() {
|
if turbo.loaders.is_some() {
|
||||||
OutdatedConfigIssue {
|
OutdatedConfigIssue {
|
||||||
path: config_file.unwrap_or(project_path),
|
path: config_file.unwrap_or(project_path),
|
||||||
|
@ -730,7 +789,14 @@ Example: loaders: { \".mdx\": [\"mdx-loader\"] } -> rules: { \"*.mdx\": [\"mdx-l
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(next_config.cell())
|
Ok(NextConfigAndCustomRoutes {
|
||||||
|
config: next_config_and_custom_routes.config.cell(),
|
||||||
|
custom_routes: CustomRoutes {
|
||||||
|
rewrites: next_config_and_custom_routes.custom_routes.rewrites.cell(),
|
||||||
|
}
|
||||||
|
.cell(),
|
||||||
|
}
|
||||||
|
.cell())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[turbo_tasks::function]
|
#[turbo_tasks::function]
|
||||||
|
|
|
@ -5,7 +5,7 @@ use turbopack_binding::turbo::tasks_fs::{
|
||||||
DirectoryContent, DirectoryEntry, FileSystemEntryType, FileSystemPathVc,
|
DirectoryContent, DirectoryEntry, FileSystemEntryType, FileSystemPathVc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{embed_js::next_js_file_path, next_config::NextConfigVc};
|
use crate::embed_js::next_js_file_path;
|
||||||
|
|
||||||
/// A final route in the pages directory.
|
/// A final route in the pages directory.
|
||||||
#[turbo_tasks::value]
|
#[turbo_tasks::value]
|
||||||
|
@ -125,7 +125,7 @@ impl PagesDirectoryStructureVc {
|
||||||
pub async fn find_pages_structure(
|
pub async fn find_pages_structure(
|
||||||
project_root: FileSystemPathVc,
|
project_root: FileSystemPathVc,
|
||||||
next_router_root: FileSystemPathVc,
|
next_router_root: FileSystemPathVc,
|
||||||
next_config: NextConfigVc,
|
page_extensions: StringsVc,
|
||||||
) -> Result<PagesStructureVc> {
|
) -> Result<PagesStructureVc> {
|
||||||
let pages_root = project_root.join("pages");
|
let pages_root = project_root.join("pages");
|
||||||
let pages_root: FileSystemPathOptionVc = FileSystemPathOptionVc::cell(
|
let pages_root: FileSystemPathOptionVc = FileSystemPathOptionVc::cell(
|
||||||
|
@ -149,7 +149,7 @@ pub async fn find_pages_structure(
|
||||||
Ok(get_pages_structure_for_root_directory(
|
Ok(get_pages_structure_for_root_directory(
|
||||||
pages_root,
|
pages_root,
|
||||||
next_router_root,
|
next_router_root,
|
||||||
next_config.page_extensions(),
|
page_extensions,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ use next_core::{
|
||||||
manifest::DevManifestContentSource,
|
manifest::DevManifestContentSource,
|
||||||
mode::NextMode,
|
mode::NextMode,
|
||||||
next_client::{get_client_chunking_context, get_client_compile_time_info},
|
next_client::{get_client_chunking_context, get_client_compile_time_info},
|
||||||
next_config::load_next_config,
|
next_config::{load_next_config, load_rewrites},
|
||||||
next_image::NextImageContentSourceVc,
|
next_image::NextImageContentSourceVc,
|
||||||
pages_structure::find_pages_structure,
|
pages_structure::find_pages_structure,
|
||||||
router_source::NextRouterContentSourceVc,
|
router_source::NextRouterContentSourceVc,
|
||||||
|
@ -335,7 +335,9 @@ async fn source(
|
||||||
ExecutionContextVc::new(project_path, build_chunking_context.into(), env);
|
ExecutionContextVc::new(project_path, build_chunking_context.into(), env);
|
||||||
|
|
||||||
let mode = NextMode::Development;
|
let mode = NextMode::Development;
|
||||||
let next_config = load_next_config(execution_context.with_layer("next_config"));
|
let next_config_execution_context = execution_context.with_layer("next_config");
|
||||||
|
let next_config = load_next_config(next_config_execution_context);
|
||||||
|
let rewrites = load_rewrites(next_config_execution_context);
|
||||||
|
|
||||||
let output_root = output_fs.root().join(".next/server");
|
let output_root = output_fs.root().join(".next/server");
|
||||||
|
|
||||||
|
@ -367,7 +369,8 @@ async fn source(
|
||||||
client_compile_time_info.environment(),
|
client_compile_time_info.environment(),
|
||||||
mode,
|
mode,
|
||||||
);
|
);
|
||||||
let pages_structure = find_pages_structure(project_path, dev_server_root, next_config);
|
let pages_structure =
|
||||||
|
find_pages_structure(project_path, dev_server_root, next_config.page_extensions());
|
||||||
let page_source = create_page_source(
|
let page_source = create_page_source(
|
||||||
pages_structure,
|
pages_structure,
|
||||||
project_path,
|
project_path,
|
||||||
|
@ -402,7 +405,7 @@ async fn source(
|
||||||
StaticAssetsContentSourceVc::new(String::new(), project_path.join("public")).into();
|
StaticAssetsContentSourceVc::new(String::new(), project_path.join("public")).into();
|
||||||
let manifest_source = DevManifestContentSource {
|
let manifest_source = DevManifestContentSource {
|
||||||
page_roots: vec![page_source],
|
page_roots: vec![page_source],
|
||||||
next_config,
|
rewrites,
|
||||||
}
|
}
|
||||||
.cell()
|
.cell()
|
||||||
.into();
|
.into();
|
||||||
|
|
|
@ -939,7 +939,7 @@ export default async function build(
|
||||||
ignore: [] as string[],
|
ignore: [] as string[],
|
||||||
}))
|
}))
|
||||||
|
|
||||||
let binding = (await loadBindings()) as any
|
let binding = await loadBindings()
|
||||||
|
|
||||||
async function turbopackBuild() {
|
async function turbopackBuild() {
|
||||||
const turboNextBuildStart = process.hrtime()
|
const turboNextBuildStart = process.hrtime()
|
||||||
|
|
|
@ -9,6 +9,8 @@ import { eventSwcLoadFailure } from '../../telemetry/events/swc-load-failure'
|
||||||
import { patchIncorrectLockfile } from '../../lib/patch-incorrect-lockfile'
|
import { patchIncorrectLockfile } from '../../lib/patch-incorrect-lockfile'
|
||||||
import { downloadWasmSwc } from '../../lib/download-wasm-swc'
|
import { downloadWasmSwc } from '../../lib/download-wasm-swc'
|
||||||
import { spawn } from 'child_process'
|
import { spawn } from 'child_process'
|
||||||
|
import { NextConfigComplete, TurboLoaderItem } from '../../server/config-shared'
|
||||||
|
import { isDeepStrictEqual } from 'util'
|
||||||
|
|
||||||
const nextVersion = process.env.__NEXT_VERSION as string
|
const nextVersion = process.env.__NEXT_VERSION as string
|
||||||
|
|
||||||
|
@ -88,7 +90,38 @@ let swcHeapProfilerFlushGuard: any
|
||||||
let swcCrashReporterFlushGuard: any
|
let swcCrashReporterFlushGuard: any
|
||||||
export const lockfilePatchPromise: { cur?: Promise<void> } = {}
|
export const lockfilePatchPromise: { cur?: Promise<void> } = {}
|
||||||
|
|
||||||
export async function loadBindings(): Promise<any> {
|
export interface Binding {
|
||||||
|
isWasm: boolean
|
||||||
|
turbo: {
|
||||||
|
startDev: any
|
||||||
|
startTrace: any
|
||||||
|
nextBuild?: any
|
||||||
|
createTurboTasks?: any
|
||||||
|
entrypoints: {
|
||||||
|
stream: any
|
||||||
|
get: any
|
||||||
|
}
|
||||||
|
mdx: {
|
||||||
|
compile: any
|
||||||
|
compileSync: any
|
||||||
|
}
|
||||||
|
createProject: (options: ProjectOptions) => Promise<Project>
|
||||||
|
}
|
||||||
|
minify: any
|
||||||
|
minifySync: any
|
||||||
|
transform: any
|
||||||
|
transformSync: any
|
||||||
|
parse: any
|
||||||
|
parseSync: any
|
||||||
|
getTargetTriple(): string | undefined
|
||||||
|
initCustomTraceSubscriber?: any
|
||||||
|
teardownTraceSubscriber?: any
|
||||||
|
initHeapProfiler?: any
|
||||||
|
teardownHeapProfiler?: any
|
||||||
|
teardownCrashReporter?: any
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function loadBindings(): Promise<Binding> {
|
||||||
if (pendingBindings) {
|
if (pendingBindings) {
|
||||||
return pendingBindings
|
return pendingBindings
|
||||||
}
|
}
|
||||||
|
@ -236,6 +269,379 @@ function logLoadFailure(attempts: any, triedWasm = false) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ProjectOptions {
|
||||||
|
/**
|
||||||
|
* A root path from which all files must be nested under. Trying to access
|
||||||
|
* a file outside this root will fail. Think of this as a chroot.
|
||||||
|
*/
|
||||||
|
rootPath: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A path inside the root_path which contains the app/pages directories.
|
||||||
|
*/
|
||||||
|
projectPath: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The next.config.js contents.
|
||||||
|
*/
|
||||||
|
nextConfig: NextConfigComplete
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to watch he filesystem for file changes.
|
||||||
|
*/
|
||||||
|
watch: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An upper bound of memory that turbopack will attempt to stay under.
|
||||||
|
*/
|
||||||
|
memoryLimit?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Issue {}
|
||||||
|
|
||||||
|
interface Diagnostics {}
|
||||||
|
|
||||||
|
type TurbopackResult<T = {}> = T & {
|
||||||
|
issues: Issue[]
|
||||||
|
diagnostics: Diagnostics[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Middleware {
|
||||||
|
endpoint: Endpoint
|
||||||
|
runtime: 'nodejs' | 'edge'
|
||||||
|
matcher?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Entrypoints {
|
||||||
|
routes: Map<string, Route>
|
||||||
|
middleware?: Middleware
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Project {
|
||||||
|
entrypointsSubscribe(): AsyncIterableIterator<TurbopackResult<Entrypoints>>
|
||||||
|
}
|
||||||
|
|
||||||
|
type Route =
|
||||||
|
| {
|
||||||
|
type: 'conflict'
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'app-page'
|
||||||
|
htmlEndpoint: Endpoint
|
||||||
|
rscEndpoint: Endpoint
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'app-route'
|
||||||
|
endpoint: Endpoint
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'page'
|
||||||
|
htmlEndpoint: Endpoint
|
||||||
|
dataEndpoint: Endpoint
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'page-api'
|
||||||
|
endpoint: Endpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Endpoint {
|
||||||
|
/** Write files for the endpoint to disk. */
|
||||||
|
writeToDisk(): Promise<TurbopackResult<WrittenEndpoint>>
|
||||||
|
/**
|
||||||
|
* Listen to changes to the endpoint.
|
||||||
|
* After changed() has been awaited it will listen to changes.
|
||||||
|
* The async iterator will yield for each change.
|
||||||
|
*/
|
||||||
|
changed(): Promise<AsyncIterableIterator<TurbopackResult>>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EndpointConfig {
|
||||||
|
dynamic?: 'auto' | 'force-dynamic' | 'error' | 'force-static'
|
||||||
|
dynamicParams?: boolean
|
||||||
|
revalidate?: 'never' | 'force-cache' | number
|
||||||
|
fetchCache?:
|
||||||
|
| 'auto'
|
||||||
|
| 'default-cache'
|
||||||
|
| 'only-cache'
|
||||||
|
| 'force-cache'
|
||||||
|
| 'default-no-store'
|
||||||
|
| 'only-no-store'
|
||||||
|
| 'force-no-store'
|
||||||
|
runtime?: 'nodejs' | 'edge'
|
||||||
|
preferredRegion?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WrittenEndpoint {
|
||||||
|
/** The entry path for the endpoint. */
|
||||||
|
entryPath: string
|
||||||
|
/** All paths that has been written for the endpoint. */
|
||||||
|
paths: string[]
|
||||||
|
config: EndpointConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(sokra) Support wasm option.
|
||||||
|
function bindingToApi(binding: any, _wasm: boolean) {
|
||||||
|
type NativeFunction<T> = (
|
||||||
|
callback: (err: Error, value: T) => void
|
||||||
|
) => Promise<{ __napiType: 'RootTask' }>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility function to ensure all variants of an enum are handled.
|
||||||
|
*/
|
||||||
|
function invariant(
|
||||||
|
never: never,
|
||||||
|
computeMessage: (arg: any) => string
|
||||||
|
): never {
|
||||||
|
throw new Error(`Invariant: ${computeMessage(never)}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls a native function and streams the result.
|
||||||
|
* If useBuffer is true, all values will be preserved, potentially buffered
|
||||||
|
* if consumed slower than produced. Else, only the latest value will be
|
||||||
|
* preserved.
|
||||||
|
*/
|
||||||
|
function subscribe<T>(
|
||||||
|
useBuffer: boolean,
|
||||||
|
nativeFunction: NativeFunction<T>
|
||||||
|
): AsyncIterableIterator<T> {
|
||||||
|
type BufferItem =
|
||||||
|
| { err: Error; value: undefined }
|
||||||
|
| { err: undefined; value: T }
|
||||||
|
// A buffer of produced items. This will only contain values if the
|
||||||
|
// consumer is slower than the producer.
|
||||||
|
let buffer: BufferItem[] = []
|
||||||
|
// A deferred value waiting for the next produced item. This will only
|
||||||
|
// exist if the consumer is faster than the producer.
|
||||||
|
let waiting:
|
||||||
|
| {
|
||||||
|
resolve: (value: T) => void
|
||||||
|
reject: (error: Error) => void
|
||||||
|
}
|
||||||
|
| undefined
|
||||||
|
|
||||||
|
// The native function will call this every time it emits a new result. We
|
||||||
|
// either need to notify a waiting consumer, or buffer the new result until
|
||||||
|
// the consumer catches up.
|
||||||
|
const emitResult = (err: Error | undefined, value: T | undefined) => {
|
||||||
|
if (waiting) {
|
||||||
|
let { resolve, reject } = waiting
|
||||||
|
waiting = undefined
|
||||||
|
if (err) reject(err)
|
||||||
|
else resolve(value!)
|
||||||
|
} else {
|
||||||
|
const item = { err, value } as BufferItem
|
||||||
|
if (useBuffer) buffer.push(item)
|
||||||
|
else buffer[0] = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (async function* () {
|
||||||
|
const task = await nativeFunction(emitResult)
|
||||||
|
try {
|
||||||
|
while (true) {
|
||||||
|
if (buffer.length > 0) {
|
||||||
|
const item = buffer.shift()!
|
||||||
|
if (item.err) throw item.err
|
||||||
|
yield item.value
|
||||||
|
} else {
|
||||||
|
// eslint-disable-next-line no-loop-func
|
||||||
|
yield new Promise<T>((resolve, reject) => {
|
||||||
|
waiting = { resolve, reject }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
binding.rootTaskDispose(task)
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProjectImpl implements Project {
|
||||||
|
private _nativeProject: { __napiType: 'Project' }
|
||||||
|
|
||||||
|
constructor(nativeProject: { __napiType: 'Project' }) {
|
||||||
|
this._nativeProject = nativeProject
|
||||||
|
}
|
||||||
|
|
||||||
|
entrypointsSubscribe() {
|
||||||
|
type NapiEndpoint = { __napiType: 'Endpoint' }
|
||||||
|
|
||||||
|
type NapiEntrypoints = {
|
||||||
|
routes: NapiRoute[]
|
||||||
|
middleware?: NapiMiddleware
|
||||||
|
issues: Issue[]
|
||||||
|
diagnostics: Diagnostics[]
|
||||||
|
}
|
||||||
|
|
||||||
|
type NapiMiddleware = {
|
||||||
|
endpoint: NapiEndpoint
|
||||||
|
runtime: 'nodejs' | 'edge'
|
||||||
|
matcher?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
type NapiRoute = {
|
||||||
|
pathname: string
|
||||||
|
} & (
|
||||||
|
| {
|
||||||
|
type: 'page'
|
||||||
|
htmlEndpoint: NapiEndpoint
|
||||||
|
dataEndpoint: NapiEndpoint
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'page-api'
|
||||||
|
endpoint: NapiEndpoint
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'app-page'
|
||||||
|
htmlEndpoint: NapiEndpoint
|
||||||
|
rscEndpoint: NapiEndpoint
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'app-route'
|
||||||
|
endpoint: NapiEndpoint
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'conflict'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const subscription = subscribe<NapiEntrypoints>(false, async (callback) =>
|
||||||
|
binding.projectEntrypointsSubscribe(await this._nativeProject, callback)
|
||||||
|
)
|
||||||
|
return (async function* () {
|
||||||
|
for await (const entrypoints of subscription) {
|
||||||
|
const routes = new Map()
|
||||||
|
for (const { pathname, ...nativeRoute } of entrypoints.routes) {
|
||||||
|
let route: Route
|
||||||
|
switch (nativeRoute.type) {
|
||||||
|
case 'page':
|
||||||
|
route = {
|
||||||
|
type: 'page',
|
||||||
|
htmlEndpoint: new EndpointImpl(nativeRoute.htmlEndpoint),
|
||||||
|
dataEndpoint: new EndpointImpl(nativeRoute.dataEndpoint),
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'page-api':
|
||||||
|
route = {
|
||||||
|
type: 'page-api',
|
||||||
|
endpoint: new EndpointImpl(nativeRoute.endpoint),
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'app-page':
|
||||||
|
route = {
|
||||||
|
type: 'app-page',
|
||||||
|
htmlEndpoint: new EndpointImpl(nativeRoute.htmlEndpoint),
|
||||||
|
rscEndpoint: new EndpointImpl(nativeRoute.rscEndpoint),
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'app-route':
|
||||||
|
route = {
|
||||||
|
type: 'app-route',
|
||||||
|
endpoint: new EndpointImpl(nativeRoute.endpoint),
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'conflict':
|
||||||
|
route = {
|
||||||
|
type: 'conflict',
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
invariant(
|
||||||
|
nativeRoute,
|
||||||
|
() => `Unknown route type: ${(nativeRoute as any).type}`
|
||||||
|
)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
routes.set(pathname, route)
|
||||||
|
}
|
||||||
|
const napiMiddlewareToMiddleware = (middleware: NapiMiddleware) => ({
|
||||||
|
endpoint: new EndpointImpl(middleware.endpoint),
|
||||||
|
runtime: middleware.runtime,
|
||||||
|
matcher: middleware.matcher,
|
||||||
|
})
|
||||||
|
const middleware = entrypoints.middleware
|
||||||
|
? napiMiddlewareToMiddleware(entrypoints.middleware)
|
||||||
|
: undefined
|
||||||
|
yield {
|
||||||
|
routes,
|
||||||
|
middleware,
|
||||||
|
issues: entrypoints.issues,
|
||||||
|
diagnostics: entrypoints.diagnostics,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EndpointImpl implements Endpoint {
|
||||||
|
private _nativeEndpoint: { __napiType: 'Endpoint' }
|
||||||
|
|
||||||
|
constructor(nativeEndpoint: { __napiType: 'Endpoint' }) {
|
||||||
|
this._nativeEndpoint = nativeEndpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
async writeToDisk(): Promise<TurbopackResult<WrittenEndpoint>> {
|
||||||
|
return await binding.endpointWriteToDisk(this._nativeEndpoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
async changed(): Promise<AsyncIterableIterator<TurbopackResult>> {
|
||||||
|
const iter = subscribe<TurbopackResult>(false, async (callback) =>
|
||||||
|
binding.endpointChangedSubscribe(await this._nativeEndpoint, callback)
|
||||||
|
)
|
||||||
|
await iter.next()
|
||||||
|
return iter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function serializeNextConfig(
|
||||||
|
nextConfig: NextConfigComplete
|
||||||
|
): Promise<string> {
|
||||||
|
let nextConfigSerializable = nextConfig as any
|
||||||
|
|
||||||
|
nextConfigSerializable.generateBuildId =
|
||||||
|
await nextConfig.generateBuildId?.()
|
||||||
|
|
||||||
|
// TODO: these functions takes arguments, have to be supported in a different way
|
||||||
|
nextConfigSerializable.exportPathMap = {}
|
||||||
|
nextConfigSerializable.webpack = nextConfig.webpack && {}
|
||||||
|
|
||||||
|
if (nextConfig.experimental?.turbo?.loaders) {
|
||||||
|
ensureLoadersHaveSerializableOptions(
|
||||||
|
nextConfig.experimental.turbo.loaders
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON.stringify(nextConfigSerializable)
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureLoadersHaveSerializableOptions(
|
||||||
|
turbopackLoaders: Record<string, TurboLoaderItem[]>
|
||||||
|
) {
|
||||||
|
for (const [ext, loaderItems] of Object.entries(turbopackLoaders)) {
|
||||||
|
for (const loaderItem of loaderItems) {
|
||||||
|
if (
|
||||||
|
typeof loaderItem !== 'string' &&
|
||||||
|
!isDeepStrictEqual(loaderItem, JSON.parse(JSON.stringify(loaderItem)))
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
`loader ${loaderItem.loader} for match "${ext}" does not have serializable options. Ensure that options passed are plain JavaScript objects and values.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createProject(options: ProjectOptions) {
|
||||||
|
const optionsForRust = options as any
|
||||||
|
optionsForRust.nextConfig = await serializeNextConfig(options.nextConfig)
|
||||||
|
|
||||||
|
return new ProjectImpl(await binding.projectNew(optionsForRust))
|
||||||
|
}
|
||||||
|
|
||||||
|
return createProject
|
||||||
|
}
|
||||||
|
|
||||||
async function loadWasm(importPath = '', isCustomTurbopack: boolean) {
|
async function loadWasm(importPath = '', isCustomTurbopack: boolean) {
|
||||||
if (wasmBindings) {
|
if (wasmBindings) {
|
||||||
return wasmBindings
|
return wasmBindings
|
||||||
|
@ -314,9 +720,6 @@ async function loadWasm(importPath = '', isCustomTurbopack: boolean) {
|
||||||
startTrace: () => {
|
startTrace: () => {
|
||||||
Log.error('Wasm binding does not support trace yet')
|
Log.error('Wasm binding does not support trace yet')
|
||||||
},
|
},
|
||||||
experimentalTurbo: () => {
|
|
||||||
Log.error('Wasm binding does not support this interface')
|
|
||||||
},
|
|
||||||
entrypoints: {
|
entrypoints: {
|
||||||
stream: (
|
stream: (
|
||||||
turboTasks: any,
|
turboTasks: any,
|
||||||
|
@ -577,12 +980,6 @@ function loadNative(isCustomTurbopack = false) {
|
||||||
)
|
)
|
||||||
return ret
|
return ret
|
||||||
},
|
},
|
||||||
experimentalTurbo: () => {
|
|
||||||
initHeapProfiler()
|
|
||||||
|
|
||||||
const ret = bindings.experimentalTurbo()
|
|
||||||
return ret
|
|
||||||
},
|
|
||||||
createTurboTasks: (memoryLimit?: number): unknown =>
|
createTurboTasks: (memoryLimit?: number): unknown =>
|
||||||
bindings.createTurboTasks(memoryLimit),
|
bindings.createTurboTasks(memoryLimit),
|
||||||
entrypoints: {
|
entrypoints: {
|
||||||
|
@ -615,6 +1012,7 @@ function loadNative(isCustomTurbopack = false) {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
createProject: bindingToApi(bindings, false),
|
||||||
},
|
},
|
||||||
mdx: {
|
mdx: {
|
||||||
compile: (src: string, options: any) =>
|
compile: (src: string, options: any) =>
|
||||||
|
|
|
@ -218,7 +218,7 @@ export class TraceEntryPointsPlugin implements webpack.WebpackPluginInstance {
|
||||||
|
|
||||||
// startTrace existed and callable
|
// startTrace existed and callable
|
||||||
if (this.turbotrace) {
|
if (this.turbotrace) {
|
||||||
let binding = (await loadBindings()) as any
|
let binding = await loadBindings()
|
||||||
if (
|
if (
|
||||||
!binding?.isWasm &&
|
!binding?.isWasm &&
|
||||||
typeof binding.turbo.startTrace === 'function'
|
typeof binding.turbo.startTrace === 'function'
|
||||||
|
@ -475,7 +475,7 @@ export class TraceEntryPointsPlugin implements webpack.WebpackPluginInstance {
|
||||||
})
|
})
|
||||||
// startTrace existed and callable
|
// startTrace existed and callable
|
||||||
if (this.turbotrace) {
|
if (this.turbotrace) {
|
||||||
let binding = (await loadBindings()) as any
|
let binding = await loadBindings()
|
||||||
if (
|
if (
|
||||||
!binding?.isWasm &&
|
!binding?.isWasm &&
|
||||||
typeof binding.turbo.startTrace === 'function'
|
typeof binding.turbo.startTrace === 'function'
|
||||||
|
@ -825,7 +825,7 @@ export class TraceEntryPointsPlugin implements webpack.WebpackPluginInstance {
|
||||||
|
|
||||||
if (this.turbotrace) {
|
if (this.turbotrace) {
|
||||||
compiler.hooks.afterEmit.tapPromise(PLUGIN_NAME, async () => {
|
compiler.hooks.afterEmit.tapPromise(PLUGIN_NAME, async () => {
|
||||||
let binding = (await loadBindings()) as any
|
let binding = await loadBindings()
|
||||||
if (
|
if (
|
||||||
!binding?.isWasm &&
|
!binding?.isWasm &&
|
||||||
typeof binding.turbo.startTrace === 'function'
|
typeof binding.turbo.startTrace === 'function'
|
||||||
|
|
|
@ -211,7 +211,6 @@ const nextDev: CliCommand = async (argv) => {
|
||||||
// We do not set a default host value here to prevent breaking
|
// We do not set a default host value here to prevent breaking
|
||||||
// some set-ups that rely on listening on other interfaces
|
// some set-ups that rely on listening on other interfaces
|
||||||
const host = args['--hostname']
|
const host = args['--hostname']
|
||||||
const experimentalTurbo = args['--experimental-turbo']
|
|
||||||
|
|
||||||
const devServerOptions: StartServerOptions = {
|
const devServerOptions: StartServerOptions = {
|
||||||
dir,
|
dir,
|
||||||
|
@ -221,14 +220,64 @@ const nextDev: CliCommand = async (argv) => {
|
||||||
hostname: host,
|
hostname: host,
|
||||||
// This is required especially for app dir.
|
// This is required especially for app dir.
|
||||||
useWorkers: true,
|
useWorkers: true,
|
||||||
isExperimentalTurbo: experimentalTurbo,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args['--turbo']) {
|
if (args['--turbo']) {
|
||||||
process.env.TURBOPACK = '1'
|
process.env.TURBOPACK = '1'
|
||||||
}
|
}
|
||||||
|
if (args['--experimental-turbo']) {
|
||||||
|
process.env.EXPERIMENTAL_TURBOPACK = '1'
|
||||||
|
}
|
||||||
|
const experimentalTurbo = !!process.env.EXPERIMENTAL_TURBOPACK
|
||||||
|
|
||||||
if (process.env.TURBOPACK) {
|
if (experimentalTurbo) {
|
||||||
|
const { loadBindings } =
|
||||||
|
require('../build/swc') as typeof import('../build/swc')
|
||||||
|
|
||||||
|
resetEnv()
|
||||||
|
let bindings = await loadBindings()
|
||||||
|
|
||||||
|
const config = await loadConfig(
|
||||||
|
PHASE_DEVELOPMENT_SERVER,
|
||||||
|
dir,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
|
// Just testing code here:
|
||||||
|
|
||||||
|
const project = await bindings.turbo.createProject({
|
||||||
|
projectPath: dir,
|
||||||
|
rootPath: dir,
|
||||||
|
nextConfig: config,
|
||||||
|
watch: true,
|
||||||
|
})
|
||||||
|
const iter = project.entrypointsSubscribe()
|
||||||
|
|
||||||
|
try {
|
||||||
|
for await (const entrypoints of iter) {
|
||||||
|
for (const [pathname, route] of entrypoints.routes) {
|
||||||
|
switch (route.type) {
|
||||||
|
case 'page': {
|
||||||
|
Log.info(`writing ${pathname} to disk`)
|
||||||
|
const written = await route.htmlEndpoint.writeToDisk()
|
||||||
|
Log.info(written)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
Log.info(`skipping ${pathname} (${route.type})`)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.error('Not supported yet')
|
||||||
|
process.exit(1)
|
||||||
|
} else if (process.env.TURBOPACK) {
|
||||||
isTurboSession = true
|
isTurboSession = true
|
||||||
|
|
||||||
const { validateTurboNextConfig } =
|
const { validateTurboNextConfig } =
|
||||||
|
@ -297,7 +346,8 @@ const nextDev: CliCommand = async (argv) => {
|
||||||
// Turbopack need to be in control over reading the .env files and watching them.
|
// Turbopack need to be in control over reading the .env files and watching them.
|
||||||
// So we need to start with a initial env to know which env vars are coming from the user.
|
// So we need to start with a initial env to know which env vars are coming from the user.
|
||||||
resetEnv()
|
resetEnv()
|
||||||
let bindings: any = await loadBindings()
|
let bindings = await loadBindings()
|
||||||
|
|
||||||
let server = bindings.turbo.startDev({
|
let server = bindings.turbo.startDev({
|
||||||
...devServerOptions,
|
...devServerOptions,
|
||||||
showAll: args['--show-all'] ?? false,
|
showAll: args['--show-all'] ?? false,
|
||||||
|
@ -318,11 +368,6 @@ const nextDev: CliCommand = async (argv) => {
|
||||||
|
|
||||||
return server
|
return server
|
||||||
} else {
|
} else {
|
||||||
if (experimentalTurbo) {
|
|
||||||
Log.error('Not supported yet')
|
|
||||||
process.exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
let cleanupFns: (() => Promise<void> | void)[] = []
|
let cleanupFns: (() => Promise<void> | void)[] = []
|
||||||
const runDevServer = async () => {
|
const runDevServer = async () => {
|
||||||
const oldCleanupFns = cleanupFns
|
const oldCleanupFns = cleanupFns
|
||||||
|
|
|
@ -85,7 +85,7 @@ type JSONValue =
|
||||||
| JSONValue[]
|
| JSONValue[]
|
||||||
| { [k: string]: JSONValue }
|
| { [k: string]: JSONValue }
|
||||||
|
|
||||||
type TurboLoaderItem =
|
export type TurboLoaderItem =
|
||||||
| string
|
| string
|
||||||
| {
|
| {
|
||||||
loader: string
|
loader: string
|
||||||
|
@ -93,7 +93,7 @@ type TurboLoaderItem =
|
||||||
options: Record<string, JSONValue>
|
options: Record<string, JSONValue>
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ExperimentalTurboOptions {
|
export interface ExperimentalTurboOptions {
|
||||||
/**
|
/**
|
||||||
* (`next --turbo` only) A mapping of aliased imports to modules to load in their place.
|
* (`next --turbo` only) A mapping of aliased imports to modules to load in their place.
|
||||||
*
|
*
|
||||||
|
|
|
@ -22,7 +22,6 @@ export interface StartServerOptions {
|
||||||
useWorkers: boolean
|
useWorkers: boolean
|
||||||
allowRetry?: boolean
|
allowRetry?: boolean
|
||||||
isTurbopack?: boolean
|
isTurbopack?: boolean
|
||||||
isExperimentalTurbo?: boolean
|
|
||||||
keepAliveTimeout?: number
|
keepAliveTimeout?: number
|
||||||
onStdout?: (data: any) => void
|
onStdout?: (data: any) => void
|
||||||
onStderr?: (data: any) => void
|
onStderr?: (data: any) => void
|
||||||
|
|
|
@ -992,8 +992,8 @@ importers:
|
||||||
'@types/react': 18.2.7
|
'@types/react': 18.2.7
|
||||||
'@types/react-dom': 18.2.4
|
'@types/react-dom': 18.2.4
|
||||||
'@vercel/ncc': ^0.36.0
|
'@vercel/ncc': ^0.36.0
|
||||||
'@vercel/turbopack-ecmascript-runtime': https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230713.2
|
'@vercel/turbopack-ecmascript-runtime': https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230713.3
|
||||||
'@vercel/turbopack-node': https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-node/js?turbopack-230713.2
|
'@vercel/turbopack-node': https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-node/js?turbopack-230713.3
|
||||||
anser: ^2.1.1
|
anser: ^2.1.1
|
||||||
css.escape: ^1.5.1
|
css.escape: ^1.5.1
|
||||||
find-up: ^6.3.0
|
find-up: ^6.3.0
|
||||||
|
@ -1005,8 +1005,8 @@ importers:
|
||||||
stacktrace-parser: ^0.1.10
|
stacktrace-parser: ^0.1.10
|
||||||
strip-ansi: ^7.0.1
|
strip-ansi: ^7.0.1
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vercel/turbopack-ecmascript-runtime': '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230713.2_react-refresh@0.12.0'
|
'@vercel/turbopack-ecmascript-runtime': '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230713.3_react-refresh@0.12.0'
|
||||||
'@vercel/turbopack-node': '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-node/js?turbopack-230713.2'
|
'@vercel/turbopack-node': '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-node/js?turbopack-230713.3'
|
||||||
anser: 2.1.1
|
anser: 2.1.1
|
||||||
css.escape: 1.5.1
|
css.escape: 1.5.1
|
||||||
next: link:../../../../next
|
next: link:../../../../next
|
||||||
|
@ -25511,9 +25511,9 @@ packages:
|
||||||
/zwitch/2.0.4:
|
/zwitch/2.0.4:
|
||||||
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
|
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
|
||||||
|
|
||||||
'@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230713.2_react-refresh@0.12.0':
|
'@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230713.3_react-refresh@0.12.0':
|
||||||
resolution: {tarball: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230713.2}
|
resolution: {tarball: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230713.3}
|
||||||
id: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230713.2'
|
id: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230713.3'
|
||||||
name: '@vercel/turbopack-ecmascript-runtime'
|
name: '@vercel/turbopack-ecmascript-runtime'
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -25524,8 +25524,8 @@ packages:
|
||||||
- webpack
|
- webpack
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
'@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-node/js?turbopack-230713.2':
|
'@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-node/js?turbopack-230713.3':
|
||||||
resolution: {tarball: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-node/js?turbopack-230713.2}
|
resolution: {tarball: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-node/js?turbopack-230713.3}
|
||||||
name: '@vercel/turbopack-node'
|
name: '@vercel/turbopack-node'
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
Loading…
Reference in a new issue