Vize (Vize v0.10.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

Bundle a CSS file and all its @import dependencies into a single stylesheet.

Compile CSS using LightningCSS.

Like compile_css/2 but raises on errors.

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.

Get the Vapor mode intermediate representation as Elixir maps.

Like vapor_ir/1 but raises on errors.

Compile a Vue template into a statics/slots split ready for LiveView %Rendered{}.

Types

css_result()

@type css_result() :: %{
  optional(:exports) => %{optional(String.t()) => String.t()} | nil,
  code: String.t(),
  css_vars: [String.t()],
  errors: [String.t()],
  warnings: [String.t()]
}

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(),
  css: String.t() | nil,
  errors: [map()],
  warnings: [map()],
  template_hash: String.t() | nil,
  style_hash: String.t() | nil,
  script_hash: String.t() | nil,
  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() :: %{code: String.t(), templates: [String.t()]}

Functions

bundle_css(entry_path, opts \\ [])

@spec bundle_css(
  String.t(),
  keyword()
) :: {:ok, css_result()}

Bundle a CSS file and all its @import dependencies into a single stylesheet.

Reads the entry file and all imported files from disk, resolving @import rules recursively. The result is a single merged stylesheet with all imports inlined, wrapped in the appropriate @media, @supports, and @layer rules.

Options

  • :minify — minify the output (default: false)
  • :css_modules — enable CSS Modules scoping (default: false)
  • :targets — browser targets for autoprefixing

Examples

{:ok, result} = Vize.bundle_css("assets/css/app.css")
result.code  #=> merged CSS with all @imports inlined

bundle_css!(entry_path, opts \\ [])

@spec bundle_css!(
  String.t(),
  keyword()
) :: css_result()

Like bundle_css/2 but raises on errors.

compile_css(source, opts \\ [])

@spec compile_css(
  String.t(),
  keyword()
) :: {:ok, css_result()}

Compile CSS using LightningCSS.

Parses, autoprefixes, and optionally minifies CSS. Also handles Vue scoped CSS transformation, v-bind() extraction, and CSS Modules.

Options

  • :minify — minify the output (default: false)
  • :scoped — apply Vue scoped CSS transformation (default: false)
  • :scope_id — scope ID for scoped CSS (e.g. "data-v-abc123")
  • :filename — filename for error reporting
  • :css_modules — enable CSS Modules scoping (default: false). When enabled, class names, IDs, keyframes, and other identifiers are scoped, and the result includes an :exports map of original → hashed names.
  • :targets — browser targets for autoprefixing, map with optional :chrome, :firefox, :safari keys as major version integers

Examples

iex> {:ok, result} = Vize.compile_css(".foo { color: red }")
iex> result.code =~ "color"
true
iex> result.errors
[]

iex> {:ok, result} = Vize.compile_css(".btn { color: red }", css_modules: true, filename: "btn.module.css")
iex> is_map(result.exports)
true

compile_css!(source, opts \\ [])

@spec compile_css!(
  String.t(),
  keyword()
) :: css_result()

Like compile_css/2 but raises on errors.

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)

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, [String.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)

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_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.

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.

vapor_split(source)

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

Compile a Vue template into a statics/slots split ready for LiveView %Rendered{}.

Returns {:ok, split} where split has:

  • "statics" — list of static HTML strings (interleaved between dynamic slots)
  • "slots" — ordered list of slot descriptors, each with :kind and values/sub-IR
  • :templates — raw template strings (for sub-block rendering)
  • :element_template_map — element ID → template index mapping

The statics + slots can be directly assembled into a %Phoenix.LiveView.Rendered{} struct by evaluating each slot against assigns.

vapor_split!(source)

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