Skip to content

Commit

Permalink
feat: add transform plugin hook
Browse files Browse the repository at this point in the history
  • Loading branch information
sorrycc committed Oct 15, 2024
1 parent 9719128 commit 012dd42
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 19 deletions.
15 changes: 15 additions & 0 deletions crates/binding/src/js_hook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ pub struct JsHooks {
ts_type = "(source: string, importer: string, { isEntry: bool }) => Promise<{ id: string }>;"
)]
pub resolve_id: Option<JsFunction>,
#[napi(
ts_type = "(content: { content: string, type: 'css' | 'js' }, path: string) => Promise<{ content: string, type: 'css' | 'js' } | void> | void;"
)]
pub transform: Option<JsFunction>,
}

pub struct TsFnHooks {
Expand All @@ -74,6 +78,7 @@ pub struct TsFnHooks {
pub resolve_id:
Option<ThreadsafeFunction<(String, String, ResolveIdParams), Option<ResolveIdResult>>>,
pub _on_generate_file: Option<ThreadsafeFunction<WriteFile, ()>>,
pub transform: Option<ThreadsafeFunction<(String, String), Option<TransformResult>>>,
}

impl TsFnHooks {
Expand All @@ -97,6 +102,9 @@ impl TsFnHooks {
_on_generate_file: hooks._on_generate_file.as_ref().map(|hook| unsafe {
ThreadsafeFunction::from_napi_value(env.raw(), hook.raw()).unwrap()
}),
transform: hooks.transform.as_ref().map(|hook| unsafe {
ThreadsafeFunction::from_napi_value(env.raw(), hook.raw()).unwrap()
}),
}
}
}
Expand Down Expand Up @@ -125,3 +133,10 @@ pub struct ResolveIdResult {
pub struct ResolveIdParams {
pub is_entry: bool,
}

#[napi(object, use_nullable = true)]
pub struct TransformResult {
pub content: String,
#[napi(js_name = "type")]
pub content_type: String,
}
50 changes: 45 additions & 5 deletions crates/binding/src/js_plugin.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
use std::path::PathBuf;
use std::sync::Arc;

use crate::js_hook::{LoadResult, ResolveIdParams, ResolveIdResult, TsFnHooks, WriteFile};

pub struct JsPlugin {
pub hooks: TsFnHooks,
}
use anyhow::{anyhow, Result};
use mako::ast::file::{Content, JsContent};
use mako::compiler::Context;
use mako::plugin::{Plugin, PluginGenerateEndParams, PluginLoadParam, PluginResolveIdParams};
use mako::resolve::{ExternalResource, Resolution, ResolvedResource, ResolverResource};

use crate::js_hook::{
LoadResult, TransformResult, ResolveIdParams, ResolveIdResult, TsFnHooks, WriteFile,
};

pub struct JsPlugin {
pub hooks: TsFnHooks,
}

impl Plugin for JsPlugin {
fn name(&self) -> &str {
"js_plugin"
Expand Down Expand Up @@ -112,4 +115,41 @@ impl Plugin for JsPlugin {
}
Ok(())
}

fn load_transform(
&self,
content: &mut Content,
path: &str,
_context: &Arc<Context>,
) -> Result<Option<Content>> {
if let Some(hook) = &self.hooks.transform {
let content_str = match content {
Content::Js(js_content) => js_content.content.clone(),
Content::Css(css_content) => css_content.clone(),
_ => return Ok(None),
};

let result: Option<TransformResult> = hook.call((content_str, path.to_string()))?;

if let Some(result) = result {
match result.content_type.as_str() {
"js" | "ts" => {
return Ok(Some(Content::Js(JsContent {
content: result.content,
is_jsx: false,
})))
}
"jsx" | "tsx" => {
return Ok(Some(Content::Js(JsContent {
content: result.content,
is_jsx: true,
})))
}
"css" => return Ok(Some(Content::Css(result.content))),
_ => return Err(anyhow!("Unsupported content type: {}", result.content_type)),
}
}
}
Ok(None)
}
}
7 changes: 6 additions & 1 deletion crates/mako/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,12 @@ __mako_require__.loadScript('{}', (e) => e.type === 'load' ? resolve() : reject(
) -> Result<Module> {
// 1. load
let mut file = file.clone();
let content = load::Load::load(&file, context.clone())?;
let mut content = load::Load::load(&file, context.clone())?;
let content = context.plugin_driver.load_transform(
&mut content,
&file.path.to_string_lossy(),
&context,
)?;
file.set_content(content);

// 2. parse
Expand Down
24 changes: 24 additions & 0 deletions crates/mako/src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ pub trait Plugin: Any + Send + Sync {
Ok(None)
}

fn load_transform(
&self,
_content: &mut Content,
_path: &str,
_context: &Arc<Context>,
) -> Result<Option<Content>> {
Ok(None)
}

fn resolve_id(
&self,
_source: &str,
Expand Down Expand Up @@ -377,4 +386,19 @@ impl PluginDriver {

Ok(())
}

pub fn load_transform(
&self,
content: &mut Content,
path: &str,
context: &Arc<Context>,
) -> Result<Content> {
let mut content = content.clone();
for plugin in &self.plugins {
if let Some(transformed) = plugin.load_transform(&mut content, path, context)? {
content = transformed;
}
}
Ok(content)
}
}
3 changes: 3 additions & 0 deletions e2e/fixtures/plugins/expect.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ assert(content.includes(`children: ".hoo"`), `relative plugin works`);
// resolve_id hook
assert(content.includes(`resolve_id mocked`), `resolve_id hook works`);
assert(content.includes(`module.exports = resolve_id_external;`), `resolve_id hook with external works`);

// transform hook
assert(content.includes(`console.log('transform_2_1');`), `transform hook works`);
50 changes: 37 additions & 13 deletions e2e/fixtures/plugins/plugins.config.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,60 @@

module.exports = [
{
async load(path) {
if (path.endsWith('foo.bar')) {
if (path.endsWith("foo.bar")) {
return {
content: `export default () => <Foooo>foo.bar</Foooo>;`,
type: 'jsx',
type: "jsx",
};
}
}
},
},
{
async loadInclude(path) {
return path.endsWith('.bar');
return path.endsWith(".bar");
},
async load() {
return {
content: `export default () => <Foooo>.bar</Foooo>;`,
type: 'jsx',
type: "jsx",
};
}
},
},
{
async resolveId(source, importer, options) {
console.log('resolveId', source, importer, options);
if (source === 'resolve_id') {
return { id: require('path').join(__dirname, 'resolve_id_mock.js'), external: false };
console.log("resolveId", source, importer, options);
if (source === "resolve_id") {
return {
id: require("path").join(__dirname, "resolve_id_mock.js"),
external: false,
};
}
if (source === 'resolve_id_external') {
return { id: 'resolve_id_external', external: true };
if (source === "resolve_id_external") {
return { id: "resolve_id_external", external: true };
}
return null;
}
},
},
{
async transform(code, id) {
if (id.endsWith("transform.ts")) {
console.log("transform", code, id);
return {
content: code.replace("transform", "transform_1"),
type: "ts",
};
}
},
},
{
async transform(code, id) {
if (id.endsWith("transform.ts")) {
console.log("transform", code, id);
return {
content: code.replace("transform", "transform_2"),
type: "ts",
};
}
},
},
];
3 changes: 3 additions & 0 deletions e2e/fixtures/plugins/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ console.log(require('./foo.haha'));
console.log(require('./foo.hoo'));
console.log(require('resolve_id'));
console.log(require('resolve_id_external'));

// transform
console.log(require('./transform'));
2 changes: 2 additions & 0 deletions e2e/fixtures/plugins/src/transform.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

console.log('transform');
8 changes: 8 additions & 0 deletions packages/mako/binding.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ export interface JsHooks {
importer: string,
{ isEntry: bool },
) => Promise<{ id: string }>;
transform?: (
content: { content: string; type: 'css' | 'js' },
path: string,
) => Promise<{ content: string; type: 'css' | 'js' } | void> | void;
}
export interface WriteFile {
path: string;
Expand All @@ -73,6 +77,10 @@ export interface ResolveIdResult {
export interface ResolveIdParams {
isEntry: boolean;
}
export interface LoadTransformResult {
content: string;
type: string;
}
export interface BuildParams {
root: string;
config: {
Expand Down

0 comments on commit 012dd42

Please sign in to comment.