Giter Club home page Giter Club logo

fervid's Introduction

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 84%

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 wip

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 alpha

The core structures and functionality shared across crates.

fervid_parser alpha

Parser for Vue SFC based on swc_html_parser.

fervid_transform alpha

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 alpha

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 alpha

NAPI-rs bindings for usage in Node.js.

fervid_deno future

Deno bindings for usage in Deno.

fervid_plugin and fervid_plugin_api future

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
  • 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

fervid's People

Contributors

cijiugechu avatar dependabot[bot] avatar erkelost avatar phoenix-ru avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

fervid's Issues

Support auto-imports (components and symbols)

To avoid extra overhead of using unimport in js side, most of the component and directive resolutions can happen in the Rust side.

  • Research how unimport works on source code;
  • Research how unimport gathers the auto-import symbols (across source code and dependencies);
  • Research existing Node resolution libraries (import 'x' -> node_modules/path/to/x/index.js) in Rust;
  • Ensure we can support Lazy prefixed imports;
  • ... define other steps after research.

Multi-target code generation

The possible compilation targets are (excluding DEV/PROD differences):

  • CSR;
  • SSR;
  • Vapor mode CSR;
  • TS library;
  • Possibly .d.ts generation;

The compiler needs to be able to efficiently support all the targets with some common layer and target-specific implementations.

Playground Preview

The project is wonderful.

In other to test and check it more conveniently, I'd like to request a playground, like this one.

Dedupe imports between `<script>` and `<script setup>`

Infer `ref` and `computed` TypeScript types for smarter inlining

Situation

When using <script setup lang="ts"> we can make assumptions regarding binding types. For instance, we can confidently infer the types of bindings in this example:

<script setup lang="ts">
import { ref, computed } from 'vue'

const foo = ref('Hello')
const bar = ref(1)
const baz = computed<number>(() => bar.value * 2)
</script>

Proposal

fervid can trust the user's TypeScript setup to catch type errors. In the future, when stc is mature enough, it will be used for type inference and checking.

Knowing the binding TS type, we can further optimize the generation of Interpolations and SSR attributes:
const msg = ref('') // string

What Mode Current generation Proposal generation
{{ msg }} CSR _toDisplayString(msg.value) msg.value
{{ msg }} SSR _ssrInterpolate(msg.value) msg.value
:value="msg" SSR _ssrRenderAttr("value", msg.value) `value="${msg.value}"`

By having the knowledge of types we can omit unnecessary runtime checks and also ship less code.

Possible implementation

The transformer already detects Vue-specific symbols, such as ref and computed. We can extend the analysis to also visit the value (second priority) or the type annotations (first priority) and store this information along with the BindingTypes.

Considering the fact that TS types are complex and inference may not be trivial, the TS type must be an optional hint for the compiler.
When no such type can be inferred (or when outside TS), the compiler should fall back to default code generation.

Provide LSP

Features I personally find very desirable:

  • auto-completion of tag names (regular html and using auto-imports from #24);
  • auto-completion of component attributes (VBind and VOn);
  • parse error reporting (HTML and JS/TS);
  • ...

Self-closing `/>` is invalid syntax on non-void HTML elements

Problem

The official Vue parser allows self-closing any HTML, but this is not valid by the spec. For example, this:

<template>
  <slot />
  <div class="bad" />
</template>

Using Nu HTML Checker by W3 results in a clear error:
image

The same happens when parsing with swc_html_parser. The error is being reported and the tag is not being closed:

InvalidHtml(NonVoidHtmlElementStartTagWithTrailingSolidus) <slot />

In addition, this also messes up the DOM Tree stack, which is the actual problem here.

Possible solution

All NonVoidHtmlElementStartTagWithTrailingSolidus should be considered a hard error.

Nice-to-have

It would also be nice to do RegEx search-replace as a utility in fervid.
Another option is to parse the HTML and only apply this fix to where the NonVoidHtmlElementStartTagWithTrailingSolidus problem is encountered.

Auto-imports for known `vue` symbols

Writing SFCs using the default JS compiler and https://github.com/unplugin/unplugin-auto-import produces not-so-optimal code.

Take this for example (playground):

<script setup>
const msg = ref('Hello World!')
</script>

<template>
  <h1>{{ msg }}</h1>
  <input v-model="msg" />
</template>

Correct binding type of msg cannot be properly inferred, which leads to compiler generating unref(msg), which in turn has runtime cost.
In addition to that, extra build step is needed to properly auto-import the ref.

A better approach would be to add a ref/computed/etc. vue-specific imports whenever their usage is detected. It is much cheaper and more beneficial to do so in the SFC compiler than in any other tool.

Steps:

  • Detect stray known symbols usage. This can happen during regular transform pass;
  • Inject non-prefixed imports (e.g. import { ref } from 'vue' instead of ref as _ref);
  • Respect user-defined imports (e.g. import { ref } from './custom-path' should not auto-import).

CI tests for ARM architecture

At the moment of writing, GitHub CI has no ARM-based hosted runners for public repositories.

As a follow-up from #12, we should add tests for ARM builds using QEMU.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.