3 releases (breaking)
0.2.0 | Jul 7, 2024 |
---|---|
0.1.0 | Dec 11, 2023 |
0.0.1 | May 10, 2023 |
#610 in WebAssembly
78 downloads per month
Used in 5 crates
(via fervid_transform)
73KB
1.5K
SLoC
fervid
All-In-One Vue compiler written in Rust. Currently in alpha stage, the closest goal is to reach feature-parity with the current Vue SFC compiler.
Getting started
Instructions on how to use fervid
in Vue CLI and Vite are coming very soon!
Progress till MVP
A minimal target of this project includes (see Roadmap):
- Vue 3 code generation;
- unplugin integration;
- Farm native plugin;
- Dev/prod mode support;
<script setup>
support;- Example Vue project with configuration;
- Performance comparison.
Is it correct?
This project uses Vue SFC playground as its reference to compare the output. As of November 2023, fervid is capable of producing the DEV and PROD code almost identical to the official compiler, with some differences in:
- Context variables. This includes usages like
{{ foo + bar.buzz }}
or<div v-if="isShown">
. Support for them in fervid is almost complete. - [WIP] Patch flags. These are used to help Vue runtime when diffing the VNodes. If a VNode only has one prop which is dynamic, and all the other props and text are static, this needs to be conveyed to Vue for fast updates. Support for them is ongoing.
To check correctness of fervid, you can compare the playground output to the output of official compiler.
Please note that "correctness" of output will depend on the version of Vue, as Vue team may change the output and/or behaviour of the compiler. This is a challenge for fervid.
Is it fast?
Yes, it is incredibly fast. In fact, below is a benchmark run for a test component.
@vue/compiler-sfc:
954 ops/s, ±1.15% | slowest, 98.42% slower
@fervid/napi sync:
6 464 ops/s, ±0.08% | 89.29% slower
@fervid/napi async (4 threads):
11 624 ops/s, ±2.12% | 80.73% slower
@fervid/napi async CPUS (23 threads):
60 329 ops/s, ±0.67% | fastest
Note: results are for AMD Ryzen 9 7900X running on Fedora 38 with kernel version 6.5.9
Benchmarking in Node.js has been done using benny
, slightly modified to take libuv
threads into consideration.
Source code for a benchmark.
Better benchmarking is a TODO and has a lower priority compared to feature-completeness and usability in real-world scenarios, so Pull Requests are welcome.
Crates
fervid
The main crate. It exports a compile
method which glues all the stages together, from taking a source string to outputting compiled code and assets.
For finer-grained compilation you can use other crates directly.
fervid_core
The core structures and functionality shared across crates.
fervid_parser
Parser for Vue SFC based on swc_html_parser.
fervid_transform
This crate is responsible for AST transformation.
Handles <script>
and <script setup>
analysis and transformations, along with Typescript.
Based on SWC and provides fast and correct transforms without using regular expressions.
fervid_css
Works on the <style>
block and enables scoped
styles, CSS Modules and Vue-specific transformations. The backbone of this crate is swc_css_parser.
fervid_napi
NAPI-rs bindings for usage in Node.js.
fervid_deno
Deno bindings for usage in Deno.
fervid_plugin
and fervid_plugin_api
These crates allow authoring plugins for fervid
in Rust using dynamically loaded libraries (.so
, .dll
and .dylib
).
These plugins allow anyone to customize how a Vue SFC is parsed, optimized and code-generated.
Roadmap
Parser
- Template parsing
- W3 Spec compliance
Transformer
- Template scope construction
- Error reporting
- JS/TS imports analysis (powered by swc_ecma_parser)
-
setup
/data
/props
analysis - Processing
<style scoped>
-
<script setup>
support- Bindings collection;
- Return statement: inline vs render function;
- defineProps
- defineEmits
- defineExpose
- defineOptions
- defineSlots
- defineModel
- Tests
Code generator
-
Basic Vue3 code generation
- Elements
-
createElementVNode
- Attributes
- Static + Dynamic
-
style
merging -
class
merging
- Children
-
- Components
-
createVNode
- Slots
-
- Context-awareness (
_ctx
,$data
,$setup
) - Directives
- v-on
- v-bind
- v-if / v-else-if / v-else
- v-for
- v-show
- v-slot
- v-model
- v-cloak
- v-html
- v-memo
- v-once
- v-pre
- v-text
- Custom directives
- Built-in components
- keep-alive
- component
- transition
- transition-group
- teleport
- slot
- suspense
- Patch flags
- Hoisting
- Elements
-
DEV/PROD mode
-
Hot Module Replacement (HMR)
-
Vue 2.7 support
-
SSR with inline critical CSS support
-
Eager pre-compilation of Vue imports (avoid unneccessary bundler->compiler calls)
Integrations
- WASM binary (unpublished)
- NAPI binary @fervid/napi
- unplugin (in progress)
- Farm native plugin
- Turbopack plugin (when plugin system is defined)
lib.rs
:
Style transformer for Vue <style>
blocks
Example
use swc_core::common::{Span, BytePos};
let input = r#"
.example {
background: #ff0;
}
"#;
// Note: `Span` usually comes from the input, e.g. from `<style>` block
let span = Span::new(
BytePos(1),
BytePos(1 + input.len() as u32),
Default::default(),
);
let mut errors = Vec::new();
let result = fervid_css::transform_css(input, span, Some("data-v-abcd1234"), &mut errors, Default::default());
if let Some(transformed_css) = result {
assert_eq!(".example[data-v-abcd1234]{background:#ff0}", transformed_css);
}
Dependencies
~14MB
~291K SLoC