Skip to content

Commit

Permalink
feat: output filename (#1725)
Browse files Browse the repository at this point in the history
* refactor: 🎨 add file name template and chunk name in ChunkFile struct

* feat: ✨ add config to output#filename

* feat: ✨ render filename when output#filename configed

* feat: ✨ calc hash in ast impl for entry

* test: ✅ add test case

* test: ✅ add ut

* chore: 🔧 disable codecov error

* refactor: 🎨 remove clone

* fix: 🐛 hash when necessary

* chore: 🔧 add codecov.yml

* release: @umijs/mako@0.9.10-canary.20241218.1

* chore: ⬆️ update pnpm-lock
  • Loading branch information
stormslowly authored Dec 18, 2024
1 parent 8f15f20 commit 817c03e
Show file tree
Hide file tree
Showing 22 changed files with 199 additions and 115 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,4 @@ jobs:
# token: # optional
# Specify whether the Codecov output should be verbose
verbose: true
fail_ci_if_error: true
fail_ci_if_error: false
4 changes: 4 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
coverage:
status:
project: off
patch: off
1 change: 1 addition & 0 deletions crates/mako/src/config/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::utils::get_pkg_name;
#[serde(rename_all = "camelCase")]
pub struct OutputConfig {
pub path: PathBuf,
pub filename: Option<String>,
pub mode: OutputMode,
pub es_version: EsVersion,
pub meta: bool,
Expand Down
12 changes: 8 additions & 4 deletions crates/mako/src/generate/chunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,11 @@ impl Chunk {
}
}

pub fn filename(&self) -> String {
pub fn name(&self) -> String {
match &self.chunk_type {
ChunkType::Runtime => "runtime.js".into(),
ChunkType::Runtime => "runtime".into(),
// foo/bar.tsx -> bar.js
ChunkType::Entry(_, name, _) => format!("{}.js", name),
ChunkType::Entry(_, name, _) => name.clone(),
// foo/bar.tsx -> foo_bar_tsx-async.js
ChunkType::Async | ChunkType::Sync | ChunkType::Worker(_) => {
let (path, search, ..) = parse_path(&self.id.id).unwrap();
Expand Down Expand Up @@ -105,7 +105,7 @@ impl Chunk {
}

format!(
"{}-{}.js",
"{}-{}",
name,
if matches!(self.chunk_type, ChunkType::Worker(_)) {
"worker"
Expand All @@ -117,6 +117,10 @@ impl Chunk {
}
}

pub fn filename(&self) -> String {
format!("{}.js", self.name())
}

pub fn add_module(&mut self, module_id: ModuleId) {
self.modules.insert(module_id);
}
Expand Down
2 changes: 2 additions & 0 deletions crates/mako/src/generate/chunk_pot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub struct ChunkPot<'a> {
pub module_map: HashMap<String, (&'a Module, u64)>,
pub js_hash: u64,
pub stylesheet: Option<CssModules<'a>>,
pub chunk_name: String,
}

impl<'cp> ChunkPot<'cp> {
Expand All @@ -41,6 +42,7 @@ impl<'cp> ChunkPot<'cp> {
chunk_id: chunk.id.id.clone(),
module_map: js_modules.module_map,
js_hash: js_modules.raw_hash,
chunk_name: chunk.name(),
stylesheet,
}
}
Expand Down
8 changes: 7 additions & 1 deletion crates/mako/src/generate/chunk_pot/ast_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ pub(crate) fn render_css_chunk(
file_name: get_css_chunk_filename(&chunk_pot.js_name),
chunk_id: chunk_pot.chunk_id.clone(),
file_type: ChunkFileType::Css,
chunk_name: chunk_pot.chunk_name.clone(),
file_name_template: None,
})
}

Expand Down Expand Up @@ -181,8 +183,10 @@ pub(crate) fn render_normal_js_chunk(
hash,
source_map,
file_name: chunk_pot.js_name.clone(),
chunk_name: chunk_pot.chunk_name.clone(),
chunk_id: chunk_pot.chunk_id.clone(),
file_type: ChunkFileType::JS,
file_name_template: None,
})
}

Expand Down Expand Up @@ -222,6 +226,8 @@ pub(crate) fn render_entry_js_chunk(
file_name: pot.js_name.clone(),
chunk_id: pot.chunk_id.clone(),
file_type: ChunkFileType::JS,
chunk_name: pot.chunk_name.clone(),
file_name_template: context.config.output.filename.clone(),
})
}

Expand Down Expand Up @@ -324,7 +330,7 @@ fn render_entry_chunk_js_without_full_hash(

let (buf, source_map_buf) = util::render_module_js(&ast.ast, context)?;

let hash = if context.config.hash {
let hash = if context.config.hash || context.config.output.filename.is_some() {
crate::mako_profile_scope!("entryHash");
Some(file_content_hash(&buf))
} else {
Expand Down
4 changes: 4 additions & 0 deletions crates/mako/src/generate/chunk_pot/str_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ pub(super) fn render_entry_js_chunk(
file_name: pot.js_name.clone(),
chunk_id: pot.chunk_id.clone(),
file_type: ChunkFileType::JS,
file_name_template: None,
chunk_name: pot.chunk_name.clone(),
})
}

Expand Down Expand Up @@ -152,6 +154,8 @@ pub(super) fn render_normal_js_chunk(
file_name: chunk_pot.js_name.clone(),
chunk_id: chunk_pot.chunk_id.clone(),
file_type: ChunkFileType::JS,
file_name_template: None,
chunk_name: chunk_pot.chunk_name.clone(),
})
}

Expand Down
156 changes: 99 additions & 57 deletions crates/mako/src/generate/generate_chunks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,19 @@ pub struct ChunkFile {
pub content: Vec<u8>,
pub source_map: Option<Vec<u8>>,
pub hash: Option<String>,
pub chunk_name: String,
pub file_name: String,
pub chunk_id: String,
pub file_type: ChunkFileType,
pub file_name_template: Option<String>,
}

impl ChunkFile {
pub fn disk_name(&self) -> String {
let format_file_name = hash_too_long_file_name(&self.file_name);

if let Some(hash) = &self.hash {
hash_file_name(&format_file_name, hash)
if let Some(tmpl) = &self.file_name_template {
self.render_tmpl(tmpl)
} else {
format_file_name
self.default_disk_name()
}
}

Expand All @@ -56,6 +56,26 @@ impl ChunkFile {
pub fn source_map_name(&self) -> String {
format!("{}.map", self.file_name)
}

fn default_disk_name(&self) -> String {
let format_file_name = hash_too_long_file_name(&self.file_name);

if let Some(hash) = &self.hash {
hash_file_name(&format_file_name, hash)
} else {
format_file_name
}
}

fn render_tmpl(&self, tpl: &str) -> String {
let hash_string = self.hash.as_deref().unwrap_or("notHashed");

tpl.replace("[name]", self.chunk_name.as_str())
.replace("[id]", self.chunk_id.as_str())
.replace("[file]", self.file_name.as_str())
.replace("[hash]", hash_string)
.replace("[contenthash]", hash_string)
}
}

type ChunksHashPlaceholder = HashMap<String, String>;
Expand Down Expand Up @@ -102,26 +122,26 @@ impl Compiler {
);

entry_chunk_files_with_placeholder
.par_iter_mut()
.try_for_each(
|(chunk_files, js_chunks_hash_placeholder, css_chunks_hash_placeholder)| -> Result<()>{
replace_chunks_placeholder(
chunk_files,
js_chunks_hash_placeholder,
&js_chunks_hash_replacer,
)?;
replace_chunks_placeholder(
chunk_files,
css_chunks_hash_placeholder,
&css_chunks_hash_replacer,
)?;
chunk_files.iter_mut().for_each(|cf| {
cf.hash = Some(file_content_hash(&cf.content));
});

Ok(())
},
)?;
.par_iter_mut()
.try_for_each(
|(chunk_files, js_chunks_hash_placeholder, css_chunks_hash_placeholder)| -> Result<()>{
replace_chunks_placeholder(
chunk_files,
js_chunks_hash_placeholder,
&js_chunks_hash_replacer,
)?;
replace_chunks_placeholder(
chunk_files,
css_chunks_hash_placeholder,
&css_chunks_hash_replacer,
)?;
chunk_files.iter_mut().for_each(|cf| {
cf.hash = Some(file_content_hash(&cf.content));
});

Ok(())
},
)?;
}

let entry_chunk_files = entry_chunk_files_with_placeholder
Expand Down Expand Up @@ -278,48 +298,48 @@ fn replace_chunks_placeholder(
chunks_hash_replacer: &ChunksHashReplacer,
) -> Result<()> {
chunks_hash_placeholder.iter().try_for_each(
|(chunk_id, placeholder)| match chunks_hash_replacer.get(chunk_id) {
Some(replacer) => {
chunk_files
.iter_mut()
.filter(|cf| matches!(cf.file_type, ChunkFileType::JS))
.try_for_each(|cf| {
if cf.content.is_empty() {
warn!("Chunk content of \"{}\" is empty.", cf.chunk_id);
}

let position = cf
.content
.windows(placeholder.len())
.position(|w| w == placeholder.as_bytes());

position.map_or(
{
Err(anyhow!(
|(chunk_id, placeholder)| match chunks_hash_replacer.get(chunk_id) {
Some(replacer) => {
chunk_files
.iter_mut()
.filter(|cf| matches!(cf.file_type, ChunkFileType::JS))
.try_for_each(|cf| {
if cf.content.is_empty() {
warn!("Chunk content of \"{}\" is empty.", cf.chunk_id);
}

let position = cf
.content
.windows(placeholder.len())
.position(|w| w == placeholder.as_bytes());

position.map_or(
{
Err(anyhow!(
"Generate \"{}\" failed, placeholder \"{}\" for \"{}\" not existed in chunk file.",
cf.chunk_id,
placeholder,
chunk_id
))
},
|pos| {
cf.content.splice(
pos..pos + replacer.len(),
replacer.as_bytes().to_vec(),
);
Ok(())
},
)
})?;
},
|pos| {
cf.content.splice(
pos..pos + replacer.len(),
replacer.as_bytes().to_vec(),
);
Ok(())
}
_ => Err(anyhow!(
},
)
})?;
Ok(())
}
_ => Err(anyhow!(
"Generate \"{}\" failed, replacer not found for placeholder \"{}\".",
chunk_id,
placeholder
)),
},
)
},
)
}

pub fn build_props(key_str: &str, value: Box<Expr>) -> PropOrSpread {
Expand Down Expand Up @@ -414,3 +434,25 @@ fn hash_too_long_file_name(file_name: &String) -> String {

format_file_name.to_string()
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_simple_template_render() {
let chunk_file = ChunkFile {
raw_hash: 0,
content: vec![],
source_map: None,
hash: Some("hash999".to_string()),
chunk_name: "chunk".to_string(),
file_name: "index.js".to_string(),
chunk_id: "c_id".to_string(),
file_type: ChunkFileType::JS,
file_name_template: Some("[name].[hash].[id].js".to_string()),
};

assert_eq!(chunk_file.disk_name(), "chunk.hash999.c_id.js");
}
}
10 changes: 10 additions & 0 deletions e2e/fixtures/config.output.filename/expect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const {
injectSimpleJest,
parseBuildResult,
} = require("../../../scripts/test-utils");

injectSimpleJest();
const {files} = parseBuildResult(__dirname);
let filename = Object.keys(files)[0]

expect(filename).toMatch(/index\.umd\..+\.js/)
5 changes: 5 additions & 0 deletions e2e/fixtures/config.output.filename/mako.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"output": {
"filename": "[name].umd.[hash].js"
}
}
1 change: 1 addition & 0 deletions e2e/fixtures/config.output.filename/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log(1);
2 changes: 1 addition & 1 deletion packages/bundler-mako/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "0.9.9",
"dependencies": {
"@umijs/bundler-utils": "^4.0.81",
"@umijs/mako": "0.9.9",
"@umijs/mako": "0.9.10-canary.20241218.1",
"chalk": "^4.1.2",
"compression": "^1.7.4",
"connect-history-api-fallback": "^2.0.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/mako/npm/darwin-arm64/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@umijs/mako-darwin-arm64",
"version": "0.9.9",
"version": "0.9.10-canary.20241218.1",
"os": [
"darwin"
],
Expand Down
2 changes: 1 addition & 1 deletion packages/mako/npm/darwin-x64/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@umijs/mako-darwin-x64",
"version": "0.9.9",
"version": "0.9.10-canary.20241218.1",
"os": [
"darwin"
],
Expand Down
2 changes: 1 addition & 1 deletion packages/mako/npm/linux-arm64-gnu/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@umijs/mako-linux-arm64-gnu",
"version": "0.9.9",
"version": "0.9.10-canary.20241218.1",
"os": [
"linux"
],
Expand Down
2 changes: 1 addition & 1 deletion packages/mako/npm/linux-arm64-musl/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@umijs/mako-linux-arm64-musl",
"version": "0.9.9",
"version": "0.9.10-canary.20241218.1",
"os": [
"linux"
],
Expand Down
Loading

0 comments on commit 817c03e

Please sign in to comment.