Skip to content

Commit 788dad9

Browse files
authored
feat: build module with path and query (#263)
1 parent a2f469b commit 788dad9

File tree

5 files changed

+100
-43
lines changed

5 files changed

+100
-43
lines changed

crates/mako/src/build.rs

+68-2
Original file line numberDiff line numberDiff line change
@@ -203,12 +203,13 @@ impl Compiler {
203203
) -> Result<(Module, ModuleDeps, Task)> {
204204
let mut dependencies = Vec::new();
205205
let module_id = ModuleId::new(task.path.clone());
206+
let request = parse_path(&task.path)?;
206207

207208
// load
208-
let content = load(&task.path, task.is_entry, &context)?;
209+
let content = load(&request, task.is_entry, &context)?;
209210

210211
// parse
211-
let mut ast = parse(&content, &task.path, &context)?;
212+
let mut ast = parse(&content, &request, &context)?;
212213

213214
// transform & resolve
214215
// TODO: 支持同时有多个 resolve error
@@ -303,14 +304,79 @@ fn get_entries(root: &Path, config: &Config) -> Option<Vec<std::path::PathBuf>>
303304
None
304305
}
305306

307+
fn parse_path(path: &str) -> Result<FileRequest> {
308+
let mut iter = path.split('?');
309+
let path = iter.next().unwrap();
310+
let query = iter.next().unwrap_or("");
311+
let mut query_vec = vec![];
312+
for pair in query.split('&') {
313+
if pair.contains('=') {
314+
let mut it = pair.split('=').take(2);
315+
let kv = match (it.next(), it.next()) {
316+
(Some(k), Some(v)) => (k.to_string(), v.to_string()),
317+
_ => continue,
318+
};
319+
query_vec.push(kv);
320+
} else if !pair.is_empty() {
321+
query_vec.push((pair.to_string(), "".to_string()));
322+
}
323+
}
324+
Ok(FileRequest {
325+
path: path.to_string(),
326+
query: query_vec,
327+
})
328+
}
329+
330+
#[derive(Debug)]
331+
pub struct FileRequest {
332+
pub path: String,
333+
pub query: Vec<(String, String)>,
334+
}
335+
336+
impl FileRequest {
337+
pub fn has_query(&self, key: &str) -> bool {
338+
self.query.iter().any(|(k, _)| *k == key)
339+
}
340+
}
341+
306342
#[cfg(test)]
307343
mod tests {
308344
use petgraph::prelude::EdgeRef;
309345
use petgraph::visit::IntoEdgeReferences;
310346

347+
use super::parse_path;
311348
use crate::compiler;
312349
use crate::config::Config;
313350

351+
#[test]
352+
fn test_parse_path() {
353+
let result = parse_path("foo").unwrap();
354+
assert_eq!(result.path, "foo");
355+
assert_eq!(result.query, vec![]);
356+
357+
let result = parse_path("foo?bar=1&hoo=2").unwrap();
358+
assert_eq!(result.path, "foo");
359+
assert_eq!(
360+
result.query.get(0).unwrap(),
361+
&("bar".to_string(), "1".to_string())
362+
);
363+
assert_eq!(
364+
result.query.get(1).unwrap(),
365+
&("hoo".to_string(), "2".to_string())
366+
);
367+
assert!(result.has_query("bar"));
368+
assert!(result.has_query("hoo"));
369+
assert!(!result.has_query("foo"));
370+
371+
let result = parse_path("foo?bar").unwrap();
372+
assert_eq!(result.path, "foo");
373+
assert_eq!(
374+
result.query.get(0).unwrap(),
375+
&("bar".to_string(), "".to_string())
376+
);
377+
assert!(result.has_query("bar"));
378+
}
379+
314380
#[tokio::test(flavor = "multi_thread")]
315381
async fn test_build_normal() {
316382
let (module_ids, references) = build("test/build/normal");

crates/mako/src/css_modules.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use swc_css_modules::{compile, CssClassName, TransformConfig, TransformResult};
44
use tracing::warn;
55

66
const CSS_MODULES_PATH_SUFFIX: &str = ".module.css";
7-
pub const MAKO_CSS_MODULES_SUFFIX: &str = ".MAKO_CSS_MODULES";
87

98
pub struct CssModuleRename {
109
pub path: String,
@@ -30,10 +29,6 @@ pub fn is_css_modules_path(path: &str) -> bool {
3029
path.ends_with(CSS_MODULES_PATH_SUFFIX)
3130
}
3231

33-
pub fn is_mako_css_modules(path: &str) -> bool {
34-
path.ends_with(MAKO_CSS_MODULES_SUFFIX)
35-
}
36-
3732
pub fn compile_css_modules(path: &str, ast: &mut Stylesheet) -> TransformResult {
3833
compile(
3934
ast,
@@ -68,11 +63,10 @@ pub fn generate_code_for_css_modules(path: &str, ast: &mut Stylesheet) -> String
6863
}
6964
format!(
7065
r#"
71-
import "{}{}";
66+
import "{}?modules";
7267
export default {{{}}}
7368
"#,
7469
path,
75-
MAKO_CSS_MODULES_SUFFIX,
7670
export_names
7771
.iter()
7872
.map(|(name, classes)| format!("\"{}\": `{}`", name, classes.join(" ").trim()))

crates/mako/src/load.rs

+4-8
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ use thiserror::Error;
1111
use tracing::debug;
1212
use twox_hash::XxHash64;
1313

14+
use crate::build::FileRequest;
1415
use crate::compiler::Context;
15-
use crate::css_modules::{is_mako_css_modules, MAKO_CSS_MODULES_SUFFIX};
1616
use crate::plugin::PluginLoadParam;
1717

1818
pub struct Asset {
@@ -54,13 +54,9 @@ pub enum LoadError {
5454
ToSvgrError { path: String, reason: String },
5555
}
5656

57-
pub fn load(path: &str, is_entry: bool, context: &Arc<Context>) -> Result<Content> {
58-
debug!("load: {}", path);
59-
let path = if is_mako_css_modules(path) {
60-
path.trim_end_matches(MAKO_CSS_MODULES_SUFFIX)
61-
} else {
62-
path
63-
};
57+
pub fn load(request: &FileRequest, is_entry: bool, context: &Arc<Context>) -> Result<Content> {
58+
debug!("load: {:?}", request);
59+
let path = &request.path;
6460
let exists = Path::new(path).exists();
6561
if !exists {
6662
return Err(anyhow!(LoadError::FileNotFound {

crates/mako/src/parse.rs

+23-21
Original file line numberDiff line numberDiff line change
@@ -6,51 +6,53 @@ use swc_css_visit::VisitMutWith;
66
use tracing::debug;
77

88
use crate::ast::{build_css_ast, build_js_ast};
9+
use crate::build::FileRequest;
910
use crate::compiler::Context;
10-
use crate::css_modules::{
11-
compile_css_modules, generate_code_for_css_modules, is_css_modules_path, is_mako_css_modules,
12-
MAKO_CSS_MODULES_SUFFIX,
13-
};
11+
use crate::css_modules::{compile_css_modules, generate_code_for_css_modules, is_css_modules_path};
1412
use crate::load::{Asset, Content};
1513
use crate::module::ModuleAst;
1614

17-
pub fn parse(content: &Content, path: &str, context: &Arc<Context>) -> Result<ModuleAst> {
18-
debug!("parse {}", path);
15+
pub fn parse(
16+
content: &Content,
17+
request: &FileRequest,
18+
context: &Arc<Context>,
19+
) -> Result<ModuleAst> {
20+
debug!("parse {:?}", request);
1921
let ast = match content {
20-
Content::Js(content) => parse_js(content, path, context)?,
21-
Content::Css(content) => parse_css(content, path, context)?,
22-
Content::Assets(asset) => parse_asset(asset, path, context)?,
22+
Content::Js(content) => parse_js(content, request, context)?,
23+
Content::Css(content) => parse_css(content, request, context)?,
24+
Content::Assets(asset) => parse_asset(asset, request, context)?,
2325
};
2426
Ok(ast)
2527
}
2628

27-
fn parse_js(content: &str, path: &str, context: &Arc<Context>) -> Result<ModuleAst> {
28-
let ast = build_js_ast(path, content, context)?;
29+
fn parse_js(content: &str, request: &FileRequest, context: &Arc<Context>) -> Result<ModuleAst> {
30+
let ast = build_js_ast(&request.path, content, context)?;
2931
Ok(ModuleAst::Script(ast))
3032
}
3133

32-
fn parse_css(content: &str, path: &str, context: &Arc<Context>) -> Result<ModuleAst> {
33-
let mut ast = build_css_ast(path, content, context)?;
34+
fn parse_css(content: &str, request: &FileRequest, context: &Arc<Context>) -> Result<ModuleAst> {
35+
let mut ast = build_css_ast(&request.path, content, context)?;
36+
let is_modules = request.has_query("modules");
3437
// parse css module as js
35-
if is_css_modules_path(path) {
36-
let code = generate_code_for_css_modules(path, &mut ast);
37-
let js_ast = build_js_ast(path, &code, context)?;
38+
if is_css_modules_path(&request.path) && !is_modules {
39+
let code = generate_code_for_css_modules(&request.path, &mut ast);
40+
let js_ast = build_js_ast(&request.path, &code, context)?;
3841
Ok(ModuleAst::Script(js_ast))
3942
} else {
4043
// TODO: move to transform step
4144
// compile css compat
4245
compile_css_compat(&mut ast);
4346
// for mako css module, compile it and parse it as css
44-
if is_mako_css_modules(path) {
45-
// should remove the suffix to generate the same hash
46-
compile_css_modules(path.trim_end_matches(MAKO_CSS_MODULES_SUFFIX), &mut ast);
47+
if is_modules {
48+
compile_css_modules(&request.path, &mut ast);
4749
}
4850
Ok(ModuleAst::Css(ast))
4951
}
5052
}
5153

52-
fn parse_asset(asset: &Asset, path: &str, context: &Arc<Context>) -> Result<ModuleAst> {
53-
let ast = build_js_ast(path, &asset.content, context)?;
54+
fn parse_asset(asset: &Asset, request: &FileRequest, context: &Arc<Context>) -> Result<ModuleAst> {
55+
let ast = build_js_ast(&request.path, &asset.content, context)?;
5456
Ok(ModuleAst::Script(ast))
5557
}
5658

crates/mako/src/resolve.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use tracing::debug;
1010

1111
use crate::compiler::Context;
1212
use crate::config::{Config, Platform};
13-
use crate::css_modules::is_mako_css_modules;
1413
use crate::module::{Dependency, ResolveType};
1514

1615
#[derive(Debug, Error)]
@@ -59,17 +58,17 @@ fn do_resolve(
5958
};
6059
if let Some(external) = external {
6160
Ok((source.to_string(), Some(external)))
62-
} else if is_mako_css_modules(source) {
63-
// css_modules has resolved and mako_css_modules cannot be resolved since the suffix
64-
Ok((source.to_string(), None))
6561
} else {
6662
let path = PathBuf::from(path);
6763
// 所有的 path 都是文件,所以 parent() 肯定是其所在目录
6864
let parent = path.parent().unwrap();
6965
debug!("parent: {:?}, source: {:?}", parent, source);
7066
let result = resolver.resolve(parent, source);
7167
if let Ok(ResolveResult::Resource(resource)) = result {
72-
let path = resource.path.to_string_lossy().to_string();
68+
let mut path = resource.path.to_string_lossy().to_string();
69+
if resource.query.is_some() {
70+
path = format!("{}{}", path, resource.query.as_ref().unwrap());
71+
}
7372
Ok((path, None))
7473
} else {
7574
Err(anyhow!(ResolveError::ResolveError {

0 commit comments

Comments
 (0)