Skip to content

Compilation Pipeline

Overview

Nexa's SFC compiler transforms .nexa files into plain JavaScript through a three-stage pipeline:

.nexa file

parse()    → { template, script, style }

transform() → { templateAST, transformedAST, scopedCSS }

codegen()  → JavaScript + CSS

Stage 1: Parse

The SFC parser extracts <template>, <script>, and <style> sections using regex-based section detection. The template is further parsed into an AST of elements, text nodes, expressions, slots, and directives.

Stage 2: Transform

The template AST is transformed to prepare it for code generation:

  • v-if and v-show directives are extracted
  • v-for expressions are parsed into item/index/list
  • Scoped style selectors are prefixed with a unique data-v-xxx attribute
  • Dynamic attributes (:attr) and event bindings (@event) are normalized

Stage 3: Codegen

The transformed AST is emitted as JavaScript render functions. A component like:

html
<template>
  <div class="counter">
    <p>Count: {{ count.value }}</p>
    <button @click="increment">+1</button>
  </div>
</template>

Compiles to:

js
export default defineComponent({
  setup(props, { emit, slots }) {
    return { count, increment }
  },
  render(ctx) {
    const { count, increment } = ctx
    return h('div', { class: 'counter' }, [
      h('p', null, ['Count: ', count.value]),
      h('button', { onClick: increment }, ['+1']),
    ])
  },
})

Vite Plugin & HMR

The vite-plugin-nexa integrates the compiler into Vite's dev server and build pipeline. It handles:

  1. Compilation: Transforming .nexa files during the dev server's request phase.
  2. HMR Bridge: Injects a lightweight HMR client into components.
  3. Hot Updates: Using the handleHotUpdate hook, it identifies changes and triggers surgical updates.

How HMR Works in Nexa

When a .nexa file is updated:

  1. Vite notifies the browser that the module has changed.
  2. The browser downloads the new version of the component.
  3. The injected HMR code calls reloadComponent(hmrId, newDefinition).
  4. The Nexa Runtime finds all active instances of that component and updates their render function.
  5. A re-patching is triggered without re-running setup(), preserving the component's state (Signals).

Released under the MIT License.