-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
0.6.0: Enables more features and improves the developer experience fo…
…r fullstack rendering (SSR, CSR and Hydration)
- Loading branch information
Showing
13 changed files
with
359 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -154,7 +154,7 @@ Sample code: | |
_Requires Deno `1.35` or later._ | ||
```typescript | ||
import van from "https://deno.land/x/minivan@0.5.7/src/van-plate.js" | ||
import van from "https://deno.land/x/minivan@0.6.0/src/van-plate.js" | ||
|
||
const {a, body, li, p, ul} = van.tags | ||
|
||
|
@@ -195,7 +195,7 @@ _Requires Deno `1.35` or later._ | |
```typescript | ||
import { DOMParser } from "https://deno.land/x/[email protected]/deno-dom-wasm.ts" | ||
import van from "https://deno.land/x/minivan@0.5.7/src/mini-van.js" | ||
import van from "https://deno.land/x/minivan@0.6.0/src/mini-van.js" | ||
|
||
const document = new DOMParser().parseFromString("", "text/html")! | ||
const {tags, html} = van.vanWithDoc(document) | ||
|
@@ -235,16 +235,16 @@ Preview via [CodeSandbox](https://codesandbox.io/p/sandbox/github/vanjs-org/vanj | |
To get started on the client side, add the line below to your script: | ||
```javascript | ||
import van from "https://cdn.jsdelivr.net/gh/vanjs-org/mini-van/public/mini-van-0.5.7.min.js" | ||
import van from "https://cdn.jsdelivr.net/gh/vanjs-org/mini-van/public/mini-van-0.6.0.min.js" | ||
``` | ||
To code without ES6 modules, add the following line to your HTML file instead: | ||
```html | ||
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/vanjs-org/mini-van/public/mini-van-0.5.7.nomodule.min.js"></script> | ||
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/vanjs-org/mini-van/public/mini-van-0.6.0.nomodule.min.js"></script> | ||
``` | ||
Alternative, you can download the files ([`mini-van-0.5.7.min.js`](https://vanjs.org/autodownload?file=mini-van-0.5.7.min.js), [`mini-van-0.5.7.nomodule.min.js`](https://vanjs.org/autodownload?file=mini-van-0.5.7.nomodule.min.js)) and serve them locally. | ||
Alternative, you can download the files ([`mini-van-0.6.0.min.js`](https://vanjs.org/autodownload?file=mini-van-0.6.0.min.js), [`mini-van-0.6.0.nomodule.min.js`](https://vanjs.org/autodownload?file=mini-van-0.6.0.nomodule.min.js)) and serve them locally. | ||
You can find all relevant **Mini-Van** files in this [Download Table](https://vanjs.org/minivan#download-table). | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
export interface State<T> { | ||
val: T | ||
readonly oldVal: T | ||
readonly rawVal: T | ||
} | ||
|
||
// Defining readonly view of State<T> for covariance. | ||
// Basically we want StateView<string> to implement StateView<string | number> | ||
export type StateView<T> = Readonly<State<T>> | ||
|
||
export type Primitive = string | number | boolean | bigint | ||
|
||
export type PropValue = Primitive | ((e: any) => void) | null | ||
|
||
export type Props = Record<string, PropValue | StateView<PropValue> | (() => PropValue)> | ||
|
||
interface HasFirstChild {firstChild?: unknown} | ||
|
||
type NodeType<ElementType extends HasFirstChild> = | ||
Omit<ElementType["firstChild"], "after" | "before" | "remove" | "replaceWith"> | ||
|
||
export type ValidChildDomValue<ElementType extends HasFirstChild, TextNodeType> = | ||
Primitive | ElementType | NodeType<ElementType> | TextNodeType | null | undefined | ||
|
||
export type BindingFunc<ElementType extends HasFirstChild, TextNodeType> = | ||
| ((dom?: ElementType | TextNodeType) => ValidChildDomValue<ElementType, TextNodeType>) | ||
| ((dom?: ElementType) => ElementType) | ||
|
||
export type ChildDom<ElementType extends HasFirstChild, TextNodeType> = | ||
| ValidChildDomValue<ElementType, TextNodeType> | ||
| StateView<Primitive | null | undefined> | ||
| BindingFunc<ElementType, TextNodeType> | ||
| readonly ChildDom<ElementType, TextNodeType>[] | ||
|
||
type AddFunc<ElementType extends HasFirstChild, TextNodeType> = | ||
(dom: ElementType, ...children: readonly ChildDom<ElementType, TextNodeType>[]) => ElementType | ||
|
||
export type TagFunc<ElementType extends HasFirstChild, TextNodeType, ResultType = ElementType> = | ||
(first?: Props | ChildDom<ElementType, TextNodeType>, | ||
...rest: readonly ChildDom<ElementType, TextNodeType>[]) => ResultType | ||
|
||
type Tags<ElementType extends HasFirstChild, TextNodeType> = | ||
Readonly<Record<string, TagFunc<ElementType, TextNodeType>>> | ||
|
||
// Tags type in browser context, which contains the signatures to tag functions that return | ||
// specialized DOM elements. | ||
type BrowserTags = Tags<Element, Text> & { | ||
[K in keyof HTMLElementTagNameMap]: TagFunc<Element, Text, HTMLElementTagNameMap[K]> | ||
} | ||
|
||
declare function state<T>(): State<T> | ||
declare function state<T>(initVal: T): State<T> | ||
|
||
export interface VanObj<ElementType extends HasFirstChild, TextNodeType> { | ||
readonly state: typeof state | ||
readonly derive: <T>(f: () => T) => State<T> | ||
readonly add: AddFunc<ElementType, TextNodeType> | ||
readonly tags: Tags<ElementType, TextNodeType> & ((namespaceURI: string) => Tags<ElementType, TextNodeType>) | ||
|
||
// Mini-Van specific API | ||
html: (first?: Props | ChildDom<ElementType, TextNodeType>, | ||
...rest: readonly ChildDom<ElementType, TextNodeType>[]) => string | ||
} | ||
|
||
export interface Van extends VanObj<Element, Text> { | ||
readonly vanWithDoc: <ElementType extends HasFirstChild, TextNodeType>(doc: { | ||
createElement(s: any): ElementType, | ||
createTextNode(s: any): TextNodeType, | ||
}) => VanObj<ElementType, TextNodeType> | ||
readonly tags: BrowserTags & ((namespaceURI: string) => Tags<Element, Text>) | ||
} | ||
|
||
declare const van: Van | ||
|
||
export default van |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/// <reference types="./mini-van.d.ts" /> | ||
|
||
// This file consistently uses `let` keyword instead of `const` for reducing the bundle size. | ||
|
||
// Aliasing some builtin symbols to reduce the bundle size. | ||
let protoOf = Object.getPrototypeOf, _undefined, funcProto = protoOf(protoOf) | ||
|
||
let stateProto = {get oldVal() { return this.val }, get rawVal() { return this.val }} | ||
let objProto = protoOf(stateProto) | ||
|
||
let state = initVal => ({__proto__: stateProto, val: initVal}) | ||
|
||
let plainValue = (k, v) => { | ||
let protoOfV = protoOf(v ?? 0) | ||
return protoOfV === stateProto ? v.val : | ||
protoOfV !== funcProto || k?.startsWith("on") ? v : v() | ||
} | ||
|
||
let add = (dom, ...children) => | ||
(dom.append(...children.flat(Infinity) | ||
.map(plainValue.bind(_undefined, _undefined)) | ||
.filter(c => c != _undefined)), | ||
dom) | ||
|
||
let vanWithDoc = doc => { | ||
let tag = (ns, name, ...args) => { | ||
let [props, ...children] = protoOf(args[0] ?? 0) === objProto ? args : [{}, ...args] | ||
let dom = ns ? doc.createElementNS(ns, name) : doc.createElement(name) | ||
for (let [k, v] of Object.entries(props)) { | ||
let plainV = plainValue(k, v) | ||
// Disable setting attribute for function-valued properties (mostly event handlers), | ||
// as they're usually not useful for SSR (server-side rendering). | ||
protoOf(plainV) !== funcProto && dom.setAttribute(k, plainV) | ||
} | ||
return add(dom, ...children) | ||
} | ||
|
||
let handler = ns => ({get: (_, name) => tag.bind(_undefined, ns, name)}) | ||
let tags = new Proxy(ns => new Proxy(tag, handler(ns)), handler()) | ||
|
||
return { | ||
add, tags, state, derive: f => state(f()), | ||
html: (...args) => "<!DOCTYPE html>" + tags.html(...args).outerHTML, | ||
} | ||
} | ||
|
||
export default {"vanWithDoc": vanWithDoc, | ||
...vanWithDoc(typeof window !== "undefined" ? window.document : null)} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
export interface State<T> { | ||
val: T | ||
readonly oldVal: T | ||
readonly rawVal: T | ||
} | ||
|
||
// Defining readonly view of State<T> for covariance. | ||
// Basically we want StateView<string> to implement StateView<string | number> | ||
export type StateView<T> = Readonly<State<T>> | ||
|
||
export type Primitive = string | number | boolean | bigint | ||
|
||
export type PropValue = Primitive | ((e: any) => void) | null | ||
|
||
export type Props = Record<string, PropValue | StateView<PropValue> | (() => PropValue)> | ||
|
||
interface HasFirstChild {firstChild?: unknown} | ||
|
||
type NodeType<ElementType extends HasFirstChild> = | ||
Omit<ElementType["firstChild"], "after" | "before" | "remove" | "replaceWith"> | ||
|
||
export type ValidChildDomValue<ElementType extends HasFirstChild, TextNodeType> = | ||
Primitive | ElementType | NodeType<ElementType> | TextNodeType | null | undefined | ||
|
||
export type BindingFunc<ElementType extends HasFirstChild, TextNodeType> = | ||
| ((dom?: ElementType | TextNodeType) => ValidChildDomValue<ElementType, TextNodeType>) | ||
| ((dom?: ElementType) => ElementType) | ||
|
||
export type ChildDom<ElementType extends HasFirstChild, TextNodeType> = | ||
| ValidChildDomValue<ElementType, TextNodeType> | ||
| StateView<Primitive | null | undefined> | ||
| BindingFunc<ElementType, TextNodeType> | ||
| readonly ChildDom<ElementType, TextNodeType>[] | ||
|
||
type AddFunc<ElementType extends HasFirstChild, TextNodeType> = | ||
(dom: ElementType, ...children: readonly ChildDom<ElementType, TextNodeType>[]) => ElementType | ||
|
||
export type TagFunc<ElementType extends HasFirstChild, TextNodeType, ResultType = ElementType> = | ||
(first?: Props | ChildDom<ElementType, TextNodeType>, | ||
...rest: readonly ChildDom<ElementType, TextNodeType>[]) => ResultType | ||
|
||
type Tags<ElementType extends HasFirstChild, TextNodeType> = | ||
Readonly<Record<string, TagFunc<ElementType, TextNodeType>>> | ||
|
||
// Tags type in browser context, which contains the signatures to tag functions that return | ||
// specialized DOM elements. | ||
type BrowserTags = Tags<Element, Text> & { | ||
[K in keyof HTMLElementTagNameMap]: TagFunc<Element, Text, HTMLElementTagNameMap[K]> | ||
} | ||
|
||
declare function state<T>(): State<T> | ||
declare function state<T>(initVal: T): State<T> | ||
|
||
export interface VanObj<ElementType extends HasFirstChild, TextNodeType> { | ||
readonly state: typeof state | ||
readonly derive: <T>(f: () => T) => State<T> | ||
readonly add: AddFunc<ElementType, TextNodeType> | ||
readonly tags: Tags<ElementType, TextNodeType> & ((namespaceURI: string) => Tags<ElementType, TextNodeType>) | ||
|
||
// Mini-Van specific API | ||
html: (first?: Props | ChildDom<ElementType, TextNodeType>, | ||
...rest: readonly ChildDom<ElementType, TextNodeType>[]) => string | ||
} | ||
|
||
export interface Van extends VanObj<Element, Text> { | ||
readonly vanWithDoc: <ElementType extends HasFirstChild, TextNodeType>(doc: { | ||
createElement(s: any): ElementType, | ||
createTextNode(s: any): TextNodeType, | ||
}) => VanObj<ElementType, TextNodeType> | ||
readonly tags: BrowserTags & ((namespaceURI: string) => Tags<Element, Text>) | ||
} | ||
|
||
declare const van: Van | ||
|
||
export default van |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
(() => { | ||
// mini-van.js | ||
var protoOf = Object.getPrototypeOf; | ||
var _undefined; | ||
var funcProto = protoOf(protoOf); | ||
var stateProto = { get oldVal() { | ||
return this.val; | ||
}, get rawVal() { | ||
return this.val; | ||
} }; | ||
var objProto = protoOf(stateProto); | ||
var state = (initVal) => ({ __proto__: stateProto, val: initVal }); | ||
var plainValue = (k, v) => { | ||
let protoOfV = protoOf(v ?? 0); | ||
return protoOfV === stateProto ? v.val : protoOfV !== funcProto || k?.startsWith("on") ? v : v(); | ||
}; | ||
var add = (dom, ...children) => (dom.append(...children.flat(Infinity).map(plainValue.bind(_undefined, _undefined)).filter((c) => c != _undefined)), dom); | ||
var vanWithDoc = (doc) => { | ||
let tag = (ns, name, ...args) => { | ||
let [props, ...children] = protoOf(args[0] ?? 0) === objProto ? args : [{}, ...args]; | ||
let dom = ns ? doc.createElementNS(ns, name) : doc.createElement(name); | ||
for (let [k, v] of Object.entries(props)) { | ||
let plainV = plainValue(k, v); | ||
protoOf(plainV) !== funcProto && dom.setAttribute(k, plainV); | ||
} | ||
return add(dom, ...children); | ||
}; | ||
let handler = (ns) => ({ get: (_, name) => tag.bind(_undefined, ns, name) }); | ||
let tags = new Proxy((ns) => new Proxy(tag, handler(ns)), handler()); | ||
return { | ||
add, | ||
tags, | ||
state, | ||
derive: (f) => state(f()), | ||
html: (...args) => "<!DOCTYPE html>" + tags.html(...args).outerHTML | ||
}; | ||
}; | ||
var mini_van_default = { | ||
"vanWithDoc": vanWithDoc, | ||
...vanWithDoc(typeof window !== "undefined" ? window.document : null) | ||
}; | ||
|
||
// mini-van.forbundle.js | ||
window.van = mini_van_default; | ||
})(); |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
0.5.7 | ||
0.6.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,29 @@ | ||
export {}; | ||
export const env = {}; | ||
export const registerEnv = (input) => { | ||
if (input.van) | ||
env.van = input.van; | ||
if (input.vanX) | ||
env.vanX = input.vanX; | ||
}; | ||
export const dummyVanX = { | ||
calc: f => f(), | ||
reactive: obj => obj, | ||
noreactive: obj => obj, | ||
stateFields: (obj) => { | ||
const states = Array.isArray(obj) ? [] : { __proto__: Object.getPrototypeOf(obj) }; | ||
for (const [k, v] of Object.entries(obj)) | ||
states[k] = env.van.state(v); | ||
return states; | ||
}, | ||
raw: obj => obj, | ||
list: (container, items, itemFunc) => { | ||
if (container instanceof Function) | ||
container = container(); | ||
const isArray = Array.isArray(items); | ||
for (const [k, v] of Object.entries(items)) | ||
env.van.add(container, itemFunc(env.van.state(v), () => { }, (isArray ? Number(k) : k))); | ||
return container; | ||
}, | ||
replace: obj => obj, | ||
compact: obj => obj, | ||
}; |
Oops, something went wrong.