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: support load with jsx enabled js #1079

Merged
merged 1 commit into from
Apr 23, 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
15 changes: 13 additions & 2 deletions crates/binding/src/js_plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::tsfn::{LoadResult, ReadMessage, TsFnHooks, WriteRequest};
pub struct JsPlugin {
pub hooks: TsFnHooks,
}
use mako::ast::file::Content;
use mako::ast::file::{Content, JsContent};
use mako::compiler::Context;
use mako::plugin::{Plugin, PluginGenerateEndParams, PluginLoadParam};
use mako_core::anyhow::{anyhow, Result};
Expand Down Expand Up @@ -44,7 +44,18 @@ impl Plugin for JsPlugin {
.unwrap_or_else(|e| panic!("recv error: {:?}", e.to_string()))?;
if let Some(x) = x {
match x.content_type.as_str() {
"js" => return Ok(Some(Content::Js(x.content))),
"js" | "ts" => {
return Ok(Some(Content::Js(JsContent {
content: x.content,
is_jsx: false,
})))
}
"jsx" | "tsx" => {
return Ok(Some(Content::Js(JsContent {
content: x.content,
is_jsx: true,
})))
}
"css" => return Ok(Some(Content::Css(x.content))),
_ => return Err(anyhow!("Unsupported content type: {}", x.content_type)),
}
Expand Down
30 changes: 27 additions & 3 deletions crates/mako/src/ast/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,24 @@ pub struct Asset {
pub content: String,
}

#[derive(Debug, Clone)]
pub struct JsContent {
pub is_jsx: bool,
pub content: String,
}

impl Default for JsContent {
fn default() -> Self {
JsContent {
is_jsx: false,
content: "".to_string(),
}
}
}

#[derive(Debug, Clone)]
pub enum Content {
Js(String),
Js(JsContent),
Css(String),
// TODO: unify the assets handler
// it's used in minifish plugin(bundless mode) only
Expand Down Expand Up @@ -159,7 +174,9 @@ impl File {

pub fn get_content_raw(&self) -> String {
match &self.content {
Some(Content::Js(content)) | Some(Content::Css(content)) => content.clone(),
Some(Content::Js(JsContent { content, .. })) | Some(Content::Css(content)) => {
content.clone()
}
Some(Content::Assets(asset)) => asset.content.clone(),
None => "".to_string(),
}
Expand All @@ -169,7 +186,7 @@ impl File {
let mut hasher: XxHash64 = Default::default();
if let Some(content) = &self.content {
match content {
Content::Js(content)
Content::Js(JsContent { content, .. })
| Content::Css(content)
| Content::Assets(Asset { content, .. }) => {
// hasher.write_u64(init);
Expand Down Expand Up @@ -236,6 +253,13 @@ impl File {
Ok(hash[0..8].to_string())
}

pub fn is_content_jsx(&self) -> bool {
match &self.content {
Some(Content::Js(JsContent { is_jsx, .. })) => *is_jsx,
_ => false,
}
}

pub fn has_param(&self, key: &str) -> bool {
self.params.iter().any(|(k, _)| k == key)
}
Expand Down
13 changes: 8 additions & 5 deletions crates/mako/src/ast/js_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use mako_core::swc_ecma_visit::{VisitMutWith, VisitWith};
use swc_core::base::try_with_handler;
use swc_core::common::Spanned;

use super::file::Content;
use super::file::{Content, JsContent};
use crate::ast::file::File;
use crate::ast::{error, utils};
use crate::compiler::Context;
Expand Down Expand Up @@ -59,9 +59,8 @@ impl JsAst {
..Default::default()
})
} else {
let jsx = extname == "jsx"
// when use svg as svgr, it should come here and be treated as jsx
|| extname == "svg"
let jsx = file.is_content_jsx()
|| extname == "jsx"
|| (extname == "js" && !file.is_under_node_modules);
Syntax::Es(EsConfig {
jsx,
Expand Down Expand Up @@ -119,10 +118,14 @@ impl JsAst {
}

pub fn build(path: &str, content: &str, context: Arc<Context>) -> Result<Self> {
let is_jsx = path.ends_with(".jsx") || path.ends_with(".tsx");
JsAst::new(
&File::with_content(
path.to_string(),
Content::Js(content.to_string()),
Content::Js(JsContent {
content: content.to_string(),
is_jsx,
}),
context.clone(),
),
context.clone(),
Expand Down
5 changes: 3 additions & 2 deletions crates/mako/src/ast/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use mako_core::swc_ecma_visit::VisitMutWith;
use swc_core::common::GLOBALS;

use super::css_ast::{CSSAstGenerated, CssAst};
use super::file::{Content, File};
use super::file::{Content, File, JsContent};
use super::js_ast::{JSAstGenerated, JsAst};
use crate::compiler::Context;
use crate::config::Mode;
Expand Down Expand Up @@ -67,6 +67,7 @@ impl TestUtils {
} else {
"test.js".to_string()
};
let is_jsx = file.ends_with(".jsx") || file.ends_with(".tsx");
let mut file = File::new(file, context.clone());
let is_css = file.extname == "css";
let content = if let Some(content) = opts.content {
Expand All @@ -77,7 +78,7 @@ impl TestUtils {
if is_css {
file.set_content(Content::Css(content));
} else {
file.set_content(Content::Js(content));
file.set_content(Content::Js(JsContent { content, is_jsx }));
}
let ast = if is_css {
TestAst::Css(CssAst::new(&file, context.clone(), false).unwrap())
Expand Down
17 changes: 13 additions & 4 deletions crates/mako/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use mako_core::colored::Colorize;
use mako_core::thiserror::Error;

use crate::analyze_deps::AnalyzeDeps;
use crate::ast::file::{Content, File};
use crate::ast::file::{Content, File, JsContent};
use crate::chunk_pot::util::hash_hashmap;
use crate::compiler::{Compiler, Context};
use crate::load::Load;
Expand Down Expand Up @@ -164,7 +164,10 @@ __mako_require__.loadScript('{}', (e) => e.type === 'load' ? resolve() : reject(
} else {
format!("module.exports = {};", external_name)
};
file.set_content(Content::Js(code));
file.set_content(Content::Js(JsContent {
content: code,
..Default::default()
}));
let ast = Parse::parse(&file, context)
// safe
.unwrap();
Expand All @@ -188,7 +191,10 @@ __mako_require__.loadScript('{}', (e) => e.type === 'load' ? resolve() : reject(
fn create_error_module(file: &File, err: String, context: Arc<Context>) -> Result<Module> {
let mut file = file.clone();
let code = format!("throw new Error(`Module build failed:\n{:}`)", err);
file.set_content(Content::Js(code));
file.set_content(Content::Js(JsContent {
content: code,
..Default::default()
}));
let ast = Parse::parse(&file, context.clone())?;
let path = file.path.to_string_lossy().to_string();
let module_id = ModuleId::new(path.clone());
Expand All @@ -211,7 +217,10 @@ __mako_require__.loadScript('{}', (e) => e.type === 'load' ? resolve() : reject(
let info = {
let file = File::with_content(
path.to_owned(),
Content::Js("export {};".to_string()),
Content::Js(JsContent {
content: "export {};".to_string(),
..Default::default()
}),
context.clone(),
);
let ast = Parse::parse(&file, context.clone()).unwrap();
Expand Down
68 changes: 46 additions & 22 deletions crates/mako/src/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use mako_core::thiserror::Error;
use mako_core::toml::{from_str as from_toml_str, Value as TomlValue};
use mako_core::tracing::debug;

use crate::ast::file::{Content, File};
use crate::ast::file::{Content, File, JsContent};
use crate::compiler::Context;
use crate::config::Mode;
use crate::plugin::PluginLoadParam;
Expand Down Expand Up @@ -63,8 +63,8 @@ impl Load {

// virtual:inline_css:runtime
if file.path.to_str().unwrap() == "virtual:inline_css:runtime" {
return Ok(Content::Js(
r#"
return Ok(Content::Js(JsContent {
content: r#"
var memo = {};
export function moduleToDom(css) {
var styleElement = document.createElement("style");
Expand All @@ -80,9 +80,10 @@ export function moduleToDom(css) {
}
target.appendChild(styleElement);
}
"#
"#
.to_string(),
));
..Default::default()
}));
}

// file exists check must after virtual modules handling
Expand All @@ -104,13 +105,17 @@ export function moduleToDom(css) {
if file.has_param("raw") {
let content = FileSystem::read_file(&file.pathname)?;
let content = serde_json::to_string(&content)?;
return Ok(Content::Js(format!("module.exports = {}", content)));
return Ok(Content::Js(JsContent {
content: format!("module.exports = {}", content),
..Default::default()
}));
}

// js
if JS_EXTENSIONS.contains(&file.extname.as_str()) {
// entry with ?hmr
// TODO: should be more general
let is_jsx = file.extname.as_str() == "jsx" || file.extname.as_str() == "tsx";
if file.is_entry && file.has_param("hmr") {
let port = &context.config.hmr.as_ref().unwrap().port.to_string();
let host = &context.config.hmr.as_ref().unwrap().host.to_string();
Expand All @@ -122,10 +127,10 @@ export function moduleToDom(css) {
)
.replace("__PORT__", port)
.replace("__HOST__", host);
return Ok(Content::Js(content));
return Ok(Content::Js(JsContent { content, is_jsx }));
}
let content = FileSystem::read_file(&file.pathname)?;
return Ok(Content::Js(content));
return Ok(Content::Js(JsContent { content, is_jsx }));
}

// css
Expand All @@ -150,7 +155,8 @@ export function moduleToDom(css) {
}));
}
};
return Ok(Content::Js(content));
let is_jsx = file.extname.as_str() == "mdx";
return Ok(Content::Js(JsContent { content, is_jsx }));
}

// svg
Expand All @@ -173,18 +179,21 @@ export function moduleToDom(css) {
reason: err.to_string(),
})?;
let asset_path = Self::handle_asset(file, true, context.clone())?;
return Ok(Content::Js(format!(
"{}\nexport default {};",
svgr_transformed, asset_path
)));
return Ok(Content::Js(JsContent {
content: format!("{}\nexport default {};", svgr_transformed, asset_path),
is_jsx: true,
}));
}

// toml
if TOML_EXTENSIONS.contains(&file.extname.as_str()) {
let content = FileSystem::read_file(&file.pathname)?;
let content = from_toml_str::<TomlValue>(&content)?;
let content = serde_json::to_string(&content)?;
return Ok(Content::Js(format!("module.exports = {}", content)));
return Ok(Content::Js(JsContent {
content: format!("module.exports = {}", content),
..Default::default()
}));
}

// wasm
Expand All @@ -199,38 +208,53 @@ export function moduleToDom(css) {
file.pathname.to_string_lossy().to_string(),
final_file_name.clone(),
);
return Ok(Content::Js(format!(
"module.exports = require._interopreRequireWasm(exports, \"{}\")",
final_file_name
)));
return Ok(Content::Js(JsContent {
content: format!(
"module.exports = require._interopreRequireWasm(exports, \"{}\")",
final_file_name
),
..Default::default()
}));
}

// xml
if XML_EXTENSIONS.contains(&file.extname.as_str()) {
let content = FileSystem::read_file(&file.pathname)?;
let content = from_xml_str::<serde_json::Value>(&content)?;
let content = serde_json::to_string(&content)?;
return Ok(Content::Js(format!("module.exports = {}", content)));
return Ok(Content::Js(JsContent {
content: format!("module.exports = {}", content),
..Default::default()
}));
}

// yaml
if YAML_EXTENSIONS.contains(&file.extname.as_str()) {
let content = FileSystem::read_file(&file.pathname)?;
let content = from_yaml_str::<YamlValue>(&content)?;
let content = serde_json::to_string(&content)?;
return Ok(Content::Js(format!("module.exports = {}", content)));
return Ok(Content::Js(JsContent {
content: format!("module.exports = {}", content),
..Default::default()
}));
}

// json
// TODO: json5 should be more complex
if JSON_EXTENSIONS.contains(&file.extname.as_str()) {
let content = FileSystem::read_file(&file.pathname)?;
return Ok(Content::Js(format!("module.exports = {}", content)));
return Ok(Content::Js(JsContent {
content: format!("module.exports = {}", content),
..Default::default()
}));
}

// assets
let asset_path = Self::handle_asset(file, true, context.clone())?;
Ok(Content::Js(format!("module.exports = {};", asset_path)))
Ok(Content::Js(JsContent {
content: format!("module.exports = {};", asset_path),
..Default::default()
}))
}

pub fn handle_asset(
Expand Down
Loading
Loading