Code Monkey home page Code Monkey logo

vue-compiler's Introduction

Vue Compiler in Rust

WebAssembly ferris Vue

Try it out in the wasm playground!

CI Playground codecov

Evan says:

Maybe in the long run we want the whole transform (and even the Vue compiler!) to be implemented in native Go/Rust so performance would no longer be a concern ;)

Future is now!

Project Docs

Intended Usage

  • Rust library
  • CLI binary
  • napi based nodejs library
  • wasm based npm package: a fallback if napi fails to work and a toy for browser.
  • No Browser build No support since most features in full build are additional except for browser based expression checking or HTML escaping. Browser build removed them for size. But template compiler in browser is already for toy project. For browser specific summary see this google sheet.

Reference

  • vuejs/core: ご本家様
  • html spec is the definitive guide for parsing HTML-like files.
  • Vue Template Explorer gives instant results for code generation and error reporting.
  • Nu html checker is the official html validator from W3C. This is the canonical error reporter for html parsing, when there is a discrepancy between the framework and the spec.
  • AST explorer can inspect AST nodes interactively.

vue-compiler's People

Contributors

herringtondarkholme avatar iwanabethatguy avatar jerrywu1234 avatar renovate-bot avatar renovate[bot] avatar ubugeeei avatar zhmushan 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  avatar  avatar  avatar

vue-compiler's Issues

Rayon parallelization?

The experimentation shows that rayon has at least 100us overhead for thread pool initialization.
However, most template can be compiled within 100us. The parallelization, at least in practice, does not pay off.

The example is the most complicated SFC in element-plus, el-table.vue. The compilation takes about 100us without thread pool.

But after the thread pool is introduced the compilation time comes to 200us+.

Separate parser as a dedicated crate

Currently Vue SFC parser is included in the "vue-compiler-core" crate. Would you like you separate and publish the parser as a crate? I hope it can only parser <template> section, while other sections like <script> and <style> are kept as source text, leaving them to user to decide how to process them.

Should RE used in the crate?

Hard to migrate but possible

  • compiler-core/src/transforms/vFor.ts|304 col 15| const forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/
  • compiler-core/src/transforms/vFor.ts|307 col 18| const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/
  • compiler-core/src/transforms/vOn.ts|19 col 12| const fnExpRE = /^\s*([\w$_]+|\([^)]*?\))\s*=>|^\s*function(?:\s+[\w$]+)?\s*\(/
  • compiler-core/src/utils.ts|79 col 17| const whitespaceRE = /\s+[.[]\s*|\s*[.[]\s+/g
  • shared/src/normalizeProp.ts|30 col 20| const listDelimiterRE = /;(?![^(]*\))/g // ; followed by no single )

Easy to migrate

compiler-core/src/parse.ts|60 col 13| const decodeRE = /&(gt|lt|amp|apos|quot);/g
compiler-core/src/transforms/vFor.ts|308 col 18| const stripParensRE = /^\(|\)$/g
compiler-core/src/utils.ts|66 col 20| const nonIdentifierRE = /^\d|[^\$\w]/
compiler-core/src/utils.ts|77 col 26| const validFirstIdentCharRE = /[A-Za-z_$\xA0-\uFFFF]/
compiler-core/src/utils.ts|78 col 21| const validIdentCharRE = /[\.\?\w$\xA0-\uFFFF]/
shared/src/normalizeProp.ts|31 col 24| const propertyDelimiterRE = /:(.+)/
shared/src/escapeHtml.ts|1 col 13| const escapeRE = /["'&<>]/
compiler-dom/src/transforms/stringifyStatic.ts|142 col 15| const dataAriaRE = /^(data|aria)-/

use RE in SFC crates

compiler-sfc/src/parse.ts|333 col 12| const splitRE = /\r?\n/g
compiler-sfc/src/parse.ts|334 col 12| const emptyRE = /^(?:\/\/)?\s*$/
compiler-sfc/src/parse.ts|335 col 14| const replaceRE = /./g
compiler-sfc/src/rewriteDefault.ts|4 col 20| const defaultExportRE = /((?:^|\n|;)\s*)export(\s*)default/
compiler-sfc/src/rewriteDefault.ts|5 col 25| const namedDefaultExportRE = /((?:^|\n|;)\s*)export(.+)as(\s*)default/s
compiler-sfc/src/rewriteDefault.ts|6 col 25| const exportDefaultClassRE =
compiler-sfc/src/stylePluginScoped.ts|5 col 20| const animationNameRE = /^(-\w+-)?animation-name$/
compiler-sfc/src/stylePluginScoped.ts|6 col 16| const animationRE = /^(-\w+-)?animation$/
compiler-sfc/src/cssVars.ts|15 col 20| export const cssVarRE = /\bv-bind\(\s*(?:'([^']+)'|"([^"]+)"|([^'"][^)]*))\s*\)/g
ref-transform/src/refTransform.ts|28 col 21| const transformCheckRE = /[^\w]\$(?:\$|ref|computed|shallowRef)?\s*(\(|\<)/

_resolveComponent should include quotes

<template>
<my-component/>
<template>

in playground :

const _component_my_component = _resolveComponent(my-component)

should be :

const _component_my_component = _resolveComponent("my-component")

run playground/"npm run build" throw an error

documemts

I follow the playground/README.md, use 'wasm-pack build' to build wasm,and then run "npm run build" in playground directory.

it throw an error

error

Then I use "wasm-build build --target web" to build wasm, run "npm run build" again find it's ok

success

run cargo install will be an error

warning: profiles for the non root package will be ignored, specify profiles at the workspace root:
package: /Users/wuls/Desktop/rust/vue-compiler/crates/wasm/Cargo.toml
workspace: /Users/wuls/Desktop/rust/vue-compiler/Cargo.toml
warning: profiles for the non root package will be ignored, specify profiles at the workspace root:
package: /Users/wuls/Desktop/rust/vue-compiler/napi/Cargo.toml
workspace: /Users/wuls/Desktop/rust/vue-compiler/Cargo.toml
error: found a virtual manifest at /Users/wuls/Desktop/rust/vue-compiler/Cargo.toml instead of a package manifest

I follow this doc,
it will be an error

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Rate-Limited

These updates are currently rate-limited. Click on a checkbox below to force their creation now.

  • chore(deps): update dependency @types/node to v20.11.24
  • chore(deps): update dependency @vitejs/plugin-vue to v5.0.4
  • chore(deps): update dependency prettier to v3.2.5
  • fix(deps): update dependency @types/benchmark to v2.1.5
  • fix(deps): update rust crate anyhow to 1.0.80
  • fix(deps): update rust crate serde_yaml to 0.9.32
  • fix(deps): update rust crate tree-sitter-typescript to 0.20.5
  • fix(deps): update rust crate wasm-bindgen to 0.2.92
  • chore(deps): update dependency @babel/types to v7.24.0
  • chore(deps): update dependency eslint to v8.57.0
  • chore(deps): update dependency eslint-plugin-sonarjs to v0.24.0
  • chore(deps): update dependency vite to v5.1.5
  • chore(deps): update rust crate insta to 1.36.1
  • fix(deps): update dependency glob to v10.3.10
  • fix(deps): update rust crate clap to 4.5.1
  • chore(deps): update codecov/codecov-action action to v4
  • chore(deps): update dependency vue-tsc to v2
  • chore(deps): update pnpm/action-setup action to v3
  • chore(deps): update typescript-eslint monorepo to v7 (major) (@typescript-eslint/eslint-plugin, @typescript-eslint/parser)
  • 🔐 Create all rate-limited PRs at once 🔐

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

cargo
benches/Cargo.toml
  • criterion 0.5
  • glob 0.3.1
crates/cli/Cargo.toml
  • anyhow 1.0.79
  • clap 4.4.18
  • path-clean 1.0.1
  • codespan-reporting 0.11.1
  • serde_yaml 0.9.30
crates/compiler/Cargo.toml
  • smallvec 1.12.0
  • bitflags 2.4.2
  • rustc-hash 1.1.0
  • serde 1.0
  • rslint_parser 0.3.1
  • phf 0.11
  • lazy_static 1.4.0
  • insta 1.34.0
crates/dom/Cargo.toml
  • phf 0.11
crates/sfc/Cargo.toml
  • smallvec 1.12.0
  • rustc-hash 1.1.0
  • ast-grep-core 0.5.3
  • tree-sitter-typescript 0.20.3
  • lazy_static 1.4.0
crates/ssr/Cargo.toml
crates/wasm/Cargo.toml
  • wasm-bindgen 0.2.90
  • wee_alloc 0.4.5
napi/Cargo.toml
  • napi 2.14.2
  • napi-derive 2.14.6
  • napi-build 2
  • mimalloc 0.1
github-actions
.github/workflows/baseline.yml
  • actions/checkout v4
  • actions/setup-node v4
  • actions/cache v3
  • pnpm/action-setup v2.4.0
  • benchmark-action/github-action-benchmark v1
.github/workflows/benchmark.yml
  • actions/checkout v4
  • actions-rs/toolchain v1
  • actions/cache v3
.github/workflows/ci.yml
  • actions/checkout v4
  • actions-rs/toolchain v1
  • actions/cache v3
.github/workflows/coverage.yml
  • actions/checkout v4
  • codecov/codecov-action v3
.github/workflows/gh-pages.yml
  • actions/checkout v4
  • actions-rs/toolchain v1
  • jetli/wasm-pack-action v0.4.0
  • actions/cache v3
  • actions/setup-node v4
  • pnpm/action-setup v2.4.0
  • peaceiris/actions-gh-pages v3
npm
benches/package.json
  • @types/benchmark ^2.1.1
  • @types/glob ^8.0.0
  • @vue/compiler-core ^3.2.19
  • benchmark ^2.1.4
  • glob ^10.0.0
  • microtime ^3.0.0
  • ts-node 10.9.2
  • typescript 5.3.3
napi/npm/android-arm64/package.json
  • node >= 10
napi/npm/darwin-arm64/package.json
  • node >= 10
napi/npm/darwin-x64/package.json
  • node >= 10
napi/npm/freebsd-x64/package.json
  • node >= 10
napi/npm/linux-arm-gnueabihf/package.json
  • node >= 10
napi/npm/linux-arm64-gnu/package.json
  • node >= 10
napi/npm/linux-arm64-musl/package.json
  • node >= 10
napi/npm/linux-x64-gnu/package.json
  • node >= 10
napi/npm/linux-x64-musl/package.json
  • node >= 10
napi/npm/win32-arm64-msvc/package.json
  • node >= 10
napi/npm/win32-ia32-msvc/package.json
  • node >= 10
napi/npm/win32-x64-msvc/package.json
  • node >= 10
napi/package.json
  • @node-rs/helper ^1.2.1
  • @napi-rs/cli 2.17.0
  • @types/node 20.11.8
  • ts-node 10.9.2
  • @vue/compiler-core 3.4.13
  • @vue/compiler-sfc 3.4.13
  • @typescript-eslint/eslint-plugin 6.18.1
  • @typescript-eslint/parser 6.18.1
  • ava 6.0.1
  • benny 3.7.1
  • chalk 5.3.0
  • eslint 8.56.0
  • eslint-config-prettier 9.1.0
  • eslint-plugin-import 2.29.1
  • eslint-plugin-prettier 5.1.3
  • eslint-plugin-sonarjs 0.23.0
  • npm-run-all 4.1.5
  • prettier 3.2.4
  • typescript 5.3.3
  • node >= 10
playground/package.json
  • vue 3.4.13
  • @babel/types 7.23.9
  • @vitejs/plugin-vue 5.0.3
  • typescript 5.3.3
  • vite 5.0.12
  • vue-tsc 1.8.27

  • Check this box to trigger a request for Renovate to run again on this repository

Wrong output when script contains TS generics

For the example below with TS generics:

<script setup lang="ts">
import { shallowRef } from 'vue'
import { NCard } from 'naive-ui'

const root = shallowRef<InstanceType<typeof NCard>>()
</script>

It compiles:

const _Vue = Vue
const {
  createVNode: _createVNode, createElementVNode: _createElementVNode, createTextVNode: _createTextVNode, 
} = Vue
const _hoisted_0 = {
  setup: "",
  lang: "ts",
}

return function render(_ctx, _cache) {
  with (_ctx) {
    const {
      createVNode: _createVNode, createElementVNode: _createElementVNode, createTextVNode: _createTextVNode, resolveComponent: _resolveComponent, withCtx: _withCtx, 
    } = _Vue
    
    const _component_InstanceType60typeof = _resolveComponent(InstanceType [
            _createTextVNode(">()\n")
          ]),
          _: 1 /*Stable*/,
        }, 
      ]), 
    ])
  }
}

which looks wrong.

Parse range error

vue SFC file

<template v-if>
  <div v-for="item in result">test {{item}}</div>
</template>
Root 0..78
  Element 0..77
    tag_name `template`
    directive 10..14
      name `if`
    Element 18..65
      tag_name `div`
      directive 23..45
        name `for`
        value 29..45 `item in result`
      Text 51..59 `test `
      Interpolation 51..59 `item`

here text test byte offset is 51..59, which is wrong,
the correct offset should be 46..51
image

can it remove the nightly features ?

hi there,
currently I am trying the file parsing part by directly importing the crate vue-compiler-core.
Is it possible to remove once_cell feature? or any advice for the replacement of once_cell?

sorry for my dumb asking, but I think it is not a good idea to build with the nightly feature

SWC or Rslint ?

TLDR: Rslitn is still better than swc.

The code changes are in swc branch and rslint branch.

swc contains a lot of dependencies regardless if they are relevant to core parsing. Such bloated dependencies place huge burden to compiling, slowing rust-analyzer to almost freezing.
swc's docs and examples re scarce. The only working example is https://rustdoc.swc.rs/swc_ecma_parser/.
Looking to the code is also hard. The abstraction and module organization is, well, hazy at least to the uneducated. Peeking the definition is hard, if possible, given the massive usage of macros. Alas, the macro is also the perpetrator of the sluggish compilation. :/
Using swc is not a nice journey, actually. Looking at the example above, it immediately requires several crates other than the parse. common, ast, atom, visit and blahblah. And the core impl Visitor has 200+ macro generated methods to implement without one single line of documentation. The usability is poor... And the output is large, merely importing swc pushes the binary size to 33MB.

Rslint at least has more comments and documentation than swc. It's underlying crate, rowan, also has docs. So it might be a better choice. Rslint's dependencies are also more lightweight. Rslint's source code is also simple and clear, compared to swc.
Understanding Green/Red tree does require some learning. But it is fine.
The binary size is 10MB after importing Rslint, one third of swc.

vue-compiler-core problems

Why does the output ast structure have no child nodes when I parse the sfc with vue-compiler-core

use vue_compiler_core::{
    error::ErrorHandler,
    parser::{ParseOption, Parser},
    scanner::{ScanOption, Scanner, TextMode, TokenSource},
};

pub use vue_compiler_core::parser::AstRoot;
pub struct NoopErrorHandler;
impl ErrorHandler for NoopErrorHandler {}

fn scan_with_opt(s: &str, opt: ScanOption) -> impl TokenSource {
    let scanner = Scanner::new(opt);
    let ctx = NoopErrorHandler;
    scanner.scan(s, ctx)
}

pub fn base_scan(s: &str) -> impl TokenSource {
    scan_with_opt(s, ScanOption::default())
}

pub fn base_parse(s: &str) -> AstRoot {
    let tokens = base_scan(s);
    let parser = Parser::new(ParseOption {
        ..ParseOption::default()
    });
    let eh = NoopErrorHandler;
    parser.parse(tokens, eh)
}

will parse code

<script setup>
useHead({
  title: 'Nuxt Turbo App',
  link: [
    {
      rel: 'icon', type: 'image/png', href: '/images/nuxt.png',
    },
  ],
})
</script>

<template>
  <NuxtLayout>
    <NuxtPage></NuxtPage>
  </NuxtLayout>
</template>

<style>
html, body , #__nuxt{
  height: 100vh;
  margin: 0;
  padding: 0;
}

html.dark {
  background: #222;
  color: white;
}
</style>

parse result ast

image

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.