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"
trueVapor 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.
Like analyze_sfc/2 but raises Vize.Error on errors.
See Vize.CSS.bundle/2.
See Vize.CSS.bundle!/2.
See Vize.CSS.compile/2.
See Vize.CSS.compile!/2.
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.
Like compile_template/2 but raises on errors.
Compile a Vue template to Vapor mode JavaScript.
Like compile_vapor/2 but raises on errors.
Generate a TypeScript declaration file (.d.ts) from a Vue SFC.
Like generate_dts/2 but raises on errors.
Lint a Vue SFC source string.
See Vize.CSS.parse_ast/2.
Parse a Vue Single File Component into its constituent blocks.
Like parse_sfc/1 but raises on errors.
See Vize.CSS.print_ast/2.
Split a Vue template into static HTML and the dynamic slots between them,
the shape of %Phoenix.LiveView.Rendered{}.
Like split_template/2 but raises Vize.Error on errors.
Get the Vapor mode intermediate representation as Elixir maps.
Like vapor_ir/1 but raises on errors.
Types
@type css_result() :: Vize.CSS.css_result()
@type dts_result() :: %{dts: String.t()}
@type ir_result() :: %{ templates: [String.t()], components: [String.t()], directives: [String.t()], block: map(), element_template_map: [{non_neg_integer(), non_neg_integer()}] }
@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() }
@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()] }
@type vapor_result() :: Vize.Vapor.Result.t()
Functions
@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
@spec analyze_sfc!( String.t(), keyword() ) :: Vize.Croquis.t()
Like analyze_sfc/2 but raises Vize.Error on errors.
See Vize.CSS.bundle/2.
See Vize.CSS.bundle!/2.
See Vize.CSS.compile/2.
See Vize.CSS.compile!/2.
@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
[]
@spec compile_sfc!( String.t(), keyword() ) :: sfc_result()
Like compile_sfc/2 but raises on errors.
@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
@spec compile_ssr!(String.t()) :: ssr_result()
Like compile_ssr/1 but raises on errors.
@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
@spec compile_template!( String.t(), keyword() ) :: template_result()
Like compile_template/2 but raises on errors.
@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
@spec compile_vapor!( String.t(), keyword() ) :: vapor_result()
Like compile_vapor/2 but raises on errors.
@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
@spec generate_dts!( String.t(), keyword() ) :: dts_result()
Like generate_dts/2 but raises on errors.
@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
See Vize.CSS.parse_ast/2.
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
Like parse_sfc/1 but raises on errors.
See Vize.CSS.print_ast/2.
@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:kindand a:position,{line, column}in the template. Expressions are JavaScript source strings.:text— an escaped interpolation (:value):html— unescaped HTML fromv-html(:value):attr— one attribute, rendered whole with its leading space, so a renderer can leave it out, as Vue does fornulland a false boolean attribute. Has:name(or:name_valuefor:[name]),:value,:staticfor a static attribute of the same name such asclass="a"beside:class="b", and:showfor thev-showastylecombines with:spread— the attributes of an object, fromv-bind="attrs"(:value):model— what av-modelrenders on an<input>or<textarea>::value, the element's:tag, and its static:typeand:static_value:if—:branches, each a:condition(nil forv-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,:paramspattern such as{ item }, and:block:slot— a<slot>outlet::name,:props, and a:fallbackblock:root_attrs— withroot_attrs: true, see below
:bindings— events andv-models, left for the caller to render: each has a:kind(:onor: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, asVize.Diagnosticstructs
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_attrsslot, 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]
Like split_template/2 but raises Vize.Error on errors.
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
Like vapor_ir/1 but raises on errors.