Skip to content

Commit f61c7ab

Browse files
fix(plugin_http): implement respond_with_url_module (#9800)
fix(plugin_http): implement respond_with_url_module --------- Co-authored-by: ahabhgk <[email protected]>
1 parent a273443 commit f61c7ab

File tree

10 files changed

+131
-111
lines changed

10 files changed

+131
-111
lines changed

crates/rspack_plugin_schemes/src/http_uri/http_cache.rs

+20-76
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,6 @@ impl HttpCache {
137137
if status == 304 {
138138
if let Some(cached) = cached_result {
139139
let new_valid_until = valid_until.max(cached.meta.valid_until);
140-
println!("GET {} [{}] (unchanged)", url, status);
141140
return Ok(FetchResultType::Content(ContentFetchResult {
142141
meta: FetchResultMeta {
143142
fresh: true,
@@ -154,7 +153,6 @@ impl HttpCache {
154153
// Improved handling of redirects to match webpack
155154
if let Some(location) = location {
156155
if (301..=308).contains(&status) {
157-
println!("GET {} [{}] -> {}", url, status, location);
158156
// Resolve relative redirects like webpack does
159157
let absolute_location = match Url::parse(&location) {
160158
Ok(loc) => loc.to_string(), // Already absolute
@@ -181,7 +179,6 @@ impl HttpCache {
181179
&& cached_redirect.meta.store_cache == store_cache
182180
&& cached_redirect.meta.etag == etag
183181
{
184-
println!("GET {} [{}] (unchanged redirect)", url, status);
185182
return Ok(FetchResultType::Redirect(RedirectFetchResult {
186183
meta: FetchResultMeta {
187184
fresh: true,
@@ -215,14 +212,6 @@ impl HttpCache {
215212
}
216213

217214
let content = response.body;
218-
println!(
219-
"GET {} [{}] {} kB{}",
220-
url,
221-
status,
222-
content.len() / 1024,
223-
if !store_lock { " no-cache" } else { "" }
224-
);
225-
226215
let integrity = compute_integrity(&content);
227216
let content_type = headers
228217
.get("content-type")
@@ -249,14 +238,6 @@ impl HttpCache {
249238
},
250239
};
251240

252-
if !store_cache {
253-
println!(
254-
"{} can't be stored in cache, due to Cache-Control header: {}",
255-
url,
256-
cache_control.unwrap_or_else(|| "null".to_string())
257-
);
258-
}
259-
260241
if store_cache || store_lock {
261242
let should_update = cached_result
262243
.map(|cached| {
@@ -274,23 +255,7 @@ impl HttpCache {
274255
let lockfile = self.lockfile_cache.get_lockfile().await?;
275256
let mut lock_guard = lockfile.lock().await;
276257

277-
// Log entry updates similar to webpack
278-
let old_entry = lock_guard.get_entry(url);
279-
if let Some(old_entry) = old_entry {
280-
if old_entry.integrity != entry.integrity {
281-
println!("{} updated in lockfile: content changed", url);
282-
} else if old_entry.content_type != entry.content_type {
283-
println!(
284-
"{} updated in lockfile: {} -> {}",
285-
url, old_entry.content_type, entry.content_type
286-
);
287-
} else {
288-
println!("{} updated in lockfile", url);
289-
}
290-
} else {
291-
println!("{} added to lockfile", url);
292-
}
293-
258+
// Update the lockfile entry
294259
lock_guard.entries_mut().insert(url.to_string(), entry);
295260
drop(lock_guard);
296261
self.lockfile_cache.save_lockfile().await?;
@@ -306,35 +271,26 @@ impl HttpCache {
306271
let lock_guard = lockfile.lock().await;
307272

308273
if let Some(entry) = lock_guard.get_entry(resource) {
309-
// Generate cache key using webpack-compatible format
310274
let cache_key = self.get_cache_key(&entry.resolved);
311-
312-
// Full path to the cache file
313-
let cache_path_buf = PathBuf::from(cache_location).join(&cache_key);
275+
let cache_path_buf = cache_location.join(&cache_key);
314276
let cache_path = Utf8Path::from_path(&cache_path_buf).expect("Invalid cache path");
315277

316-
// Try to read the file
317-
match self.filesystem.read_file(cache_path).await {
318-
Ok(content) => {
319-
let meta = FetchResultMeta {
320-
store_cache: true,
321-
store_lock: true,
322-
valid_until: entry.valid_until,
323-
etag: entry.etag.clone(),
324-
fresh: entry.valid_until >= current_time(),
325-
};
326-
327-
let result = ContentFetchResult {
328-
entry: entry.clone(),
329-
content,
330-
meta,
331-
};
332-
333-
return Ok(Some(result));
334-
}
335-
Err(e) => {
336-
println!("Failed to read cache file: {:?}", e);
337-
}
278+
if let Ok(content) = self.filesystem.read_file(cache_path).await {
279+
let meta = FetchResultMeta {
280+
store_cache: true,
281+
store_lock: true,
282+
valid_until: entry.valid_until,
283+
etag: entry.etag.clone(),
284+
fresh: entry.valid_until >= current_time(),
285+
};
286+
287+
let result = ContentFetchResult {
288+
entry: entry.clone(),
289+
content,
290+
meta,
291+
};
292+
293+
return Ok(Some(result));
338294
}
339295
}
340296
}
@@ -343,8 +299,6 @@ impl HttpCache {
343299

344300
async fn write_to_cache(&self, resource: &str, content: &[u8]) -> Result<()> {
345301
if let Some(cache_location) = &self.cache_location {
346-
println!("Writing to cache at location: {:?}", cache_location);
347-
348302
// Generate cache key using webpack-compatible format
349303
let cache_key = self.get_cache_key(resource);
350304

@@ -355,22 +309,12 @@ impl HttpCache {
355309
// Create parent directories
356310
if let Some(parent) = cache_path.parent() {
357311
let parent_path = parent.to_string();
358-
println!("Creating directory: {:?}", parent_path);
359312
let parent_utf8_path = Utf8Path::new(&parent_path);
360-
match self.filesystem.create_dir_all(parent_utf8_path).await {
361-
Ok(_) => println!("Created cache directory successfully"),
362-
Err(e) => println!("Failed to create cache directory: {:?}", e),
363-
};
313+
self.filesystem.create_dir_all(parent_utf8_path).await.ok();
364314
}
365315

366316
// Write the cache file
367-
println!("Writing cache file to: {:?}", cache_path);
368-
match self.filesystem.write(cache_path, content).await {
369-
Ok(_) => println!("Wrote cache file successfully"),
370-
Err(e) => println!("Failed to write cache file: {:?}", e),
371-
};
372-
} else {
373-
println!("No cache location specified");
317+
self.filesystem.write(cache_path, content).await.ok();
374318
}
375319
Ok(())
376320
}

crates/rspack_plugin_schemes/src/http_uri/lockfile.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,8 @@ impl LockfileCache {
187187
Err(e) if e.kind() == io::ErrorKind::NotFound => {
188188
// File doesn't exist, use the default empty lockfile
189189
}
190-
Err(e) => {
191-
eprintln!("Error reading lockfile: {:?}", e);
190+
Err(_e) => {
191+
// Error reading lockfile
192192
}
193193
}
194194
}

crates/rspack_plugin_schemes/src/http_uri/mod.rs

+64-26
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@ pub use http_cache::{HttpClient, HttpResponse};
99
use once_cell::sync::Lazy;
1010
use regex::Regex;
1111
use rspack_core::{
12-
get_scheme, ApplyContext, CompilerOptions, Content, ModuleFactoryCreateData,
12+
ApplyContext, CompilerOptions, Content, ModuleFactoryCreateData,
1313
NormalModuleFactoryResolveForScheme, NormalModuleFactoryResolveInScheme,
1414
NormalModuleReadResource, Plugin, PluginContext, ResourceData, Scheme,
1515
};
1616
use rspack_error::Result;
1717
use rspack_fs::WritableFileSystem;
1818
use rspack_hook::{plugin, plugin_hook};
1919
use rspack_util::asset_condition::{AssetCondition, AssetConditions};
20+
use url::Url;
2021

2122
static EXTERNAL_HTTP_REQUEST: Lazy<Regex> =
2223
Lazy::new(|| Regex::new(r"^(//|https?://|#)").expect("Invalid regex"));
@@ -31,6 +32,25 @@ impl HttpUriPlugin {
3132
pub fn new(options: HttpUriPluginOptions) -> Self {
3233
Self::new_inner(options)
3334
}
35+
pub async fn respond_with_url_module(
36+
&self,
37+
resource_data: &mut ResourceData,
38+
url: &Url,
39+
mimetype: Option<String>,
40+
) -> Result<bool> {
41+
resource_data.set_resource(url.to_string());
42+
resource_data.set_path(url.origin().ascii_serialization() + url.path());
43+
if let Some(query) = url.query() {
44+
resource_data.set_query(query.to_string());
45+
}
46+
if let Some(fragment) = url.fragment() {
47+
resource_data.set_fragment(fragment.to_string());
48+
}
49+
if let Some(mime) = mimetype {
50+
resource_data.set_mimetype(mime);
51+
}
52+
Ok(true)
53+
}
3454
}
3555

3656
#[derive(Debug)]
@@ -49,14 +69,21 @@ pub struct HttpUriPluginOptions {
4969
async fn resolve_for_scheme(
5070
&self,
5171
_data: &mut ModuleFactoryCreateData,
52-
_resource_data: &mut ResourceData,
53-
scheme: &Scheme,
72+
resource_data: &mut ResourceData,
73+
_scheme: &Scheme,
5474
) -> Result<Option<bool>> {
55-
Ok(if scheme.is_http() || scheme.is_https() {
56-
Some(true)
57-
} else {
58-
None
59-
})
75+
// Try to parse the URL and handle it
76+
match Url::parse(&resource_data.resource) {
77+
Ok(url) => match self
78+
.respond_with_url_module(resource_data, &url, None)
79+
.await
80+
{
81+
Ok(true) => Ok(Some(true)),
82+
Ok(false) => Ok(None),
83+
Err(e) => Err(e),
84+
},
85+
Err(_) => Ok(None),
86+
}
6087
}
6188

6289
#[plugin_hook(NormalModuleFactoryResolveInScheme for HttpUriPlugin)]
@@ -66,31 +93,42 @@ async fn resolve_in_scheme(
6693
resource_data: &mut ResourceData,
6794
_scheme: &Scheme,
6895
) -> Result<Option<bool>> {
69-
if !matches!(
70-
get_scheme(data.context.as_str()),
71-
Scheme::Http | Scheme::Https
72-
) {
96+
// Check if the dependency type is "url", similar to webpack's check
97+
let is_not_url_dependency = data
98+
.dependencies
99+
.first()
100+
.and_then(|dep| dep.as_module_dependency())
101+
.map(|dep| dep.dependency_type().as_str() != "url")
102+
.unwrap_or(true);
103+
104+
// Only handle relative urls (./xxx, ../xxx, /xxx, //xxx) and non-url dependencies
105+
if is_not_url_dependency
106+
&& (!resource_data.resource.starts_with("./")
107+
&& !resource_data.resource.starts_with("../")
108+
&& !resource_data.resource.starts_with("/")
109+
&& !resource_data.resource.starts_with("//"))
110+
{
73111
return Ok(None);
74112
}
75113

76-
let base_url = match url::Url::parse(data.context.as_str()) {
114+
// Parse the base URL from context
115+
let base_url = match Url::parse(&format!("{}/", data.context)) {
77116
Ok(url) => url,
78117
Err(_) => return Ok(None),
79118
};
80119

81-
let resource_url = match url::Url::parse(&resource_data.resource) {
82-
Ok(url) if url.scheme() == "http" || url.scheme() == "https" => return Ok(None),
83-
Ok(_) | Err(_) => resource_data.resource.clone(),
84-
};
85-
86-
let resource_set = base_url
87-
.join(&resource_url)
88-
.map(|url| url.to_string())
89-
.unwrap_or_else(|_| resource_data.resource.clone());
90-
91-
resource_data.set_resource(resource_set);
92-
93-
Ok(Some(true))
120+
// Join the base URL with the resource
121+
match base_url.join(&resource_data.resource) {
122+
Ok(url) => match self
123+
.respond_with_url_module(resource_data, &url, None)
124+
.await
125+
{
126+
Ok(true) => Ok(Some(true)),
127+
Ok(false) => Ok(None),
128+
Err(e) => Err(e),
129+
},
130+
Err(_) => Ok(None),
131+
}
94132
}
95133

96134
#[plugin_hook(NormalModuleReadResource for HttpUriPlugin)]

examples/basic/rspack.config.cjs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module.exports = {
22
context: __dirname,
33
entry: {
4-
main: './index.js'
4+
main: "./index.js"
55
}
6-
}
6+
};
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
const urlSvg = new URL(
1+
import url1 from "https://raw.githubusercontent.com/web-infra-dev/rspack/55d5d81/packages/rspack-test-tools/tests/configCases/asset/_images/file.png";
2+
3+
const url2 = new URL(
24
"https://raw.githubusercontent.com/web-infra-dev/rspack/55d5d81/packages/rspack-test-tools/tests/configCases/asset/_images/file.jpg",
35
import.meta.url
46
);
57

68
it("should work", () => {
7-
expect(/[\da-f]{16}\.jpg$/.test(urlSvg)).toBe(true);
9+
expect(/[\da-f]{16}\.png$/.test(url1)).toBe(true);
10+
expect(/[\da-f]{16}\.jpg$/.test(url2)).toBe(true);
811
});

packages/rspack-test-tools/tests/configCases/build-http/asset/lock-files/lock.json

+7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@
77
"content_type": "image/jpeg",
88
"valid_until": 1742905466911,
99
"etag": "W/\"40111d35223d236145879eff0356549b1c5e1e09d728cc3006096a31617decdb\""
10+
},
11+
"https://raw.githubusercontent.com/web-infra-dev/rspack/55d5d81/packages/rspack-test-tools/tests/configCases/asset/_images/file.png": {
12+
"resolved": "https://raw.githubusercontent.com/web-infra-dev/rspack/55d5d81/packages/rspack-test-tools/tests/configCases/asset/_images/file.png",
13+
"integrity": "sha512-atUj9bZUhzadMFYTNmufaNze7iJSkXZuOyX69FQ5ygafYUAwwIylTHFP2/epRPrEibFRWov54NMZHhvLv+ap3w==",
14+
"content_type": "image/png",
15+
"valid_until": 1743141759795,
16+
"etag": "W/\"70f400bdbff19f7b1859bc4856f593134cfad96dd1f157b19647bdce9bef5433\""
1017
}
1118
}
1219
}

packages/rspack-test-tools/tests/configCases/build-http/asset/webpack.config.js

+8
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@ const path = require("path");
33
/** @type {import("@rspack/core").Configuration} */
44
module.exports = {
55
mode: "development",
6+
module: {
7+
rules: [
8+
{
9+
test: /\.png$/,
10+
type: "asset/resource"
11+
}
12+
]
13+
},
614
experiments: {
715
buildHttp: {
816
allowedUris: ["https://"],

packages/rspack-test-tools/tests/configCases/build-http/css/__snapshot__/bundle0.css.txt

+22-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
Array [
2-
"/* #region \"./style.css\" */
2+
"/* #region \"https://raw.githubusercontent.com/web-infra-dev/rspack/55d5d81/packages/rspack-test-tools/tests/configCases/css/at-import/c.css\" */
3+
/*
4+
- type: css/auto
5+
*/
6+
.c {
7+
color: pink;
8+
}
9+
10+
/* #endregion \"https://raw.githubusercontent.com/web-infra-dev/rspack/55d5d81/packages/rspack-test-tools/tests/configCases/css/at-import/c.css\" */
11+
12+
/* #region \"./style.css\" */
313
/*
414
- type: css/auto
515
*/
@@ -12,7 +22,17 @@ div {
1222
/* #endregion \"./style.css\" */
1323

1424
",
15-
"/* #region \"./style.css\" */
25+
"/* #region \"https://raw.githubusercontent.com/web-infra-dev/rspack/55d5d81/packages/rspack-test-tools/tests/configCases/css/at-import/c.css\" */
26+
/*
27+
- type: css/auto
28+
*/
29+
.c {
30+
color: pink;
31+
}
32+
33+
/* #endregion \"https://raw.githubusercontent.com/web-infra-dev/rspack/55d5d81/packages/rspack-test-tools/tests/configCases/css/at-import/c.css\" */
34+
35+
/* #region \"./style.css\" */
1636
/*
1737
- type: css/auto
1838
*/

0 commit comments

Comments
 (0)