Simple and elegant component-based UI library
—
Runtime compilation capabilities for compiling riot components from templates and URLs. Available only in the riot+compiler build, these functions enable dynamic component compilation and template processing in the browser.
Automatically discovers and compiles riot script tags in the DOM.
/**
* Compile riot script tags found in the DOM
* @param options - Optional compilation configuration
* @returns Promise that resolves when all scripts are compiled and registered
*/
function compile(options?: CompileOptions): Promise<void>;Usage Example:
<!-- HTML with riot script tags -->
<script type="riot" src="./components/my-timer.riot"></script>
<script type="riot" data-src="./components/my-widget.riot"></script>import { compile, mount } from "riot+compiler";
// Compile all riot script tags and register components
await compile({
// Optional compilation options
compact: true,
expression: "javascript"
});
// Components are now registered and can be mounted
mount("my-timer");
mount("my-widget");Compiles a riot component from a template string.
/**
* Compile riot component from string template
* @param string - Component template string
* @param options - Optional compilation configuration
* @returns Compilation result with code and metadata
*/
function compileFromString(
string: string,
options?: CompileOptions
): CompilationResult;Usage Example:
import { compileFromString, register } from "riot+compiler";
const template = `
<my-dynamic-component>
<h1>{ props.title }</h1>
<p>Generated at: { state.timestamp }</p>
<script>
export default {
onBeforeMount() {
this.state = { timestamp: new Date().toISOString() };
}
}
</script>
<style>
my-dynamic-component {
padding: 1rem;
border: 1px solid #ccc;
}
</style>
</my-dynamic-component>
`;
// Compile the template
const result = compileFromString(template, {
file: 'dynamic-component.riot'
});
// Register the compiled component
register("my-dynamic-component", eval(result.code));Fetches and compiles a riot component from a URL.
/**
* Compile riot component from URL
* @param url - URL to fetch component template from
* @param options - Optional compilation configuration
* @returns Promise with compilation result
*/
function compileFromUrl(
url: string,
options?: CompileOptions
): Promise<CompilationResult>;Usage Example:
import { compileFromUrl, register } from "riot+compiler";
// Fetch and compile remote component
const result = await compileFromUrl("https://example.com/components/remote-widget.riot", {
compact: false,
expression: "javascript"
});
// Register the compiled component
register("remote-widget", eval(result.code));
// Mount the component
mount("remote-widget", { apiKey: "abc123" });Evaluates and registers compiled component code in the global registry.
/**
* Inject compiled component code into global registry
* @param code - Compiled component JavaScript code
* @param tagName - Component tag name for registration
* @param url - Source URL for debugging/error reporting
* @returns void
*/
function inject(code: string, tagName: string, url: string): void;Usage Example:
import { inject } from "riot+compiler";
// Manually inject pre-compiled code
const compiledCode = `({
css: 'injected-component { color: red; }',
template: (template) => template('<h1>Injected!</h1>'),
exports: {
onMounted() {
console.log('Injected component mounted');
}
}
})`;
inject(compiledCode, "injected-component", "manual-injection");
// Component is now registered and ready to mount
mount("injected-component");The compiler build provides enhanced versions of mount and component that automatically create slots from DOM content:
/**
* Enhanced mounting function that creates slots from DOM content
* @param selector - CSS selector or HTMLElement to mount to
* @param initialProps - Initial component properties
* @param componentName - Optional component name
* @returns Array of component instances
*/
function mount<Props, State>(
selector: string | HTMLElement,
initialProps?: Props,
componentName?: string
): RiotComponent<Props, State>[];Usage Example:
<!-- Existing DOM content becomes slots -->
<my-card>
<div slot="header">Card Title</div>
<div slot="content">Card content goes here</div>
</my-card>import { mount } from "riot+compiler";
// DOM content is automatically converted to slots
const cards = mount("my-card", { theme: "dark" });/**
* Enhanced component factory with automatic slot creation
* @param wrapper - Component wrapper implementation
* @returns Enhanced factory function
*/
function component(wrapper: RiotComponentWrapper): (
el: HTMLElement,
props?: any,
meta?: ComponentMeta
) => RiotComponent;interface CompileOptions {
/** Generate compact output (minified) */
compact?: boolean;
/** Expression parser type */
expression?: "javascript" | "typescript";
/** File path for source maps and error reporting */
file?: string;
/** Custom preprocessors */
preprocessors?: {
[key: string]: PreprocessorFunction;
};
/** Template parser options */
template?: TemplateOptions;
/** CSS parser options */
css?: CSSOptions;
}
interface CompilationResult {
/** Compiled JavaScript code */
code: string;
/** Component metadata */
meta: {
tagName: string;
dependencies?: string[];
css?: boolean;
javascript?: boolean;
};
/** Source map (if enabled) */
map?: string;
}import { compileFromUrl, register, mount } from "riot+compiler";
class ComponentLoader {
constructor() {
this.cache = new Map();
}
async loadComponent(name, url) {
if (this.cache.has(name)) {
return this.cache.get(name);
}
try {
const result = await compileFromUrl(url);
const component = eval(result.code);
register(name, component);
this.cache.set(name, component);
return component;
} catch (error) {
console.error(`Failed to load component ${name}:`, error);
throw error;
}
}
async loadAndMount(name, url, selector, props) {
await this.loadComponent(name, url);
return mount(selector, props, name);
}
}
// Usage
const loader = new ComponentLoader();
await loader.loadAndMount(
"lazy-widget",
"/components/lazy-widget.riot",
".widget-container",
{ data: apiData }
);import { compileFromString } from "riot+compiler";
// Template with custom preprocessing
const preprocessTemplate = (template, context) => {
return template
.replace(/\{\{(\w+)\}\}/g, '{ $1 }') // Convert {{}} to {}
.replace(/\$\{(\w+)\}/g, '{ props.$1 }'); // Convert ${} to props
};
const rawTemplate = `
<preprocessed-component>
<h1>{{title}}</h1>
<p>Value: \${value}</p>
</preprocessed-component>
`;
const processedTemplate = preprocessTemplate(rawTemplate);
const result = compileFromString(processedTemplate);type CompileOptions = {
compact?: boolean;
expression?: "javascript" | "typescript";
file?: string;
preprocessors?: Record<string, PreprocessorFunction>;
template?: TemplateOptions;
css?: CSSOptions;
};
type CompilationResult = {
code: string;
meta: {
tagName: string;
dependencies?: string[];
css?: boolean;
javascript?: boolean;
};
map?: string;
};
type PreprocessorFunction = (
code: string,
options: any
) => { code: string; map?: string };
type TemplateOptions = {
brackets?: [string, string];
[key: string]: any;
};
type CSSOptions = {
parser?: string;
[key: string]: any;
};Install with Tessl CLI
npx tessl i tessl/npm-riot