Fine-Grained Bundling
- Marko bundles only interactive JavaScript at compile time
- Static content requires zero client-side JavaScript
- Bundle size depends on interactivity, not architecture
Marko uses compile-time analysis to generate minimal JavaScript bundles by identifying which parts of templates actually need interactivity. Instead of shipping entire component trees, only the code necessary for dynamic behavior reaches the browser. This means that Marko is zero-JS by default, and interactive pages only ship JavaScript for the parts that truly need it.
Beyond Islands
Some frameworks, including older versions of Marko, use the islands architecture to reduce JavaScript in each page bundle. Islands are determined at the component level, so applications authored in an islands-based framework need clear distinction between server components and client components.
In Marko 6 the compiler decides which code to is interactive based on the state tree, and only includes what is necessary in the browser bundle. Consider this tag that includes an interactive "watch" button:
<div>
<h3>${input.name}</h3>
<${input.content}/>
// Interactive toggle
<let/watching:=input.watching>
<button onClick() {
watching = !watching;
}>
${watching ? "watching" : "watch"}
</button>
</div>
div
h3 -- ${input.name}
${input.content}
// Interactive toggle
let/watching:=input.watching
button onClick() {
watching = !watching;
}
-- ${watching ? "watching" : "watch"}
<div>
<h3>${input.name}</h3>
<${input.content}/>
// Interactive toggle
<let/watching:=input.watching>
<button onClick() {
watching = !watching;
}>
${watching ? "watching" : "watch"}
</button>
</div>
div
h3 -- ${input.name}
${input.content}
// Interactive toggle
let/watching:=input.watching
button onClick() {
watching = !watching;
}
-- ${watching ? "watching" : "watch"}
Only the JavaScript for toggling watching
and updating the button text is included. JavaScript for rendering static content or creating the button element is not included.
Automatic Optimization
Marko's compiler automatically determines what needs JavaScript without manual configuration.
Whether an application is structured as one large component or split into many small ones, the bundle size remains the same—determined purely by the amount of interactivity, not by component architecture. The compiler extracts only the interactive portions regardless of how the code is organized. This way, component can be split up according to separation of concerns.
This creates a development experience where good performance emerges naturally from the compilation process. Architectural decisions become about maintainability and developer experience, while the compiler handles optimization automatically.
Contributors
Helpful? You can thank these awesome people! You can also edit this doc if you see any issues or want to improve it.