Ultra-lightweight frontend framework: HTML / CSS / JS SFCs, no Virtual DOM, surgical DOM updates via compile-time dependency tracking. Runtime and compiler are zero-dependency (esbuild is the only CLI build dependency).
File extension: .easy
Authoring style: Svelte-like (short, clear)
Package: one install — mez-easyjs
Repository: github.com/MoonesMezher/easyjs
npm i mez-easyjs
# or globally for the CLI
npm i -g mez-easyjs
npx easy create my-app --template starter --yes
cd my-app
npm run devimport { createApp, reactive, createRouter, createStore } from 'mez-easyjs';
// same as: from 'mez-easyjs/runtime'
import { compile } from 'mez-easyjs/compiler';Do not publish from a dirty tree:
# 1) verify
npm test
npm run pack:check # dry-run tarball contents
# 2) publish the single package
npm publish -w mez-easyjs --access public
# optional dry-run
npm run publish:dry<script>
let count = 0;
function greet() {
alert('Welcome to Easy!');
}
function inc() {
count++;
}
</script>
<button onclick={greet}>click me</button>
<p>{count}</p>
<button onclick={inc}>+</button>
<style>
button {
font-size: 2em;
}
</style>No <template> wrapper required — markup sits between <script> and <style>. Optional <template> still works for compatibility.
| Feature | Primary syntax | Notes |
|---|---|---|
| Text | {count} |
Escaped via textContent (XSS-safe) |
| Raw HTML | {@html html} |
Explicit opt-in only |
| Events | onclick={handler} |
Compiles to delegated data-e-on — never inline onclick="..." |
| State | let count = 0 |
Top-level let → reactive |
| Methods | function inc() { count++ } |
Refs to lets rewritten to state |
| Two-way | bind:value={draft} |
Also bind:checked |
| If / each | {#if} / {#each list as item} |
Also e-if / e-for |
| Types | <script lang="ts"> |
Light type-strip (not full tsc) |
| Compat | {{ }}, @click, export default {…} |
Still accepted |
| Package | Role |
|---|---|
mez-easyjs |
Runtime + compiler + CLI (easy / create-easy-app) + templates |
examples/demo |
End-to-end demo |
Stable public imports: mez-easyjs / mez-easyjs/runtime and mez-easyjs/compiler (no deep src/… paths in published consumers).
Easy.js is ESM-first and merges cleanly with Vite / Webpack / esbuild / vanilla apps:
import { createApp, reactive, createRouter, createStore } from 'mez-easyjs';
import { compile } from 'mez-easyjs/compiler';- Alongside other libs: mount into a dedicated root —
createApp(App).mount('#easy-root')— without owning the whole page. - CLI: scaffold and build with the
easybin frommez-easyjs; apps depend on the same package for the runtime. - Custom pipeline: compile
.easywithmez-easyjs/compiler, bundle the JS with your bundler, import runtime helpers frommez-easyjs. - TypeScript projects: light
.d.tsstubs ship with the package. - No globals: production builds do not set
window.*. Dev-only flags (window.__EASY_DEV__, HMR, overlay) are injected byeasy dev.
| Rule | Behavior |
|---|---|
| Default text | {expr} → textContent (never parses HTML) |
| Raw HTML | {@html expr} or e-html only — intentional XSS surface |
| Events | onclick={fn} → data-e-on; quoted onclick="..." rejected |
| URL attrs | href / src / action / … run through sanitizeUrl (blocks javascript:, data:, …) |
| Dangerous attrs | on* and srcdoc cannot be bound or emitted as static HTML |
| CSP | No eval / new Function; no inline handlers |
Recommended CSP (adjust nonces/hashes for your host scripts):
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self'; base-uri 'self'; form-action 'self'; object-src 'none'Notes:
'unsafe-inline'for style may be needed for scoped component CSS injected at runtime. Prefer nonces if you control the style injector.- Do not add
'unsafe-eval'. {@html}bypasses escaping — only pass trusted / sanitized HTML.- Tailwind Play CDN templates load a third-party script; tighten CSP if you ship that in production.
Verify:
npm run test:securitynpm install
npm run create # scaffold (uses file: links inside this repo)
npm run dev # → http://localhost:5173/
npm run build
npm test # security + reactivitynpm run create -- my-app --template starter --yes
npx create-easy-app my-app --template tailwind --yes| Template | What you get |
|---|---|
minimal |
Skeleton + App.easy |
starter |
Counter, routing, props |
tailwind |
Same + Tailwind Play CDN (no PostCSS / npm tailwindcss) |
Inside this monorepo, create rewrites deps to file:…/packages/easyjs. Published users get "mez-easyjs": "^0.1.0".
easy create [name] Interactive project wizard
create-easy-app [name] Same wizard (npm bin alias)
easy create my-app --template starter --yes
easy dev [--port 5173] [--cwd] Dev server + HMR + error overlay
easy build [--outDir dist] Vite-like dist/ (assets/*.js + *.css, minified)
easy generate component Counter
easy generate page About
npm run build
# or: easy build --cwd examples/demodist/
index.html
assets/
index-<hash>.js
index-<hash>.css
chunk-<name>-<hash>.js
Serve dist/ with any static host (npx serve dist).
Easy.js إطار خفيف بدون Virtual DOM بكتابة شبيهة بـ Svelte: {count} و onclick={fn} بدون <template> إلزامي. حزمة واحدة (mez-easyjs) تشمل runtime و compiler و CLI. يدعم HMR مع حفظ الحالة، وحماية XSS لملفات .easy.