Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: update resource in nmf resolve hook #7200

Merged
merged 2 commits into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

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

42 changes: 18 additions & 24 deletions crates/node_binding/src/plugins/interceptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 22,9 @@ use rspack_binding_values::{
ToJsCompatSource, ToJsModule,
};
use rspack_core::{
rspack_sources::SourceExt, AfterResolveData, AfterResolveResult, AssetEmittedInfo,
BeforeResolveData, BeforeResolveResult, BoxModule, Chunk, ChunkUkey, CodeGenerationResults,
Compilation, CompilationAdditionalTreeRuntimeRequirements,
parse_resource, rspack_sources::SourceExt, AfterResolveData, AfterResolveResult,
AssetEmittedInfo, BeforeResolveData, BeforeResolveResult, BoxModule, Chunk, ChunkUkey,
CodeGenerationResults, Compilation, CompilationAdditionalTreeRuntimeRequirements,
CompilationAdditionalTreeRuntimeRequirementsHook, CompilationAfterOptimizeModules,
CompilationAfterOptimizeModulesHook, CompilationAfterProcessAssets,
CompilationAfterProcessAssetsHook, CompilationAfterSeal, CompilationAfterSealHook,
Expand Down Expand Up @@ -1362,29 1362,23 @@ impl NormalModuleFactoryAfterResolve for NormalModuleFactoryAfterResolveTap {
{
Ok((ret, resolve_data)) => {
if let Some(resolve_data) = resolve_data {
fn override_resource(origin_data: &ResourceData, new_resource: String) -> ResourceData {
let mut resource_data = origin_data.clone();
let origin_resource_path = origin_data
.resource_path
.as_ref()
.map(|p| p.to_string_lossy().to_string())
.unwrap_or_default();
resource_data.resource_path = Some(new_resource.clone().into());
resource_data.resource = resource_data
.resource
.replace(&origin_resource_path, &new_resource);

resource_data
fn update_resource_data(old_resource_data: &mut ResourceData, new_resource: String) {
if old_resource_data.resource_path.is_some()
&& let Some(parsed) = parse_resource(&new_resource)
{
old_resource_data.set_path(parsed.path);
old_resource_data.set_query_optional(parsed.query);
old_resource_data.set_fragment_optional(parsed.fragment);
}
old_resource_data.set_resource(new_resource);
}

let request = resolve_data.request;
let user_request = resolve_data.user_request;
let resource =
override_resource(&create_data.resource_resolve_data, resolve_data.resource);

create_data.request = request;
create_data.user_request = user_request;
create_data.resource_resolve_data = resource;
create_data.request = resolve_data.request;
create_data.user_request = resolve_data.user_request;
update_resource_data(
&mut create_data.resource_resolve_data,
resolve_data.resource,
);
}

Ok(ret)
Expand Down
4 changes: 1 addition & 3 deletions crates/rspack_binding_values/src/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 35,7 @@ impl JsResolver {
#[napi(ts_return_type = "string | false")]
pub fn resolve_sync(&self, path: String, request: String) -> napi::Result<Either<String, bool>> {
match self.resolver.resolve(Path::new(&path), &request) {
Ok(rspack_core::ResolveResult::Resource(resource)) => Ok(Either::A(
resource.full_path().to_string_lossy().to_string(),
)),
Ok(rspack_core::ResolveResult::Resource(resource)) => Ok(Either::A(resource.full_path())),
Ok(rspack_core::ResolveResult::Ignored) => Ok(Either::B(false)),
Err(err) => Err(napi::Error::from_reason(format!("{:?}", err))),
}
Expand Down
2 changes: 1 addition & 1 deletion crates/rspack_core/src/context_module_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 191,7 @@ impl ContextModuleFactory {
})?;
match resolve_result {
ResolveResult::Resource(resource) => {
let resource = resource.full_path().to_string_lossy().to_string();
let resource = resource.full_path();
loader_result.push(resource);
}
ResolveResult::Ignored => {
Expand Down
3 changes: 2 additions & 1 deletion crates/rspack_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 96,8 @@ pub mod concatenated_module;
pub mod reserved_names;

pub use rspack_loader_runner::{
get_scheme, AdditionalData, ResourceData, Scheme, BUILTIN_LOADER_PREFIX,
get_scheme, parse_resource, AdditionalData, ResourceData, ResourceParsedData, Scheme,
BUILTIN_LOADER_PREFIX,
};
pub use rspack_macros::{impl_runtime_module, impl_source_map_config};
pub use rspack_sources;
Expand Down
13 changes: 5 additions & 8 deletions crates/rspack_core/src/normal_module_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,14 337,11 @@ impl NormalModuleFactory {
let resource_data = resolve(resolve_args, plugin_driver).await;

match resource_data {
Ok(ResolveResult::Resource(resource)) => {
let uri = resource.full_path().display().to_string();
ResourceData::new(uri)
.path(resource.path)
.query(resource.query)
.fragment(resource.fragment)
.description_optional(resource.description_data)
}
Ok(ResolveResult::Resource(resource)) => ResourceData::new(resource.full_path())
.path(resource.path)
.query(resource.query)
.fragment(resource.fragment)
.description_optional(resource.description_data),
Ok(ResolveResult::Ignored) => {
let ident = format!("{}/{}", &data.context, resource);
let module_identifier = ModuleIdentifier::from(format!("ignored|{ident}"));
Expand Down
10 changes: 6 additions & 4 deletions crates/rspack_core/src/resolver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 8,7 @@ use once_cell::sync::Lazy;
use regex::Regex;
use rspack_error::{Error, MietteExt};
use rspack_loader_runner::DescriptionData;
use rspack_util::identifier::insert_zero_width_space_for_fragment;
use rustc_hash::FxHashSet;
use sugar_path::SugarPath;

Expand Down Expand Up @@ -76,11 77,12 @@ impl Eq for Resource {}

impl Resource {
/// Get the full path with query and fragment attached.
pub fn full_path(&self) -> PathBuf {
let mut buf = format!("{}", self.path.display());
buf.push_str(&self.query);
pub fn full_path(&self) -> String {
let mut buf =
insert_zero_width_space_for_fragment(&self.path.display().to_string()).into_owned();
buf.push_str(&insert_zero_width_space_for_fragment(&self.query));
buf.push_str(&self.fragment);
PathBuf::from(buf)
buf
}
}

Expand Down
27 changes: 1 addition & 26 deletions crates/rspack_core/src/utils/identifier.rs
Original file line number Diff line number Diff line change
@@ -1,7 1,4 @@
use std::{
borrow::Cow,
path::{Path, PathBuf},
};
use std::{borrow::Cow, path::Path};

use once_cell::sync::Lazy;
use regex::Regex;
Expand Down Expand Up @@ -35,28 32,6 @@ pub fn to_identifier(v: &str) -> Cow<str> {
}
}

static PATH_QUERY_FRAGMENT_REGEXP: Lazy<Regex> = Lazy::new(|| {
Regex::new("^((?:\u{200b}.|[^?#\u{200b}])*)(\\?(?:\u{200b}.|[^#\u{200b}])*)?(#.*)?$")
.expect("Failed to initialize `PATH_QUERY_FRAGMENT_REGEXP`")
});

#[derive(Debug)]
pub struct ResourceParsedData {
pub path: PathBuf,
pub query: Option<String>,
pub fragment: Option<String>,
}

pub fn parse_resource(resource: &str) -> Option<ResourceParsedData> {
let groups = PATH_QUERY_FRAGMENT_REGEXP.captures(resource)?;

Some(ResourceParsedData {
path: groups.get(1)?.as_str().into(),
query: groups.get(2).map(|q| q.as_str().to_owned()),
fragment: groups.get(3).map(|q| q.as_str().to_owned()),
})
}

pub fn stringify_loaders_and_resource<'a>(
loaders: &'a [ModuleRuleUseLoader],
resource: &'a str,
Expand Down
1 change: 1 addition & 0 deletions crates/rspack_loader_runner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 17,5 @@ regex = { workspace = true }
rspack_error = { path = "../rspack_error" }
rspack_identifier = { path = "../rspack_identifier" }
rspack_sources = { workspace = true }
rspack_util = { path = "../rspack_util" }
serde_json = { workspace = true }
2 changes: 1 addition & 1 deletion crates/rspack_loader_runner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 10,7 @@ mod scheme;

pub use content::{AdditionalData, Content, DescriptionData, ResourceData};
pub use context::{LoaderContext, State};
pub use loader::{DisplayWithSuffix, Loader, LoaderItem};
pub use loader::{parse_resource, DisplayWithSuffix, Loader, LoaderItem, ResourceParsedData};
pub use plugin::LoaderRunnerPlugin;
pub use rspack_identifier::{Identifiable, Identifier};
pub use runner::run_loaders;
Expand Down
19 changes: 13 additions & 6 deletions crates/rspack_loader_runner/src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 14,7 @@ use once_cell::sync::Lazy;
use regex::Regex;
use rspack_error::Result;
use rspack_identifier::{Identifiable, Identifier};
use rspack_util::identifier::strip_zero_width_space_for_fragment;

use super::LoaderContext;

Expand Down Expand Up @@ -197,18 198,24 @@ impl<C> From<Arc<dyn Loader<C>>> for LoaderItem<C> {
}
}
}
struct ResourceParsedData {

#[derive(Debug)]
pub struct ResourceParsedData {
pub path: PathBuf,
pub query: Option<String>,
pub fragment: Option<String>,
}

fn parse_resource(resource: &str) -> Option<ResourceParsedData> {
pub fn parse_resource(resource: &str) -> Option<ResourceParsedData> {
let groups = PATH_QUERY_FRAGMENT_REGEXP.captures(resource)?;

Some(ResourceParsedData {
path: groups.get(1)?.as_str().into(),
query: groups.get(2).map(|q| q.as_str().to_owned()),
path: strip_zero_width_space_for_fragment(groups.get(1)?.as_str())
.into_owned()
.into(),
query: groups
.get(2)
.map(|q| strip_zero_width_space_for_fragment(q.as_str()).into_owned()),
fragment: groups.get(3).map(|q| q.as_str().to_owned()),
})
}
Expand Down Expand Up @@ -278,7 285,7 @@ pub(crate) mod test {
let c1 = Arc::new(PosixNonLenBlankUnicode) as Arc<dyn Loader<()>>;
let l: LoaderItem<()> = c1.into();
assert_eq!(l.path, PathBuf::from("/a/b/c.js"));
assert_eq!(l.query, Some("?{\"c\": \"\u{200b}#foo\"}".into()));
assert_eq!(l.query, Some("?{\"c\": \"#foo\"}".into()));
assert_eq!(l.fragment, None);
}

Expand All @@ -287,7 294,7 @@ pub(crate) mod test {
let c1 = Arc::new(WinNonLenBlankUnicode) as Arc<dyn Loader<()>>;
let l: LoaderItem<()> = c1.into();
assert_eq!(l.path, PathBuf::from(r#"\a\b\c.js"#));
assert_eq!(l.query, Some("?{\"c\": \"\u{200b}#foo\"}".into()));
assert_eq!(l.query, Some("?{\"c\": \"#foo\"}".into()));
assert_eq!(l.fragment, None);
}
}
13 changes: 13 additions & 0 deletions crates/rspack_util/src/identifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 113,16 @@ pub fn make_paths_absolute(context: &str, identifier: &str) -> String {
.collect::<Vec<String>>()
.join("")
}

static ZERO_WIDTH_SPACE: Lazy<Regex> =
Lazy::new(|| Regex::new("\u{200b}(.)").expect("invalid regex"));

static FRAGMENT: Lazy<Regex> = Lazy::new(|| Regex::new("#").expect("invalid regex"));

pub fn strip_zero_width_space_for_fragment(s: &str) -> Cow<str> {
ZERO_WIDTH_SPACE.replace_all(s, "$1")
}

pub fn insert_zero_width_space_for_fragment(s: &str) -> Cow<str> {
FRAGMENT.replace_all(s, "\u{200b}#")
}
Original file line number Diff line number Diff line change
@@ -0,0 1,5 @@
import a from "data:text/javascript,export default 42;"

it("should build with data uri and after resolve hook", () => {
expect(a).toBe(42);
});
Original file line number Diff line number Diff line change
@@ -0,0 1,11 @@
/** @type {import('webpack').Configuration} */
module.exports = {
entry: 'data:text/javascript,import "./index.js";',
plugins: [
function (compiler) {
compiler.hooks.compilation.tap('test', (compilation, { normalModuleFactory }) => {
normalModuleFactory.hooks.afterResolve.tap('test', () => {})
})
}
]
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 8,9 @@ it("should remove duplicate request modules generate by after resolve hook", ()
expect(b).toBe("c");
expect(c).toBe("c");
const ext = ".js";
expect(fs.readFileSync(__filename, "utf-8")).not.toContain("./b" ext);
expect(fs.readFileSync(__filename, "utf-8")).toContain("./c" ext);
expect(fs.readFileSync(__filename, "utf-8")).not.toContain("duplicate/b" ext);
expect(fs.readFileSync(__filename, "utf-8")).toContain("duplicate/c" ext);
expect(
fs.readFileSync(__filename, "utf-8").split("./c" ext).length - 1
fs.readFileSync(__filename, "utf-8").split("duplicate/c" ext).length - 1
).toBe(2);
});
Original file line number Diff line number Diff line change
@@ -1,12 1,12 @@
```js title=main.js
(() => { // webpackBootstrap
var __webpack_modules__ = ({
"./a.js": (function (module) {
"../../normalModuleFactory​#afterResolve/duplicate/a.js": (function (module) {
ahabhgk marked this conversation as resolved.
Show resolved Hide resolved
module.exports = "a";


}),
"./c.js": (function (module) {
"../../normalModuleFactory​#afterResolve/duplicate/c.js": (function (module) {
module.exports = "c";


Expand Down Expand Up @@ -79,9 79,9 @@ __webpack_require__.o = function (obj, prop) {
// This entry need to be wrapped in an IIFE because it need to be in strict mode.
(() => {
"use strict";
/* harmony import */var _a__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./a.js");
/* harmony import */var _a__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("../../normalModuleFactory​#afterResolve/duplicate/a.js");
/* harmony import */var _a__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_a__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */var _b__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./c.js");
/* harmony import */var _b__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("../../normalModuleFactory​#afterResolve/duplicate/c.js");
/* harmony import */var _b__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_b__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */var fs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__("fs");
/* harmony import */var fs__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_2__);
Expand All @@ -95,10 95,10 @@ it("should remove duplicate request modules generate by after resolve hook", ()
expect((_b__WEBPACK_IMPORTED_MODULE_1___default())).toBe("c");
expect((_b__WEBPACK_IMPORTED_MODULE_1___default())).toBe("c");
const ext = ".js";
expect(fs__WEBPACK_IMPORTED_MODULE_2___default().readFileSync(__filename, "utf-8")).not.toContain("./b" ext);
expect(fs__WEBPACK_IMPORTED_MODULE_2___default().readFileSync(__filename, "utf-8")).toContain("./c" ext);
expect(fs__WEBPACK_IMPORTED_MODULE_2___default().readFileSync(__filename, "utf-8")).not.toContain("duplicate/b" ext);
expect(fs__WEBPACK_IMPORTED_MODULE_2___default().readFileSync(__filename, "utf-8")).toContain("duplicate/c" ext);
expect(
fs__WEBPACK_IMPORTED_MODULE_2___default().readFileSync(__filename, "utf-8").split("./c" ext).length - 1
fs__WEBPACK_IMPORTED_MODULE_2___default().readFileSync(__filename, "utf-8").split("duplicate/c" ext).length - 1
).toBe(2);
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 1,12 @@
```js title=main.js
(() => { // webpackBootstrap
var __webpack_modules__ = ({
"./a.js": (function (module) {
"../../normalModuleFactory​#afterResolve/request/a.js": (function (module) {
module.exports = "a";


}),
"./c.js": (function (module) {
"../../normalModuleFactory​#afterResolve/request/c.js": (function (module) {
module.exports = "b";


Expand Down Expand Up @@ -75,16 75,16 @@ __webpack_require__.o = function (obj, prop) {
(() => {
"use strict";

// EXTERNAL MODULE: ./a.js
let a_ = __webpack_require__("./a.js");
// EXTERNAL MODULE: ../../normalModuleFactory​#afterResolve/request/a.js
let a_ = __webpack_require__("../../normalModuleFactory​#afterResolve/request/a.js");
let a_default = /*#__PURE__*/__webpack_require__.n(a_);
// EXTERNAL MODULE: ./c.js
let c_ = __webpack_require__("./c.js");
// EXTERNAL MODULE: ../../normalModuleFactory​#afterResolve/request/c.js
let c_ = __webpack_require__("../../normalModuleFactory​#afterResolve/request/c.js");
let c_default = /*#__PURE__*/__webpack_require__.n(c_);
;// CONCATENATED MODULE: external "fs"
var external_fs_namespaceObject = require("fs");
let external_fs_default = /*#__PURE__*/__webpack_require__.n(external_fs_namespaceObject);
;// CONCATENATED MODULE: ./request.js
;// CONCATENATED MODULE: ../../normalModuleFactory​#afterResolve/request/request.js



Expand All @@ -93,7 93,7 @@ it("should modify request by after resolve hook", () => {
expect((a_default())).toBe("a");
expect((c_default())).toBe("b");
const ext = ".js";
expect(external_fs_default().readFileSync(__filename, "utf-8")).toContain("./c" ext);
expect(external_fs_default().readFileSync(__filename, "utf-8")).toContain("request/c" ext);
});

})();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 6,5 @@ it("should modify request by after resolve hook", () => {
expect(a).toBe("a");
expect(b).toBe("b");
const ext = ".js";
expect(fs.readFileSync(__filename, "utf-8")).toContain("./c" ext);
expect(fs.readFileSync(__filename, "utf-8")).toContain("request/c" ext);
});
Loading
Loading