Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3e5e6db

Browse files
authored
Turbopack: Implement deploymentId (#76904)
Builds on #76814 Closes PACK-4071 (implementing config.deploymentId) This uses the new `__turbopack_load_by_url__` to load chunks through client references in react-dom-turbopack. After this lands I'm going to send a PR to react-dom-turbopack to switch the original source to use `__turbopack_load_by_url__` too, landing this PR first to make sure it passes all the Next.js tests. <!-- Thanks for opening a PR! Your contribution is much appreciated. To make sure your PR is handled as smoothly as possible we request that you follow the checklist sections below. Choose the right checklist for the change(s) that you're making: ## For Contributors ### Improving Documentation - Run `pnpm prettier-fix` to fix formatting issues before opening the PR. - Read the Docs Contribution Guide to ensure your contribution follows the docs guidelines: https://nextjs.org/docs/community/contribution-guide ### Adding or Updating Examples - The "examples guidelines" are followed from our contributing doc https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md - Make sure the linting passes by running `pnpm build && pnpm lint`. See https://github.com/vercel/next.js/blob/canary/contributing/repository/linting.md ### Fixing a bug - Related issues linked using `fixes #number` - Tests added. See: https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs - Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md ### Adding a feature - Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. (A discussion must be opened, see https://github.com/vercel/next.js/discussions/new?category=ideas) - Related issues/discussions are linked using `fixes #number` - e2e tests added (https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs) - Documentation added - Telemetry added. In case of a feature if it's used or not. - Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md ## For Maintainers - Minimal description (aim for explaining to someone not on the team to understand the PR) - When linking to a Slack thread, you might want to share details of the conclusion - Link both the Linear (Fixes NEXT-xxx) and the GitHub issues - Add review comments if necessary to explain to the reviewer the logic behind a change ### What? ### Why? ### How? Closes NEXT- Fixes # -->
1 parent 823484a commit 3e5e6db

File tree

13 files changed

+141
-13
lines changed

13 files changed

+141
-13
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/next-core/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ tracing = { workspace = true }
3434
rustc-hash = { workspace = true }
3535
react_remove_properties = "0.33.0"
3636
remove_console = "0.34.0"
37-
37+
itertools = { workspace = true }
3838
auto-hash-map = { workspace = true }
39+
percent-encoding = "2.3.1"
3940

4041
swc_core = { workspace = true, features = [
4142
"base",

crates/next-core/src/next_manifests/client_reference_manifest.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use anyhow::Result;
22
use either::Either;
33
use indoc::formatdoc;
4+
use itertools::Itertools;
45
use rustc_hash::FxHashMap;
56
use serde::{Deserialize, Serialize};
67
use tracing::Instrument;
@@ -25,6 +26,7 @@ use crate::{
2526
next_app::ClientReferencesChunks,
2627
next_client_reference::{ClientReferenceGraphResult, ClientReferenceType},
2728
next_config::NextConfig,
29+
next_manifests::encode_uri_component::encode_uri_component,
2830
util::NextRuntime,
2931
};
3032

@@ -83,7 +85,8 @@ impl ClientReferenceManifest {
8385
.map(|p| p.to_string())
8486
.unwrap_or("".into());
8587

86-
entry_manifest.module_loading.prefix = prefix_path;
88+
// TODO: Add `suffix` to the manifest for React to use.
89+
// entry_manifest.module_loading.prefix = prefix_path;
8790

8891
entry_manifest.module_loading.cross_origin = next_config
8992
.await?
@@ -200,9 +203,16 @@ impl ClientReferenceManifest {
200203
.map(ToString::to_string)
201204
})
202205
// It's possible that a chunk also emits CSS files, that will
203-
// be handled separatedly.
206+
// be handled separately.
204207
.filter(|path| path.ends_with(".js"))
205-
.map(|path| format!("{}{}", path, suffix_path))
208+
.map(|path| {
209+
format!(
210+
"{}{}{}",
211+
prefix_path,
212+
path.split('/').map(encode_uri_component).format("/"),
213+
suffix_path
214+
)
215+
})
206216
.map(RcStr::from)
207217
.collect::<Vec<_>>();
208218

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};
2+
3+
/// An `AsciiSet` that matches the behavior of JavaScript's `encodeURIComponent`.
4+
/// - It leaves `A-Z a-z 0-9 - _ . ~` unescaped.
5+
/// - It percent-encodes all other ASCII characters (and of course non-ASCII).
6+
/// - The `CONTROLS` set covers `\0`-`\x1F` and `\x7F`.
7+
const ENCODE_URI_COMPONENT_SET: &AsciiSet = &CONTROLS
8+
// Add everything else JS `encodeURIComponent` would encode:
9+
.add(b' ')
10+
// .add(b'!')
11+
.add(b'"')
12+
.add(b'#')
13+
.add(b'$')
14+
.add(b'%')
15+
.add(b'&')
16+
.add(b'\'')
17+
// .add(b'(')
18+
// .add(b')')
19+
.add(b'*')
20+
.add(b'+')
21+
.add(b',')
22+
.add(b'/')
23+
.add(b':')
24+
.add(b';')
25+
.add(b'<')
26+
.add(b'=')
27+
.add(b'>')
28+
.add(b'?')
29+
.add(b'@')
30+
.add(b'[')
31+
.add(b'\\')
32+
.add(b']')
33+
.add(b'^')
34+
.add(b'`')
35+
.add(b'{')
36+
.add(b'|')
37+
// .add(b'~');
38+
.add(b'}');
39+
40+
pub fn encode_uri_component(input: &str) -> String {
41+
utf8_percent_encode(input, ENCODE_URI_COMPONENT_SET).to_string()
42+
}
43+
44+
#[cfg(test)]
45+
mod tests {
46+
use super::*;
47+
48+
#[test]
49+
fn test_encode_uri_component() {
50+
// Each (input, expected_output)
51+
let test_cases = vec![
52+
("Hello", "Hello"),
53+
("Hello World", "Hello%20World"),
54+
(
55+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~",
56+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~",
57+
),
58+
("This is 100% test!", "This%20is%20100%25%20test!"),
59+
("你好", "%E4%BD%A0%E5%A5%BD"),
60+
(
61+
"こんにちは世界",
62+
"%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E4%B8%96%E7%95%8C",
63+
),
64+
("foo [email protected]", "foo%20bar%40baz.com"),
65+
("#$&+,/:;=?@", "%23%24%26%2B%2C%2F%3A%3B%3D%3F%40"),
66+
("éléphant", "%C3%A9l%C3%A9phant"),
67+
("𐍈", "%F0%90%8D%88"),
68+
("A B C", "A%20%20%20B%20%20%20%20C"),
69+
("foo\nbar", "foo%0Abar"),
70+
("foo\rbar", "foo%0Dbar"),
71+
("foo\r\nbar", "foo%0D%0Abar"),
72+
("Hello\u{200B}World", "Hello%E2%80%8BWorld"),
73+
("a\u{0301}", "a%CC%81"),
74+
("🏳️‍🌈", "%F0%9F%8F%B3%EF%B8%8F%E2%80%8D%F0%9F%8C%88"),
75+
(
76+
"👩‍❤️‍💋‍👩",
77+
"%F0%9F%91%A9%E2%80%8D%E2%9D%A4%EF%B8%8F%E2%80%8D%F0%9F%92%8B%E2%80%8D%F0%9F%91%A9",
78+
),
79+
(
80+
"Cafe\u{0301} / résumé & co.",
81+
"Cafe%CC%81%20%2F%20r%C3%A9sum%C3%A9%20%26%20co.",
82+
),
83+
(
84+
"السلام عليكم!?",
85+
"%D8%A7%D9%84%D8%B3%D9%84%D8%A7%D9%85%20%D8%B9%D9%84%D9%8A%D9%83%D9%85!%3F",
86+
),
87+
(
88+
"你好 world! ~测试~ (mixed)",
89+
"%E4%BD%A0%E5%A5%BD%20world!%20~%E6%B5%8B%E8%AF%95~%20(mixed)",
90+
),
91+
(
92+
"a\u{0301} 🇺🇳 e\u{0301} 🍏",
93+
"a%CC%81%20%F0%9F%87%BA%F0%9F%87%B3%20e%CC%81%20%F0%9F%8D%8F",
94+
),
95+
("𐍈𐍇", "%F0%90%8D%88%F0%90%8D%87"),
96+
(
97+
"<<<>>>%%%$$$###@@@",
98+
"%3C%3C%3C%3E%3E%3E%25%25%25%24%24%24%23%23%23%40%40%40",
99+
),
100+
("[some]{text}(here)<>", "%5Bsome%5D%7Btext%7D(here)%3C%3E"),
101+
(
102+
"Test\r\ntest 🐱\n\rSecond line \u{200B} end",
103+
"Test%0D%0Atest%20%F0%9F%90%B1%0A%0DSecond%20line%20%E2%80%8B%20end",
104+
),
105+
];
106+
107+
for (input, expected) in test_cases {
108+
let actual = encode_uri_component(input);
109+
assert_eq!(
110+
actual, expected,
111+
"Failed on input='{input}': expected='{expected}', got='{actual}'",
112+
);
113+
}
114+
}
115+
}

crates/next-core/src/next_manifests/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Type definitions for the Next.js manifest formats.
22
33
pub mod client_reference_manifest;
4+
mod encode_uri_component;
45

56
use anyhow::{Context, Result};
67
use serde::{Deserialize, Serialize};

packages/next/src/compiled/react-server-dom-turbopack-experimental/cjs/react-server-dom-turbopack-client.browser.development.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
var chunkFilename = chunks[i],
8888
entry = chunkCache.get(chunkFilename);
8989
if (void 0 === entry) {
90-
entry = __turbopack_load__(chunkFilename);
90+
entry = __turbopack_load_by_url__(chunkFilename);
9191
promises.push(entry);
9292
var resolve = chunkCache.set.bind(chunkCache, chunkFilename, null);
9393
entry.then(resolve, ignoreReject);

packages/next/src/compiled/react-server-dom-turbopack-experimental/cjs/react-server-dom-turbopack-client.browser.production.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ function preloadModule(metadata) {
7373
var chunkFilename = chunks[i],
7474
entry = chunkCache.get(chunkFilename);
7575
if (void 0 === entry) {
76-
entry = __turbopack_load__(chunkFilename);
76+
entry = __turbopack_load_by_url__(chunkFilename);
7777
promises.push(entry);
7878
var resolve = chunkCache.set.bind(chunkCache, chunkFilename, null);
7979
entry.then(resolve, ignoreReject);

packages/next/src/compiled/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.browser.development.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
var chunkFilename = chunks[i],
8888
entry = chunkCache.get(chunkFilename);
8989
if (void 0 === entry) {
90-
entry = __turbopack_load__(chunkFilename);
90+
entry = __turbopack_load_by_url__(chunkFilename);
9191
promises.push(entry);
9292
var resolve = chunkCache.set.bind(chunkCache, chunkFilename, null);
9393
entry.then(resolve, ignoreReject);

packages/next/src/compiled/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.browser.production.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ function preloadModule(metadata) {
7373
var chunkFilename = chunks[i],
7474
entry = chunkCache.get(chunkFilename);
7575
if (void 0 === entry) {
76-
entry = __turbopack_load__(chunkFilename);
76+
entry = __turbopack_load_by_url__(chunkFilename);
7777
promises.push(entry);
7878
var resolve = chunkCache.set.bind(chunkCache, chunkFilename, null);
7979
entry.then(resolve, ignoreReject);

packages/next/taskfile.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1792,7 +1792,7 @@ export async function copy_vendor_react(task_) {
17921792
const source = file.data.toString()
17931793
let newSource = source.replace(
17941794
/__turbopack_load__/g,
1795-
'__turbopack_load__'
1795+
'__turbopack_load_by_url__'
17961796
)
17971797

17981798
file.data = newSource

0 commit comments

Comments
 (0)