astro-stencil
v0.0.4
Published
Astro-powered template generator for multi-engines
Maintainers
Readme
astro-stencil
Astro-powered template generation primitives for building multi-engine server templates from a single Astro component source.
astro-stencil lets you write template logic using Astro components and generate output compatible with multiple backend rendering engines such as:
- PHP
- Laravel Blade
- Go templates
Key Idea
Instead of rendering values directly, you build deferred template expressions:
data.user.name
data.user.posts.map(...)
when`${data.user.age} >= 18`(...)These expressions are later translated into engine-specific template syntax.
Installation
npm install astro-stencilUsage
---
import { createDataSource as createPhpDataSource } from "astro-stencil/php";
import { createDataSource as createGoDataSource } from "astro-stencil/go";
import { createDataSource as createBladeDataSource } from "astro-stencil/blade";
interface PageData {
title: string;
}
const php = createPhpDataSource<PageData>();
const go = createGoDataSource<PageData>();
const blade = createBladeDataSource<PageData>();
---
<div>{php.title}</div>
<div>{go.title}</div>
<div>{blade.title}</div>Supported Generators
Currently included generators:
| Engine | Package Path |
| ------------ | --------------------- |
| PHP | astro-stencil/php |
| Blade | astro-stencil/blade |
| Go templates | astro-stencil/go |
Each generator exposes:
createDataSource<T>()when(...)
Core Concepts
Typed Data Sources
Data sources are proxy objects that represent template variables for the target engine.
It does not hold real data, it builds engine-specific references lazily.
Example:
---
interface Post {
title: string;
content: string;
}
interface User {
name: string;
age: number;
posts: Post[];
}
interface PageData {
user: User;
}
const data = createDataSource<PageData>();
---
<div>
{data.user.name}
{data.user.posts.map(...)}
</div>Accessing properties does not return actual values. Instead, it generates template-safe references for the target engine.
This does not read name. Instead, it becomes:
| Engine | Output |
|-----------|-----------------|
| PHP/Blade | $user['name'] |
| Go | .user.name |
Output Escaping
By default, all rendered variables are automatically escaped for safety using the conventions of the target engine (for example, PHP uses htmlspecialchars).
To bypass escaping and render raw output, explicitly opt into it:
data.user.name.displayUnescapedArray Mapping Example
Arrays expose a typed .map() helper that generates engine-specific loops.
<ul>
{data.user.posts.map((post, index) => (
<li>
#{index}: {post.title}
</li>
))}
</ul>PHP output
<ul>
<?php foreach($posts as $i0 => $iter0): ?>
<li>
#<?php echo htmlspecialchars($i0); ?>:
<?php echo htmlspecialchars($iter0['title']); ?>
</li>
<?php endforeach; ?>
</ul>Go output
{{range $i0, $_ := .user.posts}}
<li>{{$i0}}: {{.title}}</li>
{{end}}Conditional Expressions
when builds a portable expression that is later serialized into each target language.
Fluent API
<div>
{
when((expr) => expr(user.age).gte(18).and(expr.not(user.disabled)))(
<p>Adult</p>,
<p>Minor</p>,
)
}
</div>Tagged Template Syntax
<div>
{
when`${user.age} >= 18 && !${user.disabled}`(
<p>Allowed</p>,
<p>Not Allowed</p>,
)
}
</div>Supported Operators:
- Comparison:
==,!=,<,<=,>,>= - Logic:
&&,||,! - Literals:
true,false, numbers, strings ("..."or'...')
