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

feat: output filename #1725

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
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>,
stormslowly marked this conversation as resolved.
Show resolved Hide resolved
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 {
xusd320 marked this conversation as resolved.
Show resolved Hide resolved
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);
Loading