js-template-engine
js-template-engine
The command-line interface for the JS Template Engine. Renders UI components defined as plain, typed data to vanilla HTML/CSS/JS or to React, Vue, and Svelte components - with styling methodologies (BEM, Tailwind) applied as extensions.
npx js-template-engine render button.json --framework react
Installation
npm install --save-dev js-template-engine
# or globally:
npm install --global js-template-engine
Commands
render <source>
Renders a template file - or every template in a directory - and writes the generated files.
# Vanilla HTML/CSS/JS (the default):
js-template-engine render button.json
# A React component with BEM classes:
js-template-engine render button.json --framework react --styling bem
# Every template in src/components, as Svelte components, into dist/svelte:
js-template-engine render src/components --framework svelte --output-directory dist/svelte
| Option | Default | |
|---|---|---|
--framework <name> |
- | react, vue, or svelte; omitted renders HTML |
--styling <names> |
- | comma-separated styling extensions (bem, tailwind), applied in order |
-o, --output-directory <path> |
./output |
directory generated files are written to |
-n, --component-name <name> |
filename | component name for templates that declare none |
--styling-strategy <strategy> |
in-file |
inline, in-file, or separate-file |
--styling-language <language> |
css |
css, or scss for nested output; react and HTML require --styling-strategy separate-file under scss |
--stylesheet-link <mode> |
component |
component, or none to emit the separate-file stylesheet and link it from nowhere - no import, no <style src> block, no <link>; requires --styling-strategy separate-file |
--styling-layer <name> |
- | cascade layer emitted stylesheet rules are wrapped in; omitted emits them unlayered |
--styling-layer-order <names> |
- | comma-separated layer order declared ahead of the wrapper, e.g. kit.reset,kit.components |
--load-path <path> |
- | sass load-path directory for resolving @use/@include in component styles under --styling-language css; repeatable |
--scripting-strategy <strategy> |
in-file |
inline, in-file, or separate-file |
--scripting-language <language> |
javascript |
javascript, or typescript to type the generated prop consts; affects HTML mode only and requires --scripting-strategy separate-file (writing <Name>.ts) |
--bem-element-separator <separator> |
__ |
separator between BEM block and element |
--bem-modifier-separator <separator> |
-- |
separator before a BEM modifier |
--bem-mode <mode> |
literal |
literal emits BEM class strings; runtime emits use-bem bem(...) calls for framework targets (HTML keeps the literal classes) |
--bem-import-source <package> |
use-bem |
package the use-bem helper is imported from under --bem-mode runtime |
--tailwind-output <output> |
classes |
classes passes utilities through for Tailwind's build; styles converts them into the generated CSS |
--tailwind-convert-styles |
off | convert each element's authored style into Tailwind utility classes |
--svelte-mode <mode> |
legacy |
legacy emits classic Svelte components; runes emits Svelte 5 runes components ($props(), snippets, event attributes) |
Warnings are printed to stderr; written files are listed on stdout. When a template in a directory fails, the remaining templates still render and the command exits non-zero.
validate <source>
Validates a template file - or every template in a directory - against the template format, without writing anything.
js-template-engine validate src/components
Each valid template is confirmed on stdout; each invalid one is reported on stderr with the path of the offending node. The command exits non-zero when any template is invalid.
Template files
A template is plain serializable data, so the CLI accepts it in several forms:
.json- the transport form..ts,.js,.mjs,.cjs- a module whose default export is the template. TypeScript files are loaded directly; no build step is needed.
// button.ts
import { defineTemplate } from '@js-template-engine/types';
export default defineTemplate({
type: 'component',
name: 'Button',
children: [
{
type: 'element',
tag: 'button',
attributes: { class: ['button'] },
events: [{ name: 'click', handler: 'handleClick' }],
children: [{ type: 'text', content: 'Click me' }],
},
],
});
js-template-engine render button.ts --framework vue
# wrote output/Button.vue
When a directory is given, every template file directly inside it is rendered; subdirectories are not searched.
Component names
The name decides the generated file names (Button.tsx, Button.vue, ...)
and the component identifier inside them. It is resolved in order:
- the template's own
name, when it has acomponentroot; - the
--component-nameflag; - the source filename, PascalCased (
icon-badge.json→IconBadge).
Programmatic use
The CLI is a thin shell over @js-template-engine/core. For build scripts
and tooling, use the engine directly - extensions are passed as objects, no
name mapping involved:
import { process } from '@js-template-engine/core';
import { react } from '@js-template-engine/extension-react';
import { bem } from '@js-template-engine/extension-bem';
const result = process(template, { extensions: [react(), bem()] });
// result.files → [{ path: 'Button.tsx', content: '...' }]
Third-party extensions plug in through that API; the CLI's --framework
and --styling flags cover the published extensions.
Related Packages
Localization for Laravel applications, from the terminal: Lyngo wraps user-facin...
Official CLI for Esvigy — add customizable, animated illustrations directly to y...
Version History
| Version | Released | License |
|---|---|---|
| 2.2.1 | MIT | |
| 2.2.0 | MIT | |
| 2.1.0 | MIT | |
| 2.0.0 | MIT | |
| 1.0.1 | MIT | |
| 1.0.0 | MIT |