Vize (Vize v0.17.0)

Copy Markdown View Source

Elixir bindings for the Vize Vue.js toolchain.

Compile, lint, and analyze Vue Single File Components at native speed via Rust NIFs. Includes Vapor mode IR for BEAM-native SSR.

iex> {:ok, result} = Vize.compile_sfc("""
...> <template><div>{{ msg }}</div></template>
...> <script setup>
...> const msg = 'hello'
...> </script>
...> """)
iex> result.code =~ "msg"
true

Vapor IR

The vapor_ir/1 function exposes Vue's Vapor mode intermediate representation as Elixir maps — enabling BEAM-native SSR without executing JavaScript:

iex> {:ok, ir} = Vize.vapor_ir("<div>{{ msg }}</div>")
iex> [template] = ir.templates
iex> template =~ "<div>"
true

Summary

Functions

Analyze a Vue Single File Component into a semantic Croquis summary.

Compile a Vue Single File Component to JavaScript + CSS.

Like compile_sfc/2 but raises on errors.

Compile a Vue template for server-side rendering.

Like compile_ssr/1 but raises on errors.

Compile a Vue template string to a render function.

Compile a Vue template to Vapor mode JavaScript.

Generate a TypeScript declaration file (.d.ts) from a Vue SFC.

Lint a Vue SFC source string.

Parse a Vue Single File Component into its constituent blocks.

Like parse_sfc/1 but raises on errors.

Split a Vue template into static HTML and the dynamic slots between them, the shape of %Phoenix.LiveView.Rendered{}.

Get the Vapor mode intermediate representation as Elixir maps.

Like vapor_ir/1 but raises on errors.

Types

css_result()

@type css_result() :: Vize.CSS.css_result()

diagnostic()

@type diagnostic() :: %{message: String.t(), name: String.t() | nil}

dts_result()

@type dts_result() :: %{dts: String.t()}

ir_result()

@type ir_result() :: %{
  templates: [String.t()],
  components: [String.t()],
  directives: [String.t()],
  block: map(),
  element_template_map: [{non_neg_integer(), non_neg_integer()}]
}

macro_artifact()

@type macro_artifact() :: %{
  :kind => String.t(),
  :name => String.t(),
  :source => String.t(),
  :content => String.t(),
  :start => non_neg_integer(),
  :end => non_neg_integer(),
  optional(:code) => String.t()
}

sfc_result()

@type sfc_result() :: %{
  code: String.t(),
  source_map: String.t() | nil,
  css: String.t() | nil,
  errors: [map()],
  warnings: [map()],
  template_hash: String.t() | nil,
  style_hash: String.t() | nil,
  script_hash: String.t() | nil,
  has_scoped: boolean(),
  styles: [map()],
  custom_blocks: [map()],
  macro_artifacts: [macro_artifact()]
}

ssr_result()

@type ssr_result() :: %{code: String.t(), preamble: String.t()}

template_result()

@type template_result() :: %{
  code: String.t(),
  preamble: String.t(),
  helpers: [String.t()]
}

vapor_result()

@type vapor_result() :: Vize.Vapor.Result.t()

Functions

analyze_sfc(source, opts \\ [])

@spec analyze_sfc(
  String.t(),
  keyword()
) :: {:ok, Vize.Croquis.t()} | {:error, Vize.Error.t()}

Analyze a Vue Single File Component into a semantic Croquis summary.

Options

  • :mode — analysis mode: :full, :lint, :compile, or :declaration

analyze_sfc!(source, opts \\ [])

@spec analyze_sfc!(
  String.t(),
  keyword()
) :: Vize.Croquis.t()

Like analyze_sfc/2 but raises Vize.Error on errors.

bundle_css(entry_path, opts \\ [])

This function is deprecated. Use Vize.CSS.bundle/2 instead.

See Vize.CSS.bundle/2.

bundle_css!(entry_path, opts \\ [])

This function is deprecated. Use Vize.CSS.bundle!/2 instead.

See Vize.CSS.bundle!/2.

compile_css(source, opts \\ [])

This function is deprecated. Use Vize.CSS.compile/2 instead.

See Vize.CSS.compile/2.

compile_css!(source, opts \\ [])

This function is deprecated. Use Vize.CSS.compile!/2 instead.

See Vize.CSS.compile!/2.

compile_sfc(source, opts \\ [])

@spec compile_sfc(
  String.t(),
  keyword()
) :: {:ok, sfc_result()} | {:error, String.t()}

Compile a Vue Single File Component to JavaScript + CSS.

Handles <template>, <script>, <script setup>, and <style> blocks.

Options

  • :vapor — compile in Vapor mode (default: false)
  • :ssr — compile for server-side rendering (default: false)
  • :filename — SFC filename for scope ID generation and source maps (e.g. "App.vue")
  • :scope_id — explicit scope ID for scoped CSS (default: auto-generated from filename)
  • :custom_renderer — treat lowercase non-HTML tags as renderer-native elements instead of Vue components (default: false)
  • :strip_types — strip TypeScript type annotations from the output using OXC, returning plain JavaScript (default: false)
  • :source_map — include a Source Map v3 JSON document for the emitted JavaScript when authored script lines can be mapped (default: false)

Examples

iex> {:ok, result} = Vize.compile_sfc("""
...> <template><button @click="count++">{{ count }}</button></template>
...> <script setup>
...> import { ref } from 'vue'
...> const count = ref(0)
...> </script>
...> """)
iex> result.code =~ "count"
true
iex> result.errors
[]

compile_sfc!(source, opts \\ [])

@spec compile_sfc!(
  String.t(),
  keyword()
) :: sfc_result()

Like compile_sfc/2 but raises on errors.

compile_ssr(source)

@spec compile_ssr(String.t()) :: {:ok, ssr_result()} | {:error, [String.t()]}

Compile a Vue template for server-side rendering.

Generates JavaScript with _push() calls that produce HTML strings. The output is meant to be executed in a JS runtime (e.g. QuickBEAM).

Examples

iex> {:ok, result} = Vize.compile_ssr("<div>{{ msg }}</div>")
iex> result.code =~ "_push"
true

compile_ssr!(source)

@spec compile_ssr!(String.t()) :: ssr_result()

Like compile_ssr/1 but raises on errors.

compile_template(source, opts \\ [])

@spec compile_template(
  String.t(),
  keyword()
) :: {:ok, template_result()} | {:error, [String.t()]}

Compile a Vue template string to a render function.

This compiles just the template (not a full SFC). Useful for on-the-fly template compilation.

Options

  • :mode — output mode, "function" (default) or "module"
  • :ssr — compile for SSR (default: false)

Examples

iex> {:ok, result} = Vize.compile_template("<div>{{ msg }}</div>")
iex> result.code =~ "msg"
true

compile_template!(source, opts \\ [])

@spec compile_template!(
  String.t(),
  keyword()
) :: template_result()

Like compile_template/2 but raises on errors.

compile_vapor(source, opts \\ [])

@spec compile_vapor(
  String.t(),
  keyword()
) :: {:ok, vapor_result()} | {:error, Vize.Error.t()}

Compile a Vue template to Vapor mode JavaScript.

Vapor mode generates fine-grained reactive code that manipulates the DOM directly, without a virtual DOM.

Options

  • :ssr — compile for SSR (default: false)
  • :diagnostics — also report the parser's diagnostics, such as duplicate attributes, in the result's :diagnostics (default: false)
  • :template_syntax — :standard (default) or :quirks

Examples

iex> {:ok, result} = Vize.compile_vapor("<div>{{ msg }}</div>")
iex> result.code =~ "template"
true
iex> length(result.templates) > 0
true

compile_vapor!(source, opts \\ [])

@spec compile_vapor!(
  String.t(),
  keyword()
) :: vapor_result()

Like compile_vapor/2 but raises on errors.

generate_dts(source, opts \\ [])

@spec generate_dts(
  String.t(),
  keyword()
) :: {:ok, dts_result()} | {:error, String.t()}

Generate a TypeScript declaration file (.d.ts) from a Vue SFC.

Analyzes the SFC's script blocks and produces a lightweight type surface for component consumers — including prop types, emit signatures, exposed bindings, and slot definitions.

Options

  • :filename — SFC filename for diagnostics (default: "component.vue")

Examples

iex> {:ok, result} = Vize.generate_dts("<script setup>const msg = 1</script>")
iex> is_binary(result.dts)
true

generate_dts!(source, opts \\ [])

@spec generate_dts!(
  String.t(),
  keyword()
) :: dts_result()

Like generate_dts/2 but raises on errors.

lint(source, filename \\ "component.vue")

@spec lint(String.t(), String.t()) :: {:ok, [diagnostic()]}

Lint a Vue SFC source string.

Returns a list of diagnostics with :message and optionally :name (the rule name).

Examples

iex> {:ok, diagnostics} = Vize.lint("<template><img></template>", "test.vue")
iex> is_list(diagnostics)
true

parse_css_ast(source, opts \\ [])

This function is deprecated. Use Vize.CSS.parse_ast/2 instead.

See Vize.CSS.parse_ast/2.

parse_css_ast!(source, opts \\ [])

This function is deprecated. Use Vize.CSS.parse_ast!/2 instead.

See Vize.CSS.parse_ast!/2.

parse_sfc(source)

@spec parse_sfc(String.t()) :: {:ok, map()} | {:error, String.t()}

Parse a Vue Single File Component into its constituent blocks.

Returns the SFC descriptor with template, script, script_setup, styles, and custom_blocks — without compiling.

Examples

iex> {:ok, descriptor} = Vize.parse_sfc("""
...> <template><div>hello</div></template>
...> <script setup>const x = 1</script>
...> <style scoped>.red { color: red }</style>
...> """)
iex> descriptor.template.content =~ "hello"
true
iex> descriptor.script_setup.setup
true
iex> hd(descriptor.styles).scoped
true

parse_sfc!(source)

@spec parse_sfc!(String.t()) :: map()

Like parse_sfc/1 but raises on errors.

split_template(source, opts \\ [])

@spec split_template(
  String.t(),
  keyword()
) :: {:ok, map()} | {:error, Vize.Error.t()}

Split a Vue template into static HTML and the dynamic slots between them, the shape of %Phoenix.LiveView.Rendered{}.

The template is lowered to Vize's L2 semantic IR, which its SSR compiler also uses, and printed: elements, static attributes, and text become HTML, and everything that depends on data becomes a slot. Returns {:ok, split}:

  • :statics — static HTML strings, one more than there are slots
  • :slots — slots in document order. Each has a :kind and a :position, {line, column} in the template. Expressions are JavaScript source strings.
    • :text — an escaped interpolation (:value)
    • :html — unescaped HTML from v-html (:value)
    • :attr — one attribute, rendered whole with its leading space, so a renderer can leave it out, as Vue does for null and a false boolean attribute. Has :name (or :name_value for :[name]), :value, :static for a static attribute of the same name such as class="a" beside :class="b", and :show for the v-show a style combines with
    • :spread — the attributes of an object, from v-bind="attrs" (:value)
    • :model — what a v-model renders on an <input> or <textarea>: :value, the element's :tag, and its static :type and :static_value
    • :if — :branches, each a :condition (nil for v-else) and a :block
    • :for — :source, :value, :key, :index, the repeated element's :key_prop, and its :block
    • :component — :name, :props, :events, and :slots: the content passed to each of its slots, with its :name, :params pattern such as { item }, and :block
    • :slot — a <slot> outlet: :name, :props, and a :fallback block
    • :root_attrs — with root_attrs: true, see below
  • :bindings — events and v-models, left for the caller to render: each has a :kind (:on or :model), :name, :modifiers, :value, and :at, a {static_index, offset} pair where the element's start tag ends, so attributes can be inserted there
  • :diagnostics — warnings, as Vize.Diagnostic structs

A block, such as a v-if branch, has its own :statics, :slots, and :bindings. A prop or attribute in :props has :name (or :name_value), and :static or :value; one with neither name is a v-bind object.

Returns {:error, %Vize.Error{}} when the template has errors, such as an expression that doesn't parse.

Options

  • :root_attrs — for a component's template: when it has a single root element, return all of that element's attributes, static ones included, as one :root_attrs slot, so a caller can merge the fallthrough attributes a parent passes (default: false)

Examples

iex> {:ok, split} = Vize.split_template(~s(<p :class="kind">Hi {{ name }}</p>))
iex> split.statics
["<p", ">Hi ", "</p>"]
iex> Enum.map(split.slots, & &1.kind)
[:attr, :text]

split_template!(source, opts \\ [])

@spec split_template!(
  String.t(),
  keyword()
) :: map()

Like split_template/2 but raises Vize.Error on errors.

vapor_ir(source)

@spec vapor_ir(String.t()) :: {:ok, ir_result()} | {:error, [String.t()]}

Get the Vapor mode intermediate representation as Elixir maps.

This is the key function for BEAM-native SSR. Instead of generating JavaScript, it returns the structured IR that describes how to render the template — enabling a pure Elixir renderer.

The IR contains:

  • :templates — static HTML template strings
  • :components — component names used in the template
  • :directives — directive names used in the template
  • :block — the root block with operations, effects, and returns
  • :element_template_map — list of {element_id, template_index} tuples

Expressions are either plain strings (dynamic) or {:static, value} tuples (compile-time constants).

Each operation has a :kind field indicating its type:

  • :set_prop — set an attribute/property on an element
  • :set_text — set text content (interpolation)
  • :set_event — bind an event handler
  • :set_html — set innerHTML (v-html)
  • :if_node — v-if/v-else-if/v-else chain
  • :for_node — v-for loop
  • :create_component — child component
  • :child_ref / :next_ref — DOM traversal helpers

Examples

iex> {:ok, ir} = Vize.vapor_ir("<div :class=\"cls\">{{ msg }}</div>")
iex> [_template] = ir.templates
iex> ir.block.effects |> List.flatten() |> Enum.any?(&match?(%{kind: :set_text}, &1))
true

vapor_ir!(source)

@spec vapor_ir!(String.t()) :: ir_result()

Like vapor_ir/1 but raises on errors.