Reflaxe.Elixir ships a small set of Mix generators to help scaffold Haxe-first Phoenix/Ecto code.
- Haxe-first output: generators write Haxe source files only. Elixir modules are produced when you compile via
mix compile.haxe/haxe build.hxml. - No app-specific heuristics: templates are generic and follow Phoenix/Ecto APIs as-is.
- Typed by default: prefer typed assigns/params/changesets and avoid
Dynamicin generator output.
haxe --run Run create ...handles new project directory creation (greenfield).mix haxe.gen.*tasks handle in-place scaffolding inside an existing Mix/Phoenix app.- Phoenix client wiring is intentionally centralized in
mix haxe.phoenix.scaffold, which both flows use.
This avoids duplicate Phoenix patching logic while keeping each entrypoint focused on one job.
For end-to-end reference patterns, always compare against examples/todo-app/.
Generates a Haxe @:schema module.
Examples:
mix haxe.gen.schema User
mix haxe.gen.schema Post --table posts
mix haxe.gen.schema Account --fields "name:string,email:string,age:integer"Output:
src_haxe/schemas/<Schema>.hx(or--haxe-dir)
Notes:
- Uses modern schema metadata (
@:schema("table"),@:field,@:timestamps,@:changeset(...)). - Emits a
typedef <Schema>Paramsplus an externchangeset/2that the compiler generates. - If you add associations (
@:belongs_to,@:has_many, etc.), the compiler validates common FK shapes at compile time.- Example:
@:belongs_to("user")requires a localuserId/user_idfield unless you overrideforeign_key.
- Example:
Generates a Haxe Phoenix context module (optionally also generates the schema).
Examples:
mix haxe.gen.context Accounts User users
mix haxe.gen.context Blog Post posts --schema-attrs "title:string,body:text"
mix haxe.gen.context Billing Invoice invoices --no-schemaOutput:
src_haxe/contexts/<Context>.hx(or--haxe-dir)- Optional: schema via
mix haxe.gen.schema(unless--no-schema)
Notes:
- Generates Phoenix-convention functions (
list_*,get_*,create_*,update_*,delete_*). - Uses typed
ecto.Changeset+haxe.functional.Result.
Generates a Haxe Phoenix LiveView module with typed assigns and an HXX template.
Examples:
mix haxe.gen.live DashboardLive
mix haxe.gen.live UsersLive --events "refresh,search"
mix haxe.gen.live CounterLive --assigns "count:Int"Output:
src_haxe/live/<Module>.hx(or--haxe-dir)
Notes:
- Generates
mount/3,handle_event/3, andrender/1in Haxe (compiled to idiomatic LiveView callbacks). - The template uses HXX assigns interpolation (e.g.
\#{@count}) and plain HTML elements to avoid CoreComponents coupling.
Generates a Haxe migration skeleton using the typed migration DSL (std/ecto/Migration.hx).
Examples:
mix haxe.gen.migration CreateUsersTable --table users --columns "name:string,email:string"
mix haxe.gen.migration AddIndexToUsers --table users --index email --uniqueOutput:
src_haxe/migrations/<Migration>.hx(or--haxe-dir)
Important:
- Ecto executes migrations from
priv/repo/migrations/*.exs. - Reflaxe.Elixir can emit runnable
.exsmigrations via an opt-in migration build (-D ecto_migrations_exs).
Generates a starter Haxe extern from an Elixir or Erlang module.
Examples:
mix haxe.gen.extern Enum
mix haxe.gen.extern Ecto.Changeset --package externs.ecto --out src_haxe/externs
mix haxe.gen.extern :crypto --package externs.erlang --out src_haxe/externsOutput:
src_haxe/externs/<Module>.hx(configurable via--out,--package,--class-name)
Notes:
- This generator is intended to keep app code away from untyped
__elixir__()strings. - The generated extern uses
elixir.types.Termat the boundary by default (safe, generic). - Functions with multiple arities are generated using Haxe overloads.
- Canonical usage workflow (extern + wrapper + tests):
docs/06-guides/ADDING_ELIXIR_LIBS_FROM_HAXE.md.
Adds Reflaxe.Elixir plumbing to an existing Mix project (directory layout, build.hxml, Mix compiler config).
Examples:
# Minimal scaffold (gradual adoption)
mix haxe.gen.project --force
# Phoenix-friendly scaffold (adds a typed LiveView example + HXX)
mix haxe.gen.project --phoenix --basic-modules --force
# Phoenix scaffold but keep plain Phoenix JS client bootstrap
mix haxe.gen.project --phoenix --client-mode plain-js --forceOutput (defaults; configurable via flags):
src_haxe/<app>_hx/**— isolated Haxe namespace (e.g.src_haxe/todo_app_hx/*)build.hxml— aligned with current compiler flags:-lib reflaxe.elixir-D elixir_output=lib/<app>_hx-D reflaxe_runtime-D no-utf16-D app_name=<ModuleName>-dce full-D hxx_string_to_sigil(when--phoenixis enabled)-D hxx_mode=tsx(when--phoenixis enabled; strict typed HXX for new scaffolds)
package.json+.haxerc(unless--skip-npm)mix.exsupdated to includecompilers: [:haxe] ++ Mix.compilers()and ahaxe: [...]config blockbuild-tests.hxml+test_haxe/+test/generated/for Haxe-authored ExUnit modulestest/test_helper.exsbootstrap that requires generatedtest/generated/**/*_test.exsmix.exsaliases for Haxe test compilation (haxe.compile.tests, plustestalias when missing).gitignoreupdated to ignore generated output dir by default
Notes:
-D app_nameshould match your Phoenix app module (e.g.MyApp). It is used to derive framework modules (MyApp.Repo,MyAppWeb.Endpoint, Presenceotp_app/PubSub, etc). It does not need to match your generated Haxe module namespace (which is controlled by your Haxe packages, e.g.my_app_hx.*→MyAppHx.*).- This task is intended for gradual adoption: start by compiling helper modules into an isolated namespace (by default
MyAppHx.*, derived fromsrc_haxe/<app>_hx/**+-D elixir_output=lib/<app>_hx), call them from Elixir, and only later replace Phoenix-facing modules. - It does not install Haxe libraries for you. Use
npx lix install ...+npx lix download(seedocs/06-guides/PHOENIX_GRADUAL_ADOPTION.md). --phoenixis meant to be run from a Phoenix app root.- If the project does not look like Phoenix (missing
assets/js/app.jsorconfig/dev.exs), the task will still scaffold the server-side parts and print instructions to runmix haxe.phoenix.scaffoldonce Phoenix files exist.
- If the project does not look like Phoenix (missing
--client-mode <genes|plain-js>controls Phoenix client wiring when--phoenixis enabled (default:genes).
Phoenix client wiring is handled by a dedicated task:
mix haxe.phoenix.scaffold
mix haxe.phoenix.scaffold --client-mode genes
mix haxe.phoenix.scaffold --client-mode plain-js --yesFor a scenario-driven overview (greenfield vs existing app, fail-fast vs --warn-only, and how marker blocks work), see docs/06-guides/SCAFFOLDING_SYSTEM.md.
This is the canonical entrypoint for integrating a Haxe-generated JS client bundle (Genes) into Phoenix LiveView in a way that is robust under esbuild --watch.
Key behaviors:
- Marker blocks: patches
assets/js/app.js,config/dev.exs, andmix.exsusing explicitBEGIN reflaxe_elixir .../END reflaxe_elixir ...blocks (reruns replace block content only). - Fail-fast by default: if the task cannot find an expected Phoenix insertion point (template drift or heavy customization), it raises instead of silently producing a partial scaffold.
- Opt-out:
mix haxe.phoenix.scaffold --warn-onlyemits warnings and skips patches it cannot safely apply. - Modes:
--client-mode genes(default): typed Haxe/Genes client integration.--client-mode plain-js: removes only scaffold-managed Genes wiring; keeps custom user files.
See docs/06-guides/WATCHER_WORKFLOW.md for the rationale and the “temp output + promote” pattern used to avoid transient Could not resolve "./hx_app.js" errors under esbuild watch mode.