nuejs-core
Advanced tools
Comparing version 0.4.0 to 0.5.0
{ | ||
"name": "nuejs-core", | ||
"version": "0.4.0", | ||
"description": "The Nue framework for building user interfaces", | ||
"homepage": "https://nuejs.org", | ||
"repository": { | ||
"url": "https://github.com/nuejs/nue", | ||
"directory": "packages/nuejs", | ||
"type": "git" | ||
"name": "nuejs-core", | ||
"version": "0.5.0", | ||
"description": "HTML microlibrary for UX developers", | ||
"homepage": "https://nuejs.org", | ||
"license": "MIT", | ||
"type": "module", | ||
"main": "index.js", | ||
"repository": { | ||
"url": "https://github.com/nuejs/nue", | ||
"directory": "packages/nuejs", | ||
"type": "git" | ||
}, | ||
"license": "MIT", | ||
"type": "module", | ||
"scripts": { | ||
"test": "cd test && bun test", | ||
"compile": "cd test && bun compile.js" | ||
}, | ||
"main": "index.js", | ||
"dependencies": { | ||
"htmlparser2": "^9.0.0" | ||
}, | ||
"engines": { | ||
"bun": ">= 1", | ||
"node": ">= 18" | ||
} | ||
"engines": { | ||
"bun": ">= 1", | ||
"node": ">= 18" | ||
}, | ||
"scripts": { | ||
"test": "node --experimental-vm-modules ../../node_modules/jest/bin/jest.js --runInBand", | ||
"compile": "cd test && bun compile.js" | ||
}, | ||
"dependencies": { | ||
"htmlparser2": "^9.1.0" | ||
}, | ||
"jest": { | ||
"setupFilesAfterEnv": [ | ||
"jest-extended/all", | ||
"<rootDir>/../../setup-jest.js" | ||
] | ||
} | ||
} |
<a href="https://nuejs.org"> | ||
<img src="https://nuejs.org/img/nuejs-banner-big.png"> | ||
</a> | ||
# Nue JS | ||
Nue JS is a tiny (2.3kb minzipped) JavaScript library for building web interfaces. It is the layout engine for [Nue web framework](https://nuejs.org) providing both server-side templating and client-side reactive islands. | ||
Nue JS is a tiny (2.3kb minzipped) JavaScript library for building web interfaces. It is the core layout engine in [Nue](https://nuejs.org) providing both server-side templating and client-side reactive islands. | ||
## HTML microlibrary for UX developers | ||
Nue template syntax is designed for [UX developers](https://nuejs.org/docs/) who prefer to write user interfaces with clean, semantic HTML instead of JavaScript. Think Nue as standard HTML, that you can extend with custom HTML-based components. These components help you build modern web applications in a simple, declarative way. For example: | ||
## "It's just HTML" | ||
Nue uses a simple HTML-based template syntax that you can use for both server-side layouts and reactive, client-side components. For example: | ||
``` html | ||
```html | ||
<div class="{ type }"> | ||
@@ -25,52 +22,10 @@ <img src="{ img }"> | ||
If React is __"just JavaScript"__, then Nue is __"just HTML"__ because any valid HTML is also valid Nue. You can extend the standard HTML with [template expressions](https://nuejs.org/docs/reference/template-syntax.html) that help you build modern websites and web- applications in a simple, declarative way. | ||
If React is "Just JavaScript", then Nue is "Just HTML" because any valid HTML is also valid Nue. | ||
Nue is best suited for *UX developers* dealing with the [front of the frontend](https://bradfrost.com/blog/post/front-of-the-front-end-and-back-of-the-front-end-web-development/) and with topics like interaction design, accessibility, and user experience. | ||
### Links | ||
* [Template syntax](https://nuejs.org/docs/template-syntax.html) | ||
* [Reactive components](https://nuejs.org/docs/reactive-components.html) | ||
## Class- based | ||
Nue uses ES6 classes to make web development feel more natural and standards-based. Here is an example Nue- component with a `submit()` _instance method_: | ||
``` html | ||
<form @submit.prevent="submit"> | ||
<input type="email" name="email" placeholder="your@address.com" required> | ||
<button>Submit</button> | ||
<script> | ||
// input validation is natively taken care of by the browser | ||
async submit({ target }) { | ||
await fetch(`/api/leads?email=${target.email.value}`) | ||
location.href = '/thank-you' | ||
} | ||
</script> | ||
</form> | ||
``` | ||
The most notable thing is the `<script>` tag, which is now nested _inside_ the component. This is the place for your ES6 class variables and methods. | ||
ES6 classes make your code look amazingly compact and clean. You can add variables, methods, [getters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get), [setters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set), and `async` methods with the cute and short syntax. There are no hooks, effects, props, portals, watchers, provides, injects, suspension, or other unusual abstractions on your way. Learn the basics of HTML, CSS, and JavaScript and you are good to go. | ||
Learn the reasoning behind HTML- and class based syntax from our Blog article: [rethinking reactivity](https://nuejs.org/blog/rethinking-reactivity/) | ||
### Getting Started | ||
Please see https://nuejs.org/docs/ | ||
### The big picture | ||
The ultimate goal of Nue is to build a content first alternative to **Vercel** and **Netlify**, which is extremely fast and ridiculously easy to use. | ||
![Nue Roadmap](https://nuejs.org/img/roadmap4-big.png) | ||
#### Why Nue? | ||
- [Content first](https://nuejs.org/docs/why-nue/content-first.html) | ||
- [Extreme performance](https://nuejs.org/docs/why-nue/extreme-performance.html) | ||
- [Closer to standards](https://nuejs.org/docs/why-nue/closer-to-standards.html) | ||
### Contributing | ||
@@ -77,0 +32,0 @@ |
@@ -252,5 +252,4 @@ | ||
// constructor | ||
if (Impl) { | ||
impl = self.impl = new Impl(ctx) | ||
if (Impl) impl = self.impl = new Impl(ctx) | ||
// for | ||
@@ -260,4 +259,3 @@ impl.mountChild = self.mountChild | ||
impl.update = update | ||
} | ||
walk(root) | ||
@@ -277,3 +275,3 @@ | ||
append(to) { | ||
const wrap = document.createElement('b') | ||
const wrap = document.createElement('_') | ||
to.append(wrap) | ||
@@ -330,3 +328,7 @@ return self.mount(wrap) | ||
} else { | ||
self[key] = val | ||
if (Object.prototype.hasOwnProperty.call(impl, key)) { | ||
impl[key] = val | ||
} else { | ||
self[key] = val | ||
} | ||
} | ||
@@ -333,0 +335,0 @@ return true |
@@ -124,2 +124,3 @@ | ||
space: [' ', 'spacebar', 'space bar'], | ||
tab: ['tab'], | ||
up: ['arrowup'], | ||
@@ -202,2 +203,3 @@ down: ['arrowdown'], | ||
export function parse(src) { | ||
src = src.replace(/\r\n|\r/g, '\n') | ||
const { children } = mkdom(src) | ||
@@ -204,0 +206,0 @@ |
@@ -16,9 +16,9 @@ | ||
const SVG = 'animate animateMotion animateTransform circle clipPath defs desc ellipse\ | ||
feBlend feColorMatrix feComponentTransfer feComposite feConvolveMatrix feDiffuseLighting\ | ||
feDisplacementMap feDistantLight feDropShadow feFlood feFuncA feFuncB feFuncG feFuncR\ | ||
feGaussianBlur feImage feMerge feMergeNode feMorphology feOffset fePointLight feSpecularLighting\ | ||
feSpotLight feTile feTurbulence filter foreignObject g hatch hatchpath image line linearGradient\ | ||
marker mask metadata mpath path pattern polygon polyline radialGradient rect set stop style svg\ | ||
switch symbol text textPath title tspan use view'.split(' ') | ||
const SVG = 'animate animatemotion animatetransform circle clippath defs desc ellipse\ | ||
feblend fecolormatrix fecomponenttransfer fecomposite feconvolvematrix fediffuselighting\ | ||
fedisplacementmap fedistantlight fedropshadow feflood fefunca fefuncb fefuncg fefuncr\ | ||
fegaussianblur feimage femerge femergenode femorphology feoffset fepointlight fespecularlighting\ | ||
fespotlight fetile feturbulence filter foreignobject g hatch hatchpath image line lineargradient\ | ||
marker mask metadata mpath path pattern polygon polyline radialgradient rect set stop style svg\ | ||
switch symbol text textpath title tspan use view'.split(' ') | ||
@@ -37,3 +37,3 @@ STD.push(...SVG) | ||
const { attribs } = root | ||
const name = attribs['@name'] || attribs['data-name'] || attribs.id | ||
const name = attribs['@name'] || attribs['data-name'] // || attribs.id | ||
delete attribs['@name'] | ||
@@ -40,0 +40,0 @@ return name |
@@ -59,3 +59,3 @@ | ||
let val = attribs[key] | ||
if (!val) return | ||
if (val === null || val === undefined) return | ||
@@ -173,6 +173,7 @@ // TODO: check all non-strings here | ||
let child = comp.create({ ...data, ...attribs }, deps, node.children) || '' | ||
if (typeof child == 'string') child = parseDocument(child) | ||
// merge attributes | ||
const child = comp.create({ ...data, ...attribs }, deps, node.children) | ||
if (child.children.length == 1) mergeAttribs(child.firstChild.attribs, attribs) | ||
DOM.replaceElement(node, child) | ||
@@ -245,3 +246,3 @@ } | ||
if (attribs.for) { | ||
const html = data[attribs.for] | ||
const html = exec(setContext(attribs.for), data) | ||
if (html) DOM.replaceElement(node, mkdom(html)) | ||
@@ -302,2 +303,4 @@ else removeNode(node) | ||
const Impl = js[0] && exec(`class Impl { ${ js } }\n${global_js}`) | ||
// must be after getJS() | ||
const tmpl = getOuterHTML(node) | ||
@@ -356,2 +359,3 @@ | ||
export function parse(template) { | ||
template = template.replace(/\r\n|\r/g, '\n') | ||
const { children } = mkdom(template) | ||
@@ -383,3 +387,1 @@ const nodes = children.filter(el => el.type == 'tag') | ||
} | ||
@@ -104,10 +104,10 @@ | ||
'<p :for="({ name }, i) in items">{ i }. { name }</p>' : '<p>0. John</p><p>1. Alice</p>', | ||
'<p :for="({ name }, i) in items">{ i }. { name }</p>': '<p>0. John</p><p>1. Alice</p>', | ||
// loop custom tag | ||
'<show :for="el in items" :value="el.name"/> <b @name="show">{ value }</b>' : | ||
'<show :for="el in items" :value="el.name"/> <b @name="show">{ value }</b>': | ||
'<b>John</b><b>Alice</b>', | ||
// loop slots | ||
'<thing :for="el in items" :bind="el"><b>{ el.age }</b></thing><u @name="thing">{name}: <slot/></u>' : | ||
'<thing :for="el in items" :bind="el"><b>{ el.age }</b></thing><u @name="thing">{name}: <slot/></u>': | ||
'<u>John: <b>22</b></u><u>Alice: <b>33</b></u>', | ||
@@ -119,6 +119,8 @@ | ||
'<i :for="el in falsy">{el}</i>': '<i></i><i>false</i><i>0</i><i>NaN</i><i></i><i></i>' | ||
}, { | ||
items: [ { name: 'John', age: 22 }, { name: 'Alice', age: 33 }], | ||
items: [{ name: 'John', age: 22 }, { name: 'Alice', age: 33 }], | ||
person: { name: 'Nick', email: 'nick@acme.org', age: 10 }, | ||
nums: [-1, 0, 1], | ||
falsy: ['', false, 0, NaN, null, undefined], | ||
}) | ||
@@ -149,3 +151,3 @@ }) | ||
// :attr (:bind works the same on server side) | ||
'<dd :attr="person"></dd>': '<dd name="Nick" age="10"></dd>', | ||
'<dd :attr="person"></dd>': '<dd name="Nick" age="0"></dd>', | ||
@@ -162,6 +164,6 @@ '<hey :val/>': '<div is="hey">\n <script type="application/json">{"val":"1"}</script>\n</div>', | ||
}, { | ||
person: { name: 'Nick', age: 10 }, | ||
person: { name: 'Nick', age: 0 }, | ||
page: '<main>Hello</main>', | ||
nums: [1, 2], | ||
val: 1 | ||
val: 1, | ||
}) | ||
@@ -172,7 +174,12 @@ | ||
const GLOBAL_SCRIPT = ` | ||
const GLOBAL_FUNCTIONS = ` | ||
<script> | ||
// only functions are allowed globally. so no variables or import statements ATM | ||
function toLower(str) { | ||
return str.toLowerCase() | ||
} | ||
function getArray() { | ||
return [1, 2, 3] | ||
} | ||
</script> | ||
@@ -183,3 +190,9 @@ | ||
<p :for="num in iterator()">* { num }</p> | ||
<script> | ||
iterator() { | ||
return getArray() | ||
} | ||
lower(str) { | ||
@@ -192,7 +205,11 @@ return toLower(str) | ||
test('Global script', () => { | ||
const html = render(GLOBAL_SCRIPT, { title: 'Hey' }) | ||
const html = render(GLOBAL_FUNCTIONS, { title: 'Hey' }) | ||
expect(html).toStartWith('<div>') | ||
expect(html).toInclude('hey') | ||
expect(html).toInclude('<p>* 1</p><p>* 2</p>') | ||
}) | ||
const GA = ` | ||
@@ -227,3 +244,3 @@ <body> | ||
test('If sibling', () => { | ||
const els = [{ label: 'First'}] | ||
const els = [{ label: 'First' }] | ||
const html = render(IF_SIBLING, { els }) | ||
@@ -230,0 +247,0 @@ expect(html).toInclude('First') |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1584
80415
41
Updatedhtmlparser2@^9.1.0