Neo.mjs v10.3.0: Introducing HTML Templates
This release marks a major milestone in the evolution of Neo.mjs, introducing an intuitive, HTML-like syntax for building component VDOMs. This has been a significant undertaking, designed to lower the barrier to entry for new developers while holding true to the framework's core principles of performance and adherence to web standards.
This feature is the culmination of the work tracked in our public epic: #7130.
Key Feature: HTML Templates
You can now define a component's VDOM using familiar HTML-like syntax, powered by standard JavaScript Tagged Template Literals. This provides an alternative to the traditional JSON-based VDOM structure, making UI development more approachable.
import { html } from '../../src/functional/util/html.mjs';
import Button from '../../src/button/Base.mjs';
// Inside a component's render() method:
return html`
<div class="my-container">
<p>${this.myText}</p>
<${Button} text="Click Me" handler="${this.onButtonClick}" />
</div>
`;The Philosophy: Why Not JSX?
This new feature is built on a core Neo.mjs principle: a commitment to a zero-builds development experience.
- Standard JavaScript: Unlike JSX, which requires a compiler,
htmltemplates are a standard JavaScript feature. Your code runs directly in the browser without a mandatory build step, providing an instant feedback loop. - No Hidden Magic: Logic is handled with plain JavaScript (
if/else,.map()), not special template directives. What you write is what you get.
The Dual-Mode Architecture
To achieve both developer convenience and production performance, the framework uses a sophisticated dual-mode approach:
- Development Mode: Templates are parsed live in the browser using
parse5. This parser is only loaded if templates are actually used, ensuring zero overhead for applications that stick to the JSON VDOM. - Production Mode: For
dist/esm,dist/dev, anddist/prodbuilds, a powerful build-time AST transformation converts templates directly into optimized VDOM objects. This eliminates theparse5dependency from production builds entirely, resulting in zero runtime parsing overhead and maximum performance. TheenableHtmlTemplatesflag is also automatically set tofalsein production environments, ensuring that the runtime parser is never accidentally used.
As a developer convenience, if you name your template-generating method render(), the build process will automatically rename it to createVdom() for you, aligning with the framework's lifecycle methods while providing a familiar entry point.
Foundational Enhancements
The introduction of HTML templates was made possible by a series of significant enhancements to the framework's core and build scripts:
- Component Lifecycle Integration (
src/functional/component/Base.mjs): The functional component base class was updated to recognize and process the newHtmlTemplatereturn type fromrender(), seamlessly integrating the parsing process into the component lifecycle. - Runtime Parsing (
src/functional/util/HtmlTemplateProcessor.mjs): A new runtime processor that intelligently flattens nested templates, handles dynamic values, and usesparse5to convert the HTML string into a VDOM structure. - Build-Time AST Processing (
buildScripts/util/astTemplateProcessor.mjs): A new, robust build-time processor that usesacornto parse source code into an Abstract Syntax Tree (AST), replaces template literals with their VDOM object counterparts, and generates new, optimized code withastring. - Webpack Integration (
buildScripts/webpack/loader/template-loader.mjs): A new Webpack loader that hooks the AST processor into thedist/devanddist/prodbuild pipelines, applied only to the app worker where components live.
New Documentation
To support this major new feature, we have added two comprehensive guides:
- Using HTML Templates: A guide focused on the syntax, features, and best practices for using the new template system.
- Under the Hood: HTML Templates: A deep dive into the philosophy and the dual-mode architecture, explaining how templates work in both development and production environments.
All changes combined into 1 commit: 0841e7e
We are incredibly excited about this release and believe it makes Neo.mjs more powerful and accessible than ever. Please explore the new feature, read the documentation, and share your feedback!
Try it out by yourself:
https://neomjs.com/examples/functional/nestedTemplateComponent/
https://neomjs.com/dist/esm/examples/functional/nestedTemplateComponent/
https://neomjs.com/dist/development/examples/functional/nestedTemplateComponent/
