Skip to content

Commit

Permalink
feat: emit assets for new URL() (#1261)
Browse files Browse the repository at this point in the history
  • Loading branch information
sorrycc committed Jun 11, 2024
1 parent ba53450 commit 0e0aac2
Show file tree
Hide file tree
Showing 13 changed files with 192 additions and 3 deletions.
7 changes: 4 additions & 3 deletions crates/mako/src/build/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ export function moduleToDom(css) {
path: file.path.to_string_lossy().to_string(),
reason: err.to_string(),
})?;
let asset_path = Self::handle_asset(file, true, context.clone())?;
let asset_path = Self::handle_asset(file, true, true, context.clone())?;
return Ok(Content::Js(JsContent {
content: format!("{}\nexport default {};", svgr_transformed, asset_path),
is_jsx: true,
Expand Down Expand Up @@ -235,7 +235,7 @@ export function moduleToDom(css) {
}

// assets
let asset_path = Self::handle_asset(file, true, context.clone())?;
let asset_path = Self::handle_asset(file, true, true, context.clone())?;
Ok(Content::Js(JsContent {
content: format!("module.exports = {};", asset_path),
..Default::default()
Expand All @@ -245,6 +245,7 @@ export function moduleToDom(css) {
pub fn handle_asset(
file: &File,
inject_public_path: bool,
limit: bool,
context: Arc<Context>,
) -> Result<String> {
let file_size = file
Expand All @@ -260,7 +261,7 @@ export function moduleToDom(css) {
Ok(final_file_name)
}
};
if file_size > context.config.inline_limit.try_into().unwrap() {
if !limit || file_size > context.config.inline_limit.try_into().unwrap() {
emit_assets()
} else {
let base64_result = file.get_base64();
Expand Down
6 changes: 6 additions & 0 deletions crates/mako/src/build/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use crate::visitors::default_export_namer::DefaultExportNamer;
use crate::visitors::dynamic_import_to_require::DynamicImportToRequire;
use crate::visitors::env_replacer::{build_env_map, EnvReplacer};
use crate::visitors::fix_helper_inject_position::FixHelperInjectPosition;
use crate::visitors::new_url_assets::NewUrlAssets;
use crate::visitors::provide::Provide;
use crate::visitors::react::react;
use crate::visitors::try_resolve::TryResolve;
Expand Down Expand Up @@ -62,6 +63,11 @@ impl Transform {
// should be removed after upgrade to latest swc
// ref: https://github.com/umijs/mako/issues/1193
visitors.push(Box::new(FixHelperInjectPosition::new()));
visitors.push(Box::new(NewUrlAssets {
context: context.clone(),
path: file.path.clone(),
unresolved_mark,
}));
// strip should be ts only
// since when use this in js, it will remove all unused imports
// which is not expected as what webpack does
Expand Down
1 change: 1 addition & 0 deletions crates/mako/src/visitors/css_assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ impl VisitMut for CSSAssets {
let asset_content = Load::handle_asset(
&File::new(resolved_path.clone(), self.context.clone()),
false,
true,
self.context.clone(),
);
let asset_content = asset_content.unwrap_or(resolved_path);
Expand Down
1 change: 1 addition & 0 deletions crates/mako/src/visitors/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub(crate) mod env_replacer;
pub(crate) mod fix_helper_inject_position;
pub(crate) mod mako_require;
pub(crate) mod meta_url_replacer;
pub(crate) mod new_url_assets;
pub(crate) mod optimize_define_utils;
pub(crate) mod provide;
pub(crate) mod react;
Expand Down
141 changes: 141 additions & 0 deletions crates/mako/src/visitors/new_url_assets.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
use std::path::PathBuf;
use std::sync::Arc;

use mako_core::anyhow::Result;
use mako_core::swc_ecma_ast::{BinExpr, BinaryOp, Expr, Lit};
use mako_core::swc_ecma_utils::{member_expr, quote_str};
use swc_core::common::{Mark, DUMMY_SP};
use swc_core::ecma::visit::VisitMut;

use crate::ast::file::File;
use crate::ast::utils;
use crate::build::load::Load;
use crate::compiler::Context;
use crate::config::Platform;
use crate::module::{Dependency, ResolveType};
use crate::resolve;

pub struct NewUrlAssets {
pub context: Arc<Context>,
pub path: PathBuf,
pub unresolved_mark: Mark,
}

impl NewUrlAssets {
fn handle_asset(&self, url: String) -> Result<String> {
let dep = Dependency {
source: url,
resolve_as: None,
resolve_type: ResolveType::Css,
order: 0,
span: None,
};
let resolved = resolve::resolve(
self.path.to_string_lossy().as_ref(),
&dep,
&self.context.resolvers,
&self.context,
)?;
let resolved_path = resolved.get_resolved_path();
Load::handle_asset(
&File::new(resolved_path.clone(), self.context.clone()),
false,
false,
self.context.clone(),
)
}

fn build_import_meta_url(&self, context: Arc<Context>) -> Expr {
let is_browser = matches!(context.config.platform, Platform::Browser);
if is_browser {
Expr::Bin(BinExpr {
span: DUMMY_SP,
op: BinaryOp::LogicalOr,
left: member_expr!(DUMMY_SP, document.baseURI),
right: member_expr!(DUMMY_SP, self.location.href),
})
} else {
Expr::Lit(
quote_str!(format!(
"file://{}",
self.path.to_string_lossy().to_string()
))
.into(),
)
}
}
}

impl VisitMut for NewUrlAssets {
fn visit_mut_new_expr(&mut self, n: &mut mako_core::swc_ecma_ast::NewExpr) {
// new URL('', import.meta.url)
if let box Expr::Ident(ident) = &n.callee {
#[allow(clippy::needless_borrow)]
if utils::is_ident_undefined(&ident, "URL", &self.unresolved_mark) {
let args = n.args.as_mut().unwrap();
if args
.get(1)
.is_some_and(|arg| utils::is_import_meta_url(&arg.expr))
{
if let box Expr::Lit(Lit::Str(ref url)) = &args[0].expr {
if !utils::is_remote_or_data(&url.value) {
let origin = url.value.to_string();
let url = self.handle_asset(origin.clone());
if url.is_err() {
eprintln!("Failed to handle asset: {}", origin);
}
let url = url.unwrap_or(origin);
let is_browser =
matches!(self.context.config.platform, Platform::Browser);
args[0].expr = if is_browser {
Expr::Bin(BinExpr {
span: DUMMY_SP,
op: BinaryOp::Add,
left: member_expr!(DUMMY_SP, __mako_require__.publicPath),
right: Lit::Str(url.into()).into(),
})
.into()
} else {
Lit::Str(url.into()).into()
};
args[1].expr = self.build_import_meta_url(self.context.clone()).into();
}
}
}
}
}
}
}

#[cfg(test)]
mod tests {
use mako_core::swc_ecma_visit::VisitMutWith;
use swc_core::common::GLOBALS;

use super::NewUrlAssets;
use crate::ast::tests::TestUtils;

#[test]
fn test_normal() {
assert_eq!(
run(r#"new URL('big.jpg', import.meta.url)"#),
r#"new URL(__mako_require__.publicPath + "big.8e6c05c3.jpg", document.baseURI || self.location.href);"#
)
}

fn run(js_code: &str) -> String {
let mut test_utils = TestUtils::gen_js_ast(js_code.to_string());
let ast = test_utils.ast.js_mut();
GLOBALS.set(&test_utils.context.meta.script.globals, || {
let current_dir = std::env::current_dir().unwrap();
let path = current_dir.join("src/visitors/fixtures/css_assets/test.js");
let mut visitor = NewUrlAssets {
context: test_utils.context.clone(),
unresolved_mark: ast.unresolved_mark,
path,
};
ast.ast.visit_mut_with(&mut visitor);
});
test_utils.js_ast_to_code()
}
}
4 changes: 4 additions & 0 deletions e2e/fixtures/assets.new_url.node/mako.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"platform": "node",
"publicPath": "./"
}
1 change: 1 addition & 0 deletions e2e/fixtures/assets.new_url.node/src/assets/person.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions e2e/fixtures/assets.new_url.node/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
let x = new URL("./assets/person.svg", import.meta.url);
console.log(x);
13 changes: 13 additions & 0 deletions e2e/fixtures/assets.new_url/expect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const assert = require("assert");
const { parseBuildResult, moduleReg } = require("../../../scripts/test-utils");
const { files } = parseBuildResult(__dirname);

const names = Object.keys(files).join(",");
const content = files["index.js"];

// check files
assert.match(names, /person.(.*).svg/, "should have person.svg");

// check content
assert(content.includes(`new URL(__mako_require__.publicPath + "person.`), 'new URL() should be replaced');
assert(content.includes(`document.baseURI || self.location.href);`), 'import.meta.url should be replaced');
6 changes: 6 additions & 0 deletions e2e/fixtures/assets.new_url/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<!DOCTYPE html>
<html lang="en">
<body>
<script src="index.js"></script>
</body>
</html>
Loading

0 comments on commit 0e0aac2

Please sign in to comment.