using Spry; using Inversion; /** * ComponentsMkconstPage - Documentation for the spry-mkconst tool * * This page explains how to use spry-mkconst to convert HTML files * to Vala string constants that can be referenced in component markup properties. */ public class ComponentsMkconstPage : PageComponent { public override string title { get { return "spry-mkconst Tool - Spry"; } } public const string ROUTE = "/components/spry-mkconst"; private ComponentFactory factory = inject(); public override string markup { get { return """

spry-mkconst Tool

What is spry-mkconst?

spry-mkconst is a command-line tool that converts file contents (typically HTML templates) into Vala string constants. This allows you to:

  • Keep HTML templates in separate files for easier editing
  • Maintain valid Vala syntax that the Vala language server can recognize
  • Reference generated constants from your component's markup property

Unlike the previous spry-mkcomponent approach which modified Vala files, spry-mkconst generates separate constant declarations, keeping your original Vala files intact and recognizable by IDEs and language servers.

Command-Line Usage

Options

Option Description
-o, --output FILE Output file path (default: stdout)
--ns NAMESPACE Wrap const in a namespace
-n, --name NAME Override const name (default: derived from filename)
-v, --version Show version information
--help Show help message

How It Works

The tool takes a single input file and generates a Vala const declaration:

💡 Key Concept: The const name is automatically derived from the filename using CAPITAL_SNAKE_CASE. For example, UserContentComponent.vala.html becomes USER_CONTENT_COMPONENT_VALA_HTML.

Example Transformation

Here's a complete example showing how the tool works:

Input HTML File (UserContentComponent.vala.html)

Generated Output (stdout or file)

Your Vala Component (unchanged, valid Vala)

The key advantage is that your Vala file remains valid, parseable Vala code. The Vala language server can still recognize it, provide autocomplete, and show errors. The generated constant is referenced via return USER_CONTENT_COMPONENT_VALA_HTML;

Integrating with Meson

The recommended way to use spry-mkconst is with meson's build system. You generate a separate Vala file containing the const declarations, then include it in your build.

Basic meson.build Setup

With Namespace

Complete Example

💡 Tip: The generated file should be included in your executable's sources. Meson will run spry-mkconst automatically before compilation.

HTML Template Guidelines

When creating HTML templates for use with spry-mkconst, follow these guidelines:

  • Use sid attributes - Add sid="name" to elements you need to access from Vala code via this["name"]
  • Name templates consistently - Use ComponentName.vala.html for clear association with the component
  • Use HTMX attributes - Add hx-* attributes for interactivity without writing JavaScript
  • Avoid complex logic - Keep templates focused on structure; use Vala for conditional rendering

Why spry-mkconst vs spry-mkcomponent?

The previous spry-mkcomponent tool modified Vala source files by injecting HTML into the markup getter. This had a significant drawback: the Vala language server couldn't recognize the modified files as valid Vala during development.

spry-mkconst solves this by:

  • Keeping your Vala files as valid, parseable Vala code
  • Generating constants in a separate file that's included at build time
  • Allowing the language server to provide full IDE support
  • Using public override string markup { get { return CONSTANT_NAME; } } which is valid Vala syntax

Workflow Integration

A typical development workflow with spry-mkconst looks like this:

  1. Create your HTML template file (e.g., MyComponent.vala.html)
  2. Write your Vala component referencing the generated constant name
  3. Configure meson to generate the const file
  4. Build your project - meson runs spry-mkconst automatically
  5. Iterate - Edit the HTML file; changes are picked up on rebuild

During development, you can run the tool manually to see the generated output:

When to Use spry-mkconst

✅ Good Use Cases

  • Components with substantial HTML markup
  • When you need Vala language server support (autocomplete, errors)
  • Teams where designers work on HTML separately from developers
  • Keeping Vala files focused on logic

❌ When to Skip It

  • Simple components with minimal markup (inline is fine)
  • Quick prototypes where separation isn't beneficial
  • Components with dynamically generated markup

💡 Remember: You can always inline markup directly in your Vala files using triple-quoted strings. spry-mkconst is opt-in - use it when the separation provides value for your project.

Next Steps

"""; }} public override async void prepare() throws Error { var usage_code = get_component_child("usage-code"); usage_code.language = "Bash"; usage_code.code = "spry-mkconst [OPTIONS] \n\n" + "# Examples:\n" + "spry-mkconst Templates/UserContent.html\n" + "spry-mkconst -o generated/constants.vala Templates/UserContent.html\n" + "spry-mkconst --ns MyApp.Templates Templates/UserContent.html\n" + "spry-mkconst -n CUSTOM_NAME Templates/UserContent.html"; var workflow_diagram = get_component_child("workflow-diagram"); workflow_diagram.language = "Text"; workflow_diagram.code = "┌─────────────────────────────────────┐\n" + "│ UserContentComponent.vala.html │\n" + "│ (HTML template) │\n" + "└─────────────┬───────────────────────┘\n" + " │\n" + " ▼\n" + " ┌───────────────┐\n" + " │ spry-mkconst │\n" + " └───────┬───────┘\n" + " │\n" + " ▼\n" + "┌─────────────────────────────────────────────────┐\n" + "│ const string USER_CONTENT_COMPONENT_VALA_HTML │\n" + "│ = \"\"\"...\"\"\"; │\n" + "└─────────────────────────────────────────────────┘"; var input_html = get_component_child("input-html"); input_html.language = "HTML"; input_html.code = "

You said: (via )

"; var output_const = get_component_child("output-const"); output_const.language = "Vala"; output_const.code = "const string USER_CONTENT_COMPONENT_VALA_HTML = \"\"\"\n" + "

You said: (via )

\n" + "\"\"\";"; var vala_component = get_component_child("vala-component"); vala_component.language = "Vala"; vala_component.code = "// This file is valid Vala - the language server recognizes it!\n" + "class UserContentComponent : Component {\n" + " public override string markup { get { return USER_CONTENT_COMPONENT_VALA_HTML; } }\n\n" + " public async override void handle_action(string action) throws Error {\n" + " this[\"message\"].text_content = \"Hello, World!\";\n" + " }\n" + "}"; var meson_basic = get_component_child("meson-basic"); meson_basic.language = "Meson"; meson_basic.code = "# Find the tool\n" + "spry_mkconst = find_program('spry-mkconst')\n\n" + "# Generate constants from HTML templates\n" + "markup_constants = custom_target('markup-constants',\n" + " input: 'Templates/UserContentComponent.vala.html',\n" + " output: 'UserContentConstants.vala',\n" + " command: [spry_mkconst, '@INPUT@', '-o', '@OUTPUT@']\n" + ")\n\n" + "# Include in your executable\n" + "executable('myapp',\n" + " sources: ['Main.vala', 'UserContentComponent.vala', markup_constants],\n" + " dependencies: [spry_dep]\n" + ")"; var meson_namespace = get_component_child("meson-namespace"); meson_namespace.language = "Meson"; meson_namespace.code = "# Generate constants with namespace\n" + "spry_mkconst = find_program('spry-mkconst')\n\n" + "markup_constants = custom_target('markup-constants',\n" + " input: 'Templates/UserContentComponent.vala.html',\n" + " output: 'UserContentConstants.vala',\n" + " command: [spry_mkconst, '@INPUT@', '-o', '@OUTPUT@',\n" + " '--ns', 'MyApp.Markup']\n" + ")\n\n" + "# In your Vala file, use:\n" + "# public override string markup { get { return MyApp.Markup.USER_CONTENT_COMPONENT_VALA_HTML; } }"; var meson_complete = get_component_child("meson-complete"); meson_complete.language = "Meson"; meson_complete.code = "# Find the spry-mkconst tool\n" + "spry_mkconst = find_program('spry-mkconst')\n\n" + "# Collect all HTML template files\n" + "template_files = files(\n" + " 'Templates/HeaderComponent.vala.html',\n" + " 'Templates/FooterComponent.vala.html',\n" + " 'Templates/UserContentComponent.vala.html',\n" + ")\n\n" + "# Generate a single constants file from all templates\n" + "# Note: You can also generate separate files per template\n" + "markup_constants = custom_target('markup-constants',\n" + " input: template_files,\n" + " output: 'MarkupConstants.vala',\n" + " command: [spry_mkconst, '@INPUT@', '-o', '@OUTPUT@', '--ns', 'Markup']\n" + ")\n\n" + "# Component source files (reference the constants)\n" + "component_sources = files(\n" + " 'Components/HeaderComponent.vala',\n" + " 'Components/FooterComponent.vala',\n" + " 'Components/UserContentComponent.vala',\n" + ")\n\n" + "# Build executable\n" + "executable('myapp',\n" + " sources: ['Main.vala', component_sources, markup_constants],\n" + " dependencies: [spry_dep],\n" + ")"; var html_guidelines = get_component_child("html-guidelines"); html_guidelines.language = "HTML"; html_guidelines.code = "\n" + "
\n" + "

\n" + "

\n" + " \n" + "
\n\n" + "\n" + "
\n" + " \n" + " \n" + " \n" + "
"; var manual_run = get_component_child("manual-run"); manual_run.language = "Bash"; manual_run.code = "# Run manually to see generated output\n" + "spry-mkconst Templates/MyComponent.vala.html\n\n" + "# Save to a file\n" + "spry-mkconst Templates/MyComponent.vala.html -o generated/MyComponentMarkup.vala\n\n" + "# View the result\n" + "cat generated/MyComponentMarkup.vala\n\n" + "# Generate with namespace\n" + "spry-mkconst Templates/MyComponent.vala.html --ns MyApp.Templates"; } }