From f6ab4e4dbd63b7255364ba5b3d8529c2672b0e84 Mon Sep 17 00:00:00 2001 From: Bright <1521488775@qq.com> Date: Fri, 2 Feb 2024 09:20:33 +0800 Subject: [PATCH] chore: add rust plugins docs --- docs/api/hmr-api.md | 8 +- docs/plugins/community-plugins.md | 2 +- docs/plugins/writing-plugins/js-plugin.md | 2 - docs/plugins/writing-plugins/overview.md | 5 +- docs/plugins/writing-plugins/rust-plugin.md | 155 +++++++++++++++++++- 5 files changed, 159 insertions(+), 13 deletions(-) diff --git a/docs/api/hmr-api.md b/docs/api/hmr-api.md index 4fb887c4d..dfdcb98cd 100644 --- a/docs/api/hmr-api.md +++ b/docs/api/hmr-api.md @@ -3,7 +3,7 @@ The HMR API is compatible with [Vite's HMR API](https://vitejs.dev/guide/api-hmr.html). ::: -Farm exposes its manual HMR API via the special import.meta.hot object(the same as Vite): +Farm exposes its manual HMR API via the special `import.meta.hot` object(the same as Vite): ```ts export interface ViteHotContext { readonly data: any; @@ -16,12 +16,6 @@ export interface ViteHotContext { cb: (mods: Array) => void ): void; - // acceptExports is not supported in Farm for now - // acceptExports( - // exportNames: string | readonly string[], - // cb?: (mod: ModuleNamespace | undefined) => void - // ): void; - dispose(cb: (data: any) => void): void; prune(cb: (data: any) => void): void; invalidate(message?: string): void; diff --git a/docs/plugins/community-plugins.md b/docs/plugins/community-plugins.md index 3044826a5..a2727da6a 100644 --- a/docs/plugins/community-plugins.md +++ b/docs/plugins/community-plugins.md @@ -2,7 +2,7 @@ Farm support `Vite/Rollup` plugins out of box. So `Vite/Rollup` or `unplugin` plugins can be used in Farm directly. :::tip -PR welcome if you developed a Farm compatible plugin and you want to list it here. +Farm recommends to write Farm Plugins instead of `Vite/Rollup` plugins for Farm. Because Farm Plugins have the best compatibility and performance. Still, PR welcome if you developed a Farm compatible plugin and you want to list it here. ::: Current tested compatible `Vite/Rollup/unplugin` plugins as below: diff --git a/docs/plugins/writing-plugins/js-plugin.md b/docs/plugins/writing-plugins/js-plugin.md index d219e8f50..84a60c903 100644 --- a/docs/plugins/writing-plugins/js-plugin.md +++ b/docs/plugins/writing-plugins/js-plugin.md @@ -1,8 +1,6 @@ # JavaScript Plugins -:::tip{title="Js Plugins"} A JavaScript plugin is simply a pure JavaScript object. -::: ```js // farm.config.ts diff --git a/docs/plugins/writing-plugins/overview.md b/docs/plugins/writing-plugins/overview.md index e676fe590..b76ae1202 100644 --- a/docs/plugins/writing-plugins/overview.md +++ b/docs/plugins/writing-plugins/overview.md @@ -17,5 +17,6 @@ defineFarmConfig({ Farm support both rust plugins and js plugins: -* [Rust Plugin](/docs/plugins/rust-plugin) -* [Js plugin](/docs/plugins/js-plugin) \ No newline at end of file +* [Rust Plugin](/docs/plugins/writing-plugins/rust-plugin) +* [Js Plugin](/docs/plugins/writing-plugins/js-plugin) +* [Runtime Plugin](/docs/plugins/writing-plugins/runtime-plugin) \ No newline at end of file diff --git a/docs/plugins/writing-plugins/rust-plugin.md b/docs/plugins/writing-plugins/rust-plugin.md index 82b87846b..15dd5f887 100644 --- a/docs/plugins/writing-plugins/rust-plugin.md +++ b/docs/plugins/writing-plugins/rust-plugin.md @@ -1,3 +1,156 @@ # Rust Plugins -Rust Plugins are not stable for now... \ No newline at end of file +A Rust Plugin is a `dynamic linked library` that built from Rust. And it is recommended way to write your plugins caust Rust plugins are much **faster and powerful** than Js Plugins. + +```rust +#![deny(clippy::all)] +use farmfe_core::{ + config::Config, + context::CompilationContext, + module::{ModuleId, ModuleType}, + plugin::{Plugin, PluginHookContext, PluginResolveHookParam, ResolveKind}, + relative_path::RelativePath, + serde_json::{self, Value}, +}; +use farmfe_macro_plugin::farm_plugin; +use farmfe_toolkit::{fs, regex::Regex}; +use sass_embedded::{ + FileImporter, OutputStyle, Sass, StringOptions, StringOptionsBuilder, Syntax, Url, +}; +use std::path::PathBuf; +use std::sync::Arc; +use std::{env, fmt::Debug}; +use std::{ + env::consts::{ARCH, OS}, + fmt::Formatter, +}; + +const PKG_NAME: &str = "@farmfe/plugin-sass"; + +#[farm_plugin] +pub struct FarmPluginSass { + options: String, +} + +impl FarmPluginSass { + pub fn new(_config: &Config, options: String) -> Self { + Self { options } + } +} + +impl Plugin for FarmPluginSass { + fn name(&self) -> &str { + "FarmPluginSass" + } + + // this plugin should be executed before internal plugins + fn priority(&self) -> i32 { + 101 + } + + fn load( + &self, + param: &farmfe_core::plugin::PluginLoadHookParam, + _context: &std::sync::Arc, + _hook_context: &farmfe_core::plugin::PluginHookContext, + ) -> farmfe_core::error::Result> { + if param.query.is_empty() && self.regex.is_match(param.resolved_path) { + let content = fs::read_file_utf8(param.resolved_path); + + if let Ok(content) = content { + return Ok(Some(farmfe_core::plugin::PluginLoadHookResult { + content, + module_type: ModuleType::Custom(String::from("sass")), + })); + } + } + + Ok(None) + } + + fn transform( + &self, + param: &farmfe_core::plugin::PluginTransformHookParam, + context: &std::sync::Arc, + ) -> farmfe_core::error::Result> { + if param.module_type == ModuleType::Custom(String::from("sass")) { + let exe_path: PathBuf = get_exe_path(context); + let mut sass = Sass::new(exe_path).unwrap_or_else(|e| { + panic!( + "\n sass-embedded init error: {},\n Please try to install manually. eg: \n pnpm install sass-embedded-{}-{} \n", + e.message(), + get_os(), + get_arch() + ) + }); + + let (mut string_options, additional_options) = self.get_sass_options( + ModuleId::from(param.module_id.as_str()).resolved_path_with_query(&context.config.root), + context.sourcemap_enabled(¶m.module_id.to_string()), + ); + + let cloned_context = context.clone(); + + let import_collection = Box::new(FileImporterCollection { + importer: param.module_id.clone().into(), + context: cloned_context, + }); + // TODO support source map for additionalData + let content = if let Some(additional_data) = additional_options.get("additionalData") { + format!("{}\n{}", additional_data, param.content) + } else { + param.content.clone() + }; + + string_options + .common + .importers + .push(sass_embedded::SassImporter::FileImporter(import_collection)); + string_options.url = Some(Url::from_file_path(param.resolved_path).unwrap()); + + let compile_result = sass.compile_string(&content, string_options).map_err(|e| { + farmfe_core::error::CompilationError::TransformError { + resolved_path: param.resolved_path.to_string(), + msg: e.message().to_string(), + } + })?; + + let paths = compile_result + .loaded_urls + .iter() + .map(|url| url.path()) + .filter(|p| p != ¶m.resolved_path) + .map(|p| ModuleId::new(p, "", &context.config.root)) + .collect(); + + context + .add_watch_files( + ModuleId::new(param.resolved_path, "", &context.config.root), + paths, + ) + .expect("cannot add file to watch graph"); + + return Ok(Some(farmfe_core::plugin::PluginTransformHookResult { + content: compile_result.css, + source_map: compile_result.source_map, + module_type: Some(farmfe_core::module::ModuleType::Css), + ignore_previous_source_map: false, + })); + } + Ok(None) + } +} + +``` + +## Create + +## Structure + +## Develop + +## Compile + +## Publish + +## Examples \ No newline at end of file