@jacare/vite-plugin
v0.1.17
Published
Vite plugin for Jacaré .jcr files
Readme
@jacare/vite-plugin
Vite plugin that compiles .jcr files during development and production builds.
When you import a .jcr module, this plugin runs @jacare/compiler and returns optimized JavaScript with source maps. It also validates template contracts against imported children so misuse fails at transform time. No extra build step is required — Vite handles everything.
Table of contents
- Install
- Quick start
- Project setup
- Configuration
- Plugin options
- How it works
- SSR
- Inspect mode
- TypeScript
- Troubleshooting
- Links
Install
npm install @jacare/vite-plugin @jacare/compiler @jacare/core
npm install -D viteFor the Jacaré CLI (scaffold / jacare dev / jacare build):
npm install -g @jacare/cliPeer dependency: Vite ^5 or ^6.
npm: https://www.npmjs.com/package/@jacare/vite-plugin
Quick start
Option A — manual config
// vite.config.js
import { defineConfig } from 'vite'
import jacare from '@jacare/vite-plugin'
export default defineConfig({
plugins: [jacare()],
})Option B — helper config
import { createJacareViteConfig } from '@jacare/vite-plugin'
export default createJacareViteConfig({
title: 'My App',
port: 3000,
base: '/',
})The helper pre-configures the Jacaré plugin, default port, and optimizeDeps exclusions.
Project setup
A typical Jacaré + Vite project looks like this:
my-app/
src/
app.jcr # UI component
boot.js # entry — mounts the app
index.html # HTML shell
public/ # static assets
jacare.config.js # app config (optional)
jacare.d.ts # TypeScript types for .jcr
vite.config.js # Vite config (optional if using @jacare/cli)index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/boot.js"></script>
</body>
</html>boot.js
import App from './app.jcr'
const root = document.getElementById('app')
App(root)app.jcr
import { pulse, view } from '@jacare/core'
const count = pulse(0)
export default view`
<button on-click=${() => count.update((n) => n + 1)}>
Count: ${count}
</button>
`Run with npx vite or jacare dev (from @jacare/cli).
Configuration
jacare.config.js
Place this file in the project root. The plugin reads it automatically:
export default {
title: 'My App', // injected into <title> in index.html
port: 3000, // dev server port (used by @jacare/cli)
base: '/', // Vite base path (e.g. '/my-app/' for GitHub Pages)
}vite.config.js
import { defineConfig } from 'vite'
import jacare from '@jacare/vite-plugin'
export default defineConfig({
base: '/my-app/',
plugins: [
jacare({
inspect: true, // write compiled output to .jacare/compiled/
emit: 'client', // client | server | full | auto
runtimeImport: '@jacare/core',
configFile: 'jacare.config.js',
}),
],
})Plugin options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| emit | 'auto' \| 'client' \| 'server' \| 'full' | 'auto' | Which functions to emit from each .jcr file |
| inspect | boolean | false | Write compiled JS to .jacare/compiled/ for debugging |
| runtimeImport | string | '@jacare/core' | Import path for runtime helpers |
| configFile | string | 'jacare.config.js' | Path to app config file |
Emit modes
| Mode | Behavior |
|------|----------|
| auto | client for browser builds, server for SSR transforms |
| client | Emits mount() and resume() only |
| server | Emits render() only |
| full | Emits all three functions |
How it works
- Vite encounters an import like
import App from './app.jcr' - The plugin's
transformhook runs@jacare/compileron the source - Compiled JavaScript is returned with a source map pointing back to
.jcr - Vite bundles the result like any other module
The plugin runs with enforce: 'pre' so .jcr files are compiled before other transforms.
optimizeDeps
@jacare/core is excluded from Vite's dependency pre-bundling because it uses fine-grained reactivity that must not be duplicated across chunks.
HTML title injection
If jacare.config.js sets title, the plugin updates <title> in index.html during dev and build.
SSR
When Vite runs in SSR mode (transformOptions.ssr === true), the plugin automatically compiles .jcr files with mode: 'server' (when emit is 'auto').
// server entry
import { renderToString } from '@jacare/core'
import { render } from './app.jcr'
const { html, state } = render()
const page = renderToString(() => html)On the client, call resume(root, state) to hydrate.
Inspect mode
Enable compiled output inspection:
jacare({ inspect: true })Compiled files are written to:
.jacare/compiled/
app.js
Field.js
...Useful when debugging what the compiler emits for a specific .jcr file.
TypeScript
Jacaré is JS-first. Optional TypeScript:
Sibling *.jcr.ts
Place typed logic next to the view. The Vite plugin watches the sibling and the compiler merges it automatically:
// src/Counter.jcr.ts
import { pulse } from '@jacare/core'
export const count = pulse(0)// src/Counter.jcr
export <view>
<p>${count}</p>
</view>Pragma // @jacare-ts
// @jacare-ts
const title: string = 'Hi'
export <view>
<h1>${title}</h1>
</view>Typing .jcr imports
Add jacare.d.ts to your project:
declare module '*.jcr' {
export function mount(
target: HTMLElement,
props?: Record<string, unknown>,
): () => void
export function render(
props?: Record<string, unknown>,
): { html: string; state: unknown }
export function resume(
target: HTMLElement,
state: unknown,
props?: Record<string, unknown>,
): () => void
const _default: typeof mount
export default _default
}See docs/syntax.md § TypeScript.
Troubleshooting
"Failed to resolve import .jcr"
Make sure @jacare/vite-plugin is in your Vite plugins array and runs before other plugins that might intercept unknown extensions.
Stale compiled output in dev
Clear Vite's cache:
rm -rf node_modules/.viteCompile errors in the browser overlay
The plugin maps JacareCompileError to Vite's error overlay with file, line, column, and a source snippet. Fix the .jcr source — the overlay points to the original file, not generated JS.
GitHub Pages / subpath deployment
Set base in jacare.config.js or vite.config.js:
export default { base: '/my-repo/' }Links
- npm — @jacare/vite-plugin
- Repository
- Example app
- Jacaré Lab
- Jacaré UI —
@jacare/uicomponent library - Related: @jacare/compiler · @jacare/core · @jacare/cli · @jacare/ui
License
MIT
