IMPORTANT : This project is still in the development and testing stages, licensing terms may be updated in the future. Please don't do any commercial usage currently.
Choose Vue
npm create vite@latestMake sure you're in Vue project
npm install tsxAssuming the Vue project is named vue-project
import SakuraEngine as SKE
root_dir = joinpath(@__DIR__, "path", "to", "your", "root_dir")
input_path = joinpath(root_dir, "path", "to", "your", "template.sk")
vue_project_dir = joinpath(root_dir, "vue-project")
output_ts_dir = joinpath(vue_project_dir, "src", "sakura")
SKE.init_frontend(vue_project_dir)
SKE.export_assets(input_path, output_ts_dir)
vue_html = cd(vue_project_dir) do
read(`npx.cmd tsx scripts/render-vue-panel.ts`, String)
end
final_html = SKE.render_file(input_path; vue_ssr=vue_html)and then go into vue-project
npm run devjulia --project=. scripts/render_hydration_example.jl#= Julia script =#
<sk-script>
title = "Sakura mix Vue SFC"
user_name = "Sakura"
show_server_hello = true
disable_increment = false
initial_count = 5
server_tags = ["ssr", "hydration", "sfc"]
todos = [
Dict("id" => 1, "label" => "Setup Sakura-SFC ", "done" => true),
Dict("id" => 2, "label" => "Enjoy Single File Dev ", "done" => false),
]
pending_count = count(todo -> !todo["done"], todos)
</sk-script>
#= TypeScript / Vue Logic =#
<script type="sk-ts">
interface Todo {
id: number;
text: string;
done: boolean;
}
interface ServerTag {
id: string;
name: string;
}
const title = ref<string>({{|| title ||}})
const user = ref<string>({{|| user_name ||}})
const count = ref<number>({{|| initial_count ||}})
const todos = ref<Todo[]>({{|| todos ||}})
const serverTags = ref<ServerTag[]>({{|| server_tags ||}})
const ready = ref<boolean>(false)
const pending = computed((): number => {
return todos.value.filter((t: Todo) => !t.done).length
})
onMounted(() => {
ready.value = true
})
return { title, user, count, todos, serverTags, ready, pending }
</script>
<script type="module" src="/src/entry-client.ts"></script>
#= Template Area ( SSR + Vue Hydration ) =#
<sk-template>
<section id="vue-panel">
<h1>{{ title }}</h1>
<p>Server : {{|| user_name ||}} / Client : {{ user }}</p>
<p
sk-if="show_server_hello"
>
Hello from SakuraEngine server side
</p>
<p v-if="ready">Client Pending : {{ pending }}</p>
<p v-else>Server Pending : {{|| pending_count ||}}</p>
<button @click="count++">
Count: {{ count }}
</button>
<h3>Tags ( Hybrid List )</h3>
<ul>
#= sk-for for SEO, v-for for Reactivity =#
<li
sk-for="tag in server_tags"
v-for="tag in serverTags"
:key="tag"
>
tag = {{ tag }}
</li>
</ul>
<h3>Todos</h3>
<ul>
<li
sk-for="todo in todos"
v-for="todo in todos"
:key="todo.id"
>
<span
:style="{ textDecoration: todo.done ? 'line-through' : 'none' }"
>
{{ todo.label }}
</span>
<button
@click="todo.done = !todo.done"
>Toggle</button>
</li>
</ul>
<p>Status : All zones are now hydrated and reactive via Sakura-SFC.</p>
</section>
</sk-template>julia --project=. --color=yes scripts/highlight_sk.jl template_example/hydration_example.skSakuraEngine uses a two-phase template pipeline for Vue 3 style hydration :
- Server phase :
sk-if,sk-else-if,sk-else,sk-for,sk-bind:*, and{{|| expr ||}}are executed by SakuraEngine on the server first. - Client phase :
Vue directives and Vue interpolation such as
v-if,v-else-if,v-else,v-for,v-model,@click,:prop, and{{ expr }}are preserved in the rendered HTML for Vue 3 to process on the client.
Top-level sibling blocks are also allowed :
<sk-script>provides Julia server context<script type="application/json">and<script type="module">may live at the same level as<sk-template>- top-level sibling scripts are preserved in output
{{|| expr ||}}inside those sibling scripts is rendered by SakuraEngine- Vue syntax inside sibling scripts is left untouched
{{|| expr ||}}is server interpolation only.{{ expr }}is Vue interpolation only.sk-*directives own the server structural pass.v-*directives own the client reactive pass.
sk-forruns beforesk-if, matching the current transformer priority.- After SakuraEngine expands or removes nodes, the remaining template is passed forward with Vue syntax intact.
- This means Vue only sees the post-
sk-*DOM shape.
Allowed and recommended :
sk-forwrapping markup that still containsv-if,v-model,@click, or{{ }}sk-ifgating a Vue-owned section{{|| expr ||}}and{{ expr }}in the same file, as long as each side owns its own data source
Use caution :
- Putting
sk-forandv-foron the same element - Putting
sk-ifandv-ifon the same element
When both appear on the same element, SakuraEngine now keeps the Vue directive
but executes the sk-* directive first and emits a warning during the server
transform pass.
Vue3 License : https://github.com/vuejs/core/blob/main/LICENSE
Tailwind CSS License : https://github.com/tailwindlabs/tailwindcss/blob/main/LICENSE
Vite License : https://github.com/vitejs/vite/blob/main/LICENSE
