Class: Lilac::CLI::Builder
- Inherits:
-
Object
- Object
- Lilac::CLI::Builder
- Defined in:
- lib/lilac/cli/build/builder.rb
Overview
Orchestrates a full build: loads components, stages packages,
writes the (optional) bundle file, compiles each page via
PageCompiler, then vendors runtime assets into dist/vendor/.
The per-page rewriting logic lives in PageCompiler; HTML helpers
in HtmlEmitter; template parse caching in TemplateASTCache;
all of those share state through the BuildContext value object
this class assembles.
Defined Under Namespace
Classes: Error
Constant Summary collapse
- EXCLUDED_BASENAMES =
Filenames that must not land in the build output even when they exist under
public/. Add to this list as new conventions are encountered (e.g..DS_Store,Thumbs.db). %w[.gitkeep].freeze
- EXCLUDED_DIRS_FOR_TARGET =
Target-specific public/ subdirectories that should NOT be mirrored into dist/ for the inactive target. Both runtime variants live under their own namespace in
public/vendor/so a project that ships both (e.g. dev=full, prod=compiled) can keep them side by side and let the CLI prune the inactive one at build time.Paths are relative to
public_dir, POSIX style. The match is on path prefix + boundary, sovendor/lilac-fullmatchesvendor/lilac-full/lilac-full.wasmbut notvendor/lilac-full-x. { full: %w[vendor/lilac-compiled].freeze, compiled: %w[vendor/lilac-full].freeze }.freeze
Class Method Summary collapse
-
.from_config(config, live_reload: false, target: nil, delivery: nil) ⇒ Object
Construct a Builder from a resolved
Config.
Instance Method Summary collapse
- #build ⇒ Object
-
#initialize(components_dir:, pages_dir:, output_dir:, public_dir: nil, live_reload: false, target: :full, mrbc_path: nil, lilac_compiled_path: nil, lilac_full_path: nil, mruby_wasm_js_path: nil, packages: [], disable_gem_discovery: false, delivery: :inline) ⇒ Builder
constructor
A new instance of Builder.
Constructor Details
#initialize(components_dir:, pages_dir:, output_dir:, public_dir: nil, live_reload: false, target: :full, mrbc_path: nil, lilac_compiled_path: nil, lilac_full_path: nil, mruby_wasm_js_path: nil, packages: [], disable_gem_discovery: false, delivery: :inline) ⇒ Builder
Returns a new instance of Builder.
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/lilac/cli/build/builder.rb', line 81 def initialize(components_dir:, pages_dir:, output_dir:, public_dir: nil, live_reload: false, target: :full, mrbc_path: nil, lilac_compiled_path: nil, lilac_full_path: nil, mruby_wasm_js_path: nil, packages: [], disable_gem_discovery: false, delivery: :inline) @components_dir = components_dir @pages_dir = pages_dir @output_dir = output_dir # public_dir is optional. When nil or absent on disk, the # mirroring step is skipped — projects that don't need static # passthrough (no vendor bundle, no images) work fine without # creating the directory. @public_dir = public_dir @live_reload = live_reload # `:full` — dist HTML loads inline Ruby via lilac-full wasm # (vm.evalScript). `:compiled` — Ruby is pre-compiled to # `.mrb` bytecode via `mrbc` and loaded by lilac-compiled wasm # (vm.loadBytecode). The compiled target shaves ~32% off the brotli # bundle but requires `mrbc` available at build time. See # `BytecodeBuilder` for path discovery. @target = target @mrbc_path = mrbc_path # Discovery hints for the compiled runtime — wasm + boot helper # + JS bridge. Used by `auto_vendor_compiled_runtime!` so the # built dist is fully self-contained and no manual cp into # `public/vendor/lilac-compiled/` is required. @lilac_compiled_path = lilac_compiled_path # Discovery hint for the full runtime wasm — parallel to # `@lilac_compiled_path`. Used by `auto_vendor_full_runtime!` # via `FullRuntimeResolver` so a `:full` build is reliably # self-contained (offline-runnable) without the CDN. @lilac_full_path = lilac_full_path @mruby_wasm_js_path = mruby_wasm_js_path # Pre-compiled Lilac package `.mrb` paths (absolute). For both # `:compiled` and `:full` builds these get staged under # `dist/packages/`; `:compiled` injects loadBytecode into the # generated boot module directly, `:full` writes a # `dist/lilac.packages.json` manifest the scaffold boot fetches. # See decisions §25 / §26. @packages = Array(packages).map { |p| File.(p) } # Mirrors `CompiledRuntimeResolver` / `BytecodeBuilder`'s # `disable_gem_discovery:` — tests pass `true` so the gem-bundled # wasm doesn't satisfy lookups they're trying to isolate. Plumbed # through to both resolvers below. @disable_gem_discovery = disable_gem_discovery # `:inline` (default) — inject component definitions into each # page's HTML. `:bundle` — emit a single dist/lilac.bundle.html # referenced from pages via `<link rel="lilac-bundle">`. Runtime # registry fetches the bundle and injects templates + evals # scripts before mount. @delivery = delivery end |
Class Method Details
.from_config(config, live_reload: false, target: nil, delivery: nil) ⇒ Object
Construct a Builder from a resolved Config. Centralises the
Config-attr → Builder-kwarg mapping so callers in Command and
DevServer don't drift out of sync. Overridable kwargs cover
the per-caller differences:
- `target:` — Command picks `config.build_target`, DevServer
picks `config.dev_target`. Defaults to the build target.
- `delivery:` — either caller can pin a value here; both
currently leave it unset so `config.delivery` wins (build
and dev share the same delivery path, matching what ships
to prod).
- `live_reload:` — DevServer turns it on for SSE-driven page
reload; `lilac build` leaves it off.
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/lilac/cli/build/builder.rb', line 63 def self.from_config(config, live_reload: false, target: nil, delivery: nil) new( components_dir: config.components_dir, pages_dir: config.pages_dir, output_dir: config.output_dir, public_dir: config.public_dir, target: target || config.build_target, mrbc_path: config.mrbc_path, lilac_compiled_path: config.lilac_compiled_path, lilac_full_path: config.lilac_full_path, mruby_wasm_js_path: config.mruby_wasm_js_path, packages: config.packages, delivery: delivery || config.delivery, live_reload: live_reload ) end |
Instance Method Details
#build ⇒ Object
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/lilac/cli/build/builder.rb', line 137 def build components = load_components pages = Dir.glob(File.join(@pages_dir, '**', '*.html')) raise Error, "No pages found under #{@pages_dir.inspect}" if pages.empty? public_files = mirror_public_files template_cache = TemplateASTCache.new build_linter = BuildLinter.new # Resolve and stage package `.mrb` files once for the build — # the URLs are stable across pages so each page's boot module # can reference the same set. PackageStager owns both the # discovered + explicit input channels and the :full-only # `lilac.packages.json` manifest emission. package_dist_urls = PackageStager.new( packages: @packages, target: @target, output_dir: @output_dir, bytecode_builder: bytecode_builder ).run! # In :bundle delivery mode, emit a single dist/lilac.bundle.html # containing all components' templates + scripts. Pages then # reference it via <link rel="lilac-bundle">. Done once before # page processing so PageCompiler can inject the <link>. bundle_assets = if @delivery == :bundle BundleAssetWriter.new( components: components, template_cache: template_cache, target: @target, output_dir: @output_dir, bytecode_builder: bytecode_builder ).write! end context = BuildContext.new( components: components, bundle_assets: bundle_assets, package_dist_urls: package_dist_urls, template_cache: template_cache, build_linter: build_linter, bytecode_builder: bytecode_builder, target: @target, delivery: @delivery, live_reload: @live_reload, output_dir: @output_dir, pages_dir: @pages_dir, ) compiler = PageCompiler.new(context) pages.each { |page_path| compiler.compile(page_path) } build_linter.warn_cross_page_signature_drift! # `:compiled` target needs the runtime (wasm + bridge + boot # helper) sitting under `dist/vendor/lilac-compiled/`. We emit # it from the CLI directly so users don't have to vendor the # npm package by hand. Skipped when no `.mrb` was actually # produced — pages without any Ruby script don't reference the # bootstrap module. auto_vendor_compiled_runtime! if @target == :compiled && Dir.glob(File.join(@output_dir, '*.mrb')).any? # :full vendor — symmetric to :compiled. Strict: raises with an # actionable message when no runtime is discoverable (so an # offline build can't silently ship without its wasm), unless the # assets are already vendored (manual / public-mirror workflow). auto_vendor_full_runtime! if @target == :full { pages: pages.length, components: components.length, public_files: public_files } end |