I'm Tao Xin (辛韬), a senior staff software engineer at Google, and I'm the founder of VanJS. I would like to talk about 2 central questions about VanJS: What VanJS really is, and why I think it's good to the world.
So, what is VanJS? Well, it's a reactive UI framework. It's more than 100 times smaller than React. It doesn't require installation, configuration, dependencies or transpiling to use. But I think, in a nutshell, the best way to describe it is: VanJS is the scripting language for UI, just like bash is the scripting language for terminal.
Ever since the birth of GUI, there is no shortage of UI frameworks: MFC, Win Form, WPF, Qt, Flutter, SwiftUI, Jetpack Compose, React, React Native, to name a few. They enabled us to build highly sophisticated UI apps. But on the other hand, frameworks and tools themselves could be the entry barrier for UI programming: high-specialized IDEs, lengthy tutorials, mysterious problems that might arise here and there, being forced to program in a designated style, and most importantly, ONLY people with specialized skills can work on it. Even JavaScript, with "Script" in its name, is trying to become a compiled language: JSX, TSX, transpiling, and plugins/extensions to allow us to work with the transpiled code.
On the flip side, the default way for programmers to interact with computers remains the same for over 50 years - shells, CLI programs, and sometimes, ASCII arts. Why? Is terminal inherently better than GUI? Or does it just make programmers look cooler? I think the fundamental reason that lies behind, is the power of scripting, the power to start coding immediately in any environment, the power to build useful things with just a few lines of code, the power to easily assemble various code snippets together.
Being the scripting language for UI, is the fundamental principle that guides the design of VanJS. It's based on JavaScript so that it can work in as many environments as possibles, not only for websites, but also for webviews which most major OSes support. It has declarative composing API and reactive state binding as it enables an easier way to describe comprehensive UI logic within just a few lines of code. It has strictly 0 dependencies so that it can be used right after the code is typed. It's JSX-free thus REPL can be easily done in the browser console.
So, why is VanJS good to the world? I think the world needs a scripting way to build UI, and there are way more scenarios where UI can be more beneficial than people might have realized, for personal utilities, for teamwide tools, and for user-facing products as well. We are quite used to the categorization between front-end engineers and back-end engineers, and we are quite used to the notion that back-end engineers will never do UI. We think only a very small number of people need to know how to build UI.
But, is it really the case? I've been a back-end engineer for more than a decade. I had been leading a team which manages 100+ data processing pipelines and datasets produced by them. I felt, for many times, that we really needed a way to visualize the status of the pipelines and datasets. "But, ...", pushbacks would immediately arise after the idea, "We're not a front end team. We shouldn't do it. We don't have the expertise.", I think here, "We don't have the expertise", doesn't really mean the team is not technical capable of programming the UI logic. What it actually means is, "We don't really have the experience of dealing with mysterious, and oftentimes undocumented issues here and there that might only occur in our specific development environment, and we can't accurately estimate the amount of time needed to get them resolved." We tried to hire an intern to do the work, but the work couldn't finish because of waves of issues in the internal build systems.
I am never a front-end engineer, and I haven't used any UI framework. But I built lots of UI apps, and I will continue doing it, in a scripting way. And I believe anyone can do that as well.
I'm hoping open sourcing VanJS can help us one step closer to that vision. Hope you can enjoy!
Thanks!
-- Tao Xin
"Who do you truly serve?" "The Realm. Someone must."
VanJS was built by Tao Xin during his personal time while being employed as a full-time employee at Google. The project was submitted to Invention Assignment Review Committee at Google where Google, upon reviewing the designated scopes, waived its copyright claims. Thus the copyright of VanJS belongs to its creator, all rights reserved. VanJS is open sourced under MIT license. VanJS aims to build a better world by reducing the entry barrier for UI programming, with no intention or plan on commercialization whatsoever.
The project was developed, and will be maintained with strict compliance to Google's Outside Work Guidelines as well as requirements imposed by Google's copyright waiver. VanJS was created, and will continue to be maintained, without any use of internal Alphabet resources, including but not limited to, corporate hardware equipments, software licenses, internal tools, internal corporate mailing lists, corporate accounts, proprietary or confidential information, trademarks or brand features of any Alphabet company. Alphabet does not sponsor, endorse or in any form affiliate with VanJS project. To comply with the conflict of interests provisions, Tao Xin does not advocate the adoption of VanJS within Alphabet.
As a new UI framework, we put heavy focus on the reliability of the framework. For every single release of VanJS, below is the list of tests that will be run through:
A browser-based test suite, with ~500 test cases, covering different versions of VanJS files (.min.js, .debug.js, .nomodule.min.js, etc.), including the coverage of advanced behavior such as garbage collection, as well as error messages shown in the debug mode.
Examples used in VanJS tutorial are also covered in the browser-based test suite.
The browser-based test suite was implemented in TypeScript, thus TypeScript integration is covered.
Sample applications will keep working in every single VanJS release, including applications implemented in TypeScript (which covers TypeScript integration).
For every single release of Mini-Van, below is the list of tests that will be run through:
A browser-based test suite, with 70+ test cases, covering different versions of Mini-Van files (.min.js, .nomodule.min.js, etc.)
The browser-based test suite was implemented in TypeScript, thus TypeScript integration is covered.
A Deno test suite for van-plate mode, covering Deno integration.
The entire site of vanjs.org was generated with Mini-Van with TypeScript files defining all web pages. Source code can be found here.
The sample code snippets throughout this website follow a minimalist approach when it comes to coding styles. When readability is not impacted, we are leaning towards the choice that leads to more concise code, with the belief that brevity and simplicity generally make the code easier to read and write. This means that we're consciously choosing certain coding styles throughout this website: such as omitting optional semicolons, naked if statements, usage of ternary operator when appropriate, etc.
On the other hand, we acknowledge that different people might hold a somewhat different opinion regarding certain coding style choices, and some are among hotly debated issues among programmers. We understand the arguments from the other side that certain coding styles, might occasionally lead to slightly more misleading error messages for incorrect implementation in limited situations. As an unopinionated framework, VanJS doesn't take side on coding styles. If some style in the sample code doesn't align with your personal preference or your team's common practice, feel free to make the corresponding styling changes after copy/past-ing the sample code.
We believe that VanJS is a good illustration of how modern UI frameworks work under the hood. The simplicity in its design, and conciseness in its implementation make it the perfect learning material for the core fundamentals of reactive UI programming, as well as advanced techniques in modern JavaScript. Here we recommend this 7-minute video which breaks down and elucidates the underlying principles of VanJS codebase.
On the other hand, we do realize that some parts of VanJS codebase might be hard to read for some people. We believe that this is mostly because VanJS has chosen some programming techniques and language constructs that are not frequently used in the JavaScript community, despite their usefulness. Here we provide a brief explanation of those in the hope of easing the understanding of VanJS codebase, its official extensions, and its sample applications.
JavaScript language features:
Proxy: A type of JavaScript objects that allow you to intercept and redefine common operations of another object, such as getting and setting properties. The van.tags object in VanJS leverages this technique to allow you declaring DOM trees like HTML but without the need of JSX. The operation of getting any properties of van.tags will be intercepted and redefined to a function that creates an HTML element with the property name as its tag name. e.g.: van.tags.div() will create a <div> element. In addition, the reactive object in VanX leverages Proxy so that getting and setting its fields will be redefined to getting and setting values of the underlying states.
prototype: The foundation of OOP in JavaScript. Any object in JavaScript can specify a prototype object so that property access falls back to the prototype if the property doesn't exist in the object itself. Prototype is a lightweight alternative to classes in JavaScript. VanJS is using prototype instead of classes to keep its size small.
Less frequently used JavaScript syntaxes:
Ternary operator: Ternary operator is way to define conditional computations. Sometimes it can be used as an alternative to if...else statement for more concise and declarative code. For instance, the following code:
Even more complex if...else if...else statement can be simplified with ternary operators as well. For instance, the following code in the Calculator App:
Comma operator (,): Comma operator evaluates each of its operands sequentially and returns the last value. VanJS leverages comma operators in a few places to make the code concise. For instance, the logic of binding a state to a DOM property:
bind(() => {
- setter(v.val)
- return dom
-})
-
is simplified to bind(() => (setter(v.val), dom)) in van.js (don't confuse this with calling a function with 2 arguments).
if (a !== null && a !== undefined) {
- return a
-} else {
- return b
-}
-
VanJS leverages this operator in a few places to simplify code. One notable example in van.js is function addAndScheduleOnFirst:
let addAndScheduleOnFirst = (set, s, f, waitMs) =>
- (set ?? (setTimeout(f, waitMs), new Set)).add(s)
-
which is equivalent to:
let addAndScheduleOnFirst = (set, s, f, waitMs) => {
- if (set === null || set === undefined) {
- setTimeout(f, waitMs)
- set = new Set
- }
- set.add(s)
- return set
-}
-
Short-circuit evaluation for && and ||: Sometimes, we're leveraging the short-circuit evaluation for && and || to simplify code. For instance, in van-x.js, refDelete(obj[statesSym], name) && onDelete(obj, name) is equivalent to:
if (refDelete(obj[statesSym], name)) {
- onDelete(obj, name)
-}
-
VanJS is short for Vanilla JavaScript, which is a metaphor that VanJS provides an abbreviated way to write Vanilla JavaScript code. Meanwhile, the logo of VanJS is a symbolic vanilla ice cream, which means VanJS = Vanilla JavaScript + syntax Sugar.
Under the hood, VanJS stays truthful to Vanilla JavaScript as close as possible, as there is no transpiling, virtual DOM or any hidden logic. VanJS code can be translated to Vanilla JavaScript code in a very straightforward way. For instance, the following VanJS code:
a({href: "https://vanjs.org"}, "🍦 VanJS")
is just an abbreviated/sugared form of following code in Vanilla Javascript:
I'm Tao Xin (辛韬), a senior staff software engineer at Google, and I'm the founder of VanJS. I would like to talk about 2 central questions about VanJS: What VanJS really is, and why I think it's good to the world.
So, what is VanJS? Well, it's a reactive UI framework. It's more than 100 times smaller than React. It doesn't require installation, configuration, dependencies or transpiling to use. But I think, in a nutshell, the best way to describe it is: VanJS is the scripting language for UI, just like bash is the scripting language for terminal.
Ever since the birth of GUI, there is no shortage of UI frameworks: MFC, Win Form, WPF, Qt, Flutter, SwiftUI, Jetpack Compose, React, React Native, to name a few. They enabled us to build highly sophisticated UI apps. But on the other hand, frameworks and tools themselves could be the entry barrier for UI programming: high-specialized IDEs, lengthy tutorials, mysterious problems that might arise here and there, being forced to program in a designated style, and most importantly, ONLY people with specialized skills can work on it. Even JavaScript, with "Script" in its name, is trying to become a compiled language: JSX, TSX, transpiling, and plugins/extensions to allow us to work with the transpiled code.
On the flip side, the default way for programmers to interact with computers remains the same for over 50 years - shells, CLI programs, and sometimes, ASCII arts. Why? Is terminal inherently better than GUI? Or does it just make programmers look cooler? I think the fundamental reason that lies behind, is the power of scripting, the power to start coding immediately in any environment, the power to build useful things with just a few lines of code, the power to easily assemble various code snippets together.
Being the scripting language for UI, is the fundamental principle that guides the design of VanJS. It's based on JavaScript so that it can work in as many environments as possibles, not only for websites, but also for webviews which most major OSes support. It has declarative composing API and reactive state binding as it enables an easier way to describe comprehensive UI logic within just a few lines of code. It has strictly 0 dependencies so that it can be used right after the code is typed. It's JSX-free thus REPL can be easily done in the browser console.
So, why is VanJS good to the world? I think the world needs a scripting way to build UI, and there are way more scenarios where UI can be more beneficial than people might have realized, for personal utilities, for teamwide tools, and for user-facing products as well. We are quite used to the categorization between front-end engineers and back-end engineers, and we are quite used to the notion that back-end engineers will never do UI. We think only a very small number of people need to know how to build UI.
But, is it really the case? I've been a back-end engineer for more than a decade. I had been leading a team which manages 100+ data processing pipelines and datasets produced by them. I felt, for many times, that we really needed a way to visualize the status of the pipelines and datasets. "But, ...", pushbacks would immediately arise after the idea, "We're not a front end team. We shouldn't do it. We don't have the expertise.", I think here, "We don't have the expertise", doesn't really mean the team is not technical capable of programming the UI logic. What it actually means is, "We don't really have the experience of dealing with mysterious, and oftentimes undocumented issues here and there that might only occur in our specific development environment, and we can't accurately estimate the amount of time needed to get them resolved." We tried to hire an intern to do the work, but the work couldn't finish because of waves of issues in the internal build systems.
I am never a front-end engineer, and I haven't used any UI framework. But I built lots of UI apps, and I will continue doing it, in a scripting way. And I believe anyone can do that as well.
I'm hoping open sourcing VanJS can help us one step closer to that vision. Hope you can enjoy!
Thanks!
-- Tao Xin
"Who do you truly serve?" "The Realm. Someone must."
VanJS was built by Tao Xin during his personal time while being employed as a full-time employee at Google. The project was submitted to Invention Assignment Review Committee at Google where Google, upon reviewing the designated scopes, waived its copyright claims. Thus the copyright of VanJS belongs to its creator, all rights reserved. VanJS is open sourced under MIT license. VanJS aims to build a better world by reducing the entry barrier for UI programming, with no intention or plan on commercialization whatsoever.
The project was developed, and will be maintained with strict compliance to Google's Outside Work Guidelines as well as requirements imposed by Google's copyright waiver. VanJS was created, and will continue to be maintained, without any use of internal Alphabet resources, including but not limited to, corporate hardware equipments, software licenses, internal tools, internal corporate mailing lists, corporate accounts, proprietary or confidential information, trademarks or brand features of any Alphabet company. Alphabet does not sponsor, endorse or in any form affiliate with VanJS project. To comply with the conflict of interests provisions, Tao Xin does not advocate the adoption of VanJS within Alphabet.
As a new UI framework, we put heavy focus on the reliability of the framework. For every single release of VanJS, below is the list of tests that will be run through:
A browser-based test suite, with ~500 test cases, covering different versions of VanJS files (.min.js, .debug.js, .nomodule.min.js, etc.), including the coverage of advanced behavior such as garbage collection, as well as error messages shown in the debug mode.
Examples used in VanJS tutorial are also covered in the browser-based test suite.
The browser-based test suite was implemented in TypeScript, thus TypeScript integration is covered.
Sample applications will keep working in every single VanJS release, including applications implemented in TypeScript (which covers TypeScript integration).
For every single release of Mini-Van, below is the list of tests that will be run through:
A browser-based test suite, with 70+ test cases, covering different versions of Mini-Van files (.min.js, .nomodule.min.js, etc.)
The browser-based test suite was implemented in TypeScript, thus TypeScript integration is covered.
A Deno test suite for van-plate mode, covering Deno integration.
The entire site of vanjs.org was generated with Mini-Van with TypeScript files defining all web pages. Source code can be found here.
The sample code snippets throughout this website follow a minimalist approach when it comes to coding styles. When readability is not impacted, we are leaning towards the choice that leads to more concise code, with the belief that brevity and simplicity generally make the code easier to read and write. This means that we're consciously choosing certain coding styles throughout this website: such as omitting optional semicolons, naked if statements, usage of ternary operator when appropriate, etc.
On the other hand, we acknowledge that different people might hold a somewhat different opinion regarding certain coding style choices, and some are among hotly debated issues among programmers. We understand the arguments from the other side that certain coding styles, might occasionally lead to slightly more misleading error messages for incorrect implementation in limited situations. As an unopinionated framework, VanJS doesn't take side on coding styles. If some style in the sample code doesn't align with your personal preference or your team's common practice, feel free to make the corresponding styling changes after copy/past-ing the sample code.
We believe that VanJS is a good illustration of how modern UI frameworks work under the hood. The simplicity in its design, and conciseness in its implementation make it the perfect learning material for the core fundamentals of reactive UI programming, as well as advanced techniques in modern JavaScript. Here we recommend this 7-minute video which breaks down and elucidates the underlying principles of VanJS codebase.
On the other hand, we do realize that some parts of VanJS codebase might be hard to read for some people. We believe that this is mostly because VanJS has chosen some programming techniques and language constructs that are not frequently used in the JavaScript community, despite their usefulness. Here we provide a brief explanation of those in the hope of easing the understanding of VanJS codebase, its official extensions, and its sample applications.
JavaScript language features:
Proxy: A type of JavaScript objects that allow you to intercept and redefine common operations of another object, such as getting and setting properties. The van.tags object in VanJS leverages this technique to allow you declaring DOM trees like HTML but without the need of JSX. The operation of getting any properties of van.tags will be intercepted and redefined to a function that creates an HTML element with the property name as its tag name. e.g.: van.tags.div() will create a <div> element. In addition, the reactive object in VanX leverages Proxy so that getting and setting its fields will be redefined to getting and setting values of the underlying states.
prototype: The foundation of OOP in JavaScript. Any object in JavaScript can specify a prototype object so that property access falls back to the prototype if the property doesn't exist in the object itself. Prototype is a lightweight alternative to classes in JavaScript. VanJS is using prototype instead of classes to keep its size small.
Less frequently used JavaScript syntaxes:
Ternary operator: Ternary operator is way to define conditional computations. Sometimes it can be used as an alternative to if...else statement for more concise and declarative code. For instance, the following code:
Even more complex if...else if...else statement can be simplified with ternary operators as well. For instance, the following code in the Calculator App:
Comma operator (,): Comma operator evaluates each of its operands sequentially and returns the last value. VanJS leverages comma operators in a few places to make the code concise. For instance, the logic of binding a state to a DOM property:
bind(() => {
- setter(v.val)
- return dom
-})
-
is simplified to bind(() => (setter(v.val), dom)) in van.js (don't confuse this with calling a function with 2 arguments).
if (a !== null && a !== undefined) {
- return a
-} else {
- return b
-}
-
VanJS leverages this operator in a few places to simplify code. One notable example in van.js is function addAndScheduleOnFirst:
let addAndScheduleOnFirst = (set, s, f, waitMs) =>
- (set ?? (setTimeout(f, waitMs), new Set)).add(s)
-
which is equivalent to:
let addAndScheduleOnFirst = (set, s, f, waitMs) => {
- if (set === null || set === undefined) {
- setTimeout(f, waitMs)
- set = new Set
- }
- set.add(s)
- return set
-}
-
Short-circuit evaluation for && and ||: Sometimes, we're leveraging the short-circuit evaluation for && and || to simplify code. For instance, in van-x.js, refDelete(obj[statesSym], name) && onDelete(obj, name) is equivalent to:
if (refDelete(obj[statesSym], name)) {
- onDelete(obj, name)
-}
-
VanJS is short for Vanilla JavaScript, which is a metaphor that VanJS provides an abbreviated way to write Vanilla JavaScript code. Meanwhile, the logo of VanJS is a symbolic vanilla ice cream, which means VanJS = Vanilla JavaScript + syntax Sugar.
Under the hood, VanJS stays truthful to Vanilla JavaScript as close as possible, as there is no transpiling, virtual DOM or any hidden logic. VanJS code can be translated to Vanilla JavaScript code in a very straightforward way. For instance, the following VanJS code:
a({href: "https://vanjs.org"}, "🍦 VanJS")
is just an abbreviated/sugared form of following code in Vanilla Javascript:
In tag functions, while assigning values from props parameter to the created HTML element, there are 2 ways of doing it: via HTML attributes (dom.setAttribute(<key>, <value>)), or via the properties of the created HTML element (dom[<key>] = <value>). VanJS follows a consistent rule that makes sense for most use cases regarding which option to choose: when a settable property exists in a given <key> for the specific element type, we will assign the value via property, otherwise we will assign the value via attribute.
For instance, input({type: "text", value: "Hello 🍦VanJS"}) will create an input box with Hello 🍦VanJS as the value of the value property, while div({"data-index": 1}) will create the tag: <div data-index="1"></div>.
Note that, for readonly properties of HTML elements, we will still assign props values via setAttribute. For instance, in the code snippet below, the list of the <input> element is set via setAttribute:
NOTE: for Mini-Van, since 0.4.0, we consistently assign the props values via setAttribute for all property keys in tag functions. This is because for SSR (server-side rendering), which is Mini-Van's primary use case, setting the properties of a DOM node won't be visible in the rendered HTML string unless the action of setting the property itself will also set the corresponding HTML attribute (e.g.: setting the id property of a DOM node will also set the id attribute). This is helpful as input({type: "text", value: "value"}) can be rendered as <input type="text" value="value"> in Mini-Van but would be rendered as <input type="text"> if we set the property value via DOM property.
We might be prompted to assign a DOM node to a State object, especially when the State object is used as a State-typed child node. However, this is problematic when the state is bound in multiple places, like the example below:
In this example, if we click the "Turn Bold" button, the first "VanJS" text will disappear, which is unexpected. This is because the same DOM node b("VanJS") is used twice in the DOM tree. For this reason, an error will be thrown in van-{version}.debug.js whenever we assign a DOM node to a State object.
More granular State objects can help state bindings be more locally scoped, which make reactive UI updates more efficient by eliminating unnecessary DOM tree construction and replacement.
道生一,一生二,二生三,三生万物 (Tao derives one, one derives two, two derive three, and three derive everything)
-- 老子,道德经
A broad set of advanced state derivation (derived states and side effects) can indeed be defined with van.derive, as illustrated in the following piece of code:
const fullName = van.state(localStorage.getItem("fullName") ?? "Tao Xin")
-
-// State persistence with `localStorage`
-van.derive(() => localStorage.setItem("fullName", fullName.val))
-
-// Defining multiple derived states
-const firstName = van.state(), lastName = van.state()
-van.derive(() => [firstName.val, lastName.val] = fullName.val.split(" "))
-
-const elapsed = van.state(0)
-setInterval(() => elapsed.val += .01, 10)
-
-// Same as `elapsed`, but delay the state propagation by 1s
-const delayed = van.state(0)
-van.derive(() => setTimeout(v => delayed.val = v, 1000, elapsed.val))
-
-// Same as `elapsed`, but throttle the state update to every 100ms
-const throttled = van.state(0)
-setInterval(() => throttled.val = elapsed.val, 100)
-
-// Generate a data stream for all value updates of a given state `s`
-const streamOf = s => {
- let resolver
- van.derive(() => resolver ? resolver({value: s.val, done: false}) : s.val)
- return {
- [Symbol.asyncIterator]: () => ({
- next: () => new Promise(resolve => resolver = resolve)
- })
- }
-}
-
-(async () => {
- // To subscribe the data stream
- for await (const v of streamOf(throttled)) {
- console.log("elapsed: ", v)
- }
- // You can also chain the data stream with `map`, `filter`, etc. by integrating with
- // rubico (https://rubico.land) or wu.js (https://fitzgen.github.io/wu.js/).
-})()
-
In State-derived properties and State-derived child nodes, it is guaranteed that the binding function will (only) be triggered when the dependency states change. This is true even for complex binding functions, who have different dependency states under different conditions.
For instance, the binding function () => cond.val ? a.val + b.val : c.val + d.val will (only) be triggered by updates of state a, b and cond if cond.val is true, and will (only) be triggered by updates of state c, d and cond if cond.val is false. This can be illustrated with the code below:
There is garbage collection mechanism implemented in VanJS to recycle obsolete state bindings. To illustrate the necessity of garbage collection, let's take a look at the code below:
In this piece of code, the TextDiv component has a <div> element whose only child is bound to a boolean state - renderPre, which determines whether the <div> has a <pre> or <span> child. Inside the child element, the underlying text is bound to a string state - text. Whenever the value of renderPre is toggled, a new version of the <div> element will be generated, and we will add a new binding from text state to the child text node of the newly created <div> element.
Without proper garbage collection implemented, text state will eventually be bound to many text nodes after renderPre is toggled many times. All the of bindings, except for the most recently added one, are actually obsolete, as they bind the text state to a text node that is not currently being used. i.e.: disconnected from the document tree. Meanwhile, because internally, a State object holds the reference to all DOM elements are bound to it, these DOM elements won't be GC-ed by JavaScript runtime, causing memory leaks.
Garbage collection is implemented in VanJS to resolve the issue. There are 2 ways a garbage collection activity can be triggered:
Periodic recycling: periodically, VanJS will scan all State objects that have new bindings added recently, and remove all bindings to disconnected DOM elements. i.e.: isConnected property is false.
Pre-rendering recycling: before VanJS re-render the DOM tree in response to state changes, it will first check all the states whose values have been changed in this render cycle, and remove all bindings to disconnected DOM elements.
There are some general guidelines to follow to avoid your bindings being garbage collected unexpectedly:
Please complete the construction of the DOM tree and connect the newly constructed DOM tree to the document object before making any state changes. Otherwise, the bindings to yet-to-be-connected DOM elements will be garbage collected.
DOM tree construction needs to be synchronous. i.e.: you shouldn't have any suspension point while building the DOM tree (e.g.: await something in an async function). Otherwise, periodic recycling might be scheduled in the middle of the suspension point which can cause bindings to yet-to-be-connected DOM elements being garbage collected.
For derived states and side effects registered via van.derive, if they are registered inside a binding function, they will be garbage collected if the DOM node returned by the binding function becomes disconnected from the document tree. For instance, for the code below:
whenever renderPre is toggled, a new text state will be created and subscribe to changes of the prefix state. However, the derivation from prefix to the previous text state will be garbage collected as the derivation was created while executing a binding function whose result DOM node no longer connects to the document tree. This is the mechanism to avoid memory leaks caused by state derivations that hold onto memory indefinitely.
In tag functions, while assigning values from props parameter to the created HTML element, there are 2 ways of doing it: via HTML attributes (dom.setAttribute(<key>, <value>)), or via the properties of the created HTML element (dom[<key>] = <value>). VanJS follows a consistent rule that makes sense for most use cases regarding which option to choose: when a settable property exists in a given <key> for the specific element type, we will assign the value via property, otherwise we will assign the value via attribute.
For instance, input({type: "text", value: "Hello 🍦VanJS"}) will create an input box with Hello 🍦VanJS as the value of the value property, while div({"data-index": 1}) will create the tag: <div data-index="1"></div>.
Note that, for readonly properties of HTML elements, we will still assign props values via setAttribute. For instance, in the code snippet below, the list of the <input> element is set via setAttribute:
NOTE: for Mini-Van, since 0.4.0, we consistently assign the props values via setAttribute for all property keys in tag functions. This is because for SSR (server-side rendering), which is Mini-Van's primary use case, setting the properties of a DOM node won't be visible in the rendered HTML string unless the action of setting the property itself will also set the corresponding HTML attribute (e.g.: setting the id property of a DOM node will also set the id attribute). This is helpful as input({type: "text", value: "value"}) can be rendered as <input type="text" value="value"> in Mini-Van but would be rendered as <input type="text"> if we set the property value via DOM property.
We might be prompted to assign a DOM node to a State object, especially when the State object is used as a State-typed child node. However, this is problematic when the state is bound in multiple places, like the example below:
In this example, if we click the "Turn Bold" button, the first "VanJS" text will disappear, which is unexpected. This is because the same DOM node b("VanJS") is used twice in the DOM tree. For this reason, an error will be thrown in van-{version}.debug.js whenever we assign a DOM node to a State object.
More granular State objects can help state bindings be more locally scoped, which make reactive UI updates more efficient by eliminating unnecessary DOM tree construction and replacement.
道生一,一生二,二生三,三生万物 (Tao derives one, one derives two, two derive three, and three derive everything)
-- 老子,道德经
A broad set of advanced state derivation (derived states and side effects) can indeed be defined with van.derive, as illustrated in the following piece of code:
const fullName = van.state(localStorage.getItem("fullName") ?? "Tao Xin")
-
-// State persistence with `localStorage`
-van.derive(() => localStorage.setItem("fullName", fullName.val))
-
-// Defining multiple derived states
-const firstName = van.state(), lastName = van.state()
-van.derive(() => [firstName.val, lastName.val] = fullName.val.split(" "))
-
-const elapsed = van.state(0)
-setInterval(() => elapsed.val += .01, 10)
-
-// Same as `elapsed`, but delay the state propagation by 1s
-const delayed = van.state(0)
-van.derive(() => setTimeout(v => delayed.val = v, 1000, elapsed.val))
-
-// Same as `elapsed`, but throttle the state update to every 100ms
-const throttled = van.state(0)
-setInterval(() => throttled.val = elapsed.val, 100)
-
-// Generate a data stream for all value updates of a given state `s`
-const streamOf = s => {
- let resolver
- van.derive(() => resolver ? resolver({value: s.val, done: false}) : s.val)
- return {
- [Symbol.asyncIterator]: () => ({
- next: () => new Promise(resolve => resolver = resolve)
- })
- }
-}
-
-(async () => {
- // To subscribe the data stream
- for await (const v of streamOf(throttled)) {
- console.log("elapsed: ", v)
- }
- // You can also chain the data stream with `map`, `filter`, etc. by integrating with
- // rubico (https://rubico.land) or wu.js (https://fitzgen.github.io/wu.js/).
-})()
-
In State-derived properties and State-derived child nodes, it is guaranteed that the binding function will (only) be triggered when the dependency states change. This is true even for complex binding functions, who have different dependency states under different conditions.
For instance, the binding function () => cond.val ? a.val + b.val : c.val + d.val will (only) be triggered by updates of state a, b and cond if cond.val is true, and will (only) be triggered by updates of state c, d and cond if cond.val is false. This can be illustrated with the code below:
There is garbage collection mechanism implemented in VanJS to recycle obsolete state bindings. To illustrate the necessity of garbage collection, let's take a look at the code below:
In this piece of code, the TextDiv component has a <div> element whose only child is bound to a boolean state - renderPre, which determines whether the <div> has a <pre> or <span> child. Inside the child element, the underlying text is bound to a string state - text. Whenever the value of renderPre is toggled, a new version of the <div> element will be generated, and we will add a new binding from text state to the child text node of the newly created <div> element.
Without proper garbage collection implemented, text state will eventually be bound to many text nodes after renderPre is toggled many times. All the of bindings, except for the most recently added one, are actually obsolete, as they bind the text state to a text node that is not currently being used. i.e.: disconnected from the document tree. Meanwhile, because internally, a State object holds the reference to all DOM elements are bound to it, these DOM elements won't be GC-ed by JavaScript runtime, causing memory leaks.
Garbage collection is implemented in VanJS to resolve the issue. There are 2 ways a garbage collection activity can be triggered:
Periodic recycling: periodically, VanJS will scan all State objects that have new bindings added recently, and remove all bindings to disconnected DOM elements. i.e.: isConnected property is false.
Pre-rendering recycling: before VanJS re-render the DOM tree in response to state changes, it will first check all the states whose values have been changed in this render cycle, and remove all bindings to disconnected DOM elements.
There are some general guidelines to follow to avoid your bindings being garbage collected unexpectedly:
Please complete the construction of the DOM tree and connect the newly constructed DOM tree to the document object before making any state changes. Otherwise, the bindings to yet-to-be-connected DOM elements will be garbage collected.
DOM tree construction needs to be synchronous. i.e.: you shouldn't have any suspension point while building the DOM tree (e.g.: await something in an async function). Otherwise, periodic recycling might be scheduled in the middle of the suspension point which can cause bindings to yet-to-be-connected DOM elements being garbage collected.
For derived states and side effects registered via van.derive, if they are registered inside a binding function, they will be garbage collected if the DOM node returned by the binding function becomes disconnected from the document tree. For instance, for the code below:
whenever renderPre is toggled, a new text state will be created and subscribe to changes of the prefix state. However, the derivation from prefix to the previous text state will be garbage collected as the derivation was created while executing a binding function whose result DOM node no longer connects to the document tree. This is the mechanism to avoid memory leaks caused by state derivations that hold onto memory indefinitely.
-
-
-
-
-
-
\ No newline at end of file
diff --git a/advanced.js b/assert/advanced.js
similarity index 100%
rename from advanced.js
rename to assert/advanced.js
diff --git a/code/advanced-counter.html b/assert/code/advanced-counter.html
similarity index 100%
rename from code/advanced-counter.html
rename to assert/code/advanced-counter.html
diff --git a/code/advanced-state-derivation.html b/assert/code/advanced-state-derivation.html
similarity index 100%
rename from code/advanced-state-derivation.html
rename to assert/code/advanced-state-derivation.html
diff --git a/code/auto-complete-derived-props.html b/assert/code/auto-complete-derived-props.html
similarity index 100%
rename from code/auto-complete-derived-props.html
rename to assert/code/auto-complete-derived-props.html
diff --git a/code/auto-complete-derived-props.js b/assert/code/auto-complete-derived-props.js
similarity index 100%
rename from code/auto-complete-derived-props.js
rename to assert/code/auto-complete-derived-props.js
diff --git a/code/auto-complete-derived-props.ts b/assert/code/auto-complete-derived-props.ts
similarity index 100%
rename from code/auto-complete-derived-props.ts
rename to assert/code/auto-complete-derived-props.ts
diff --git a/code/auto-complete-stateful-dom-func.html b/assert/code/auto-complete-stateful-dom-func.html
similarity index 100%
rename from code/auto-complete-stateful-dom-func.html
rename to assert/code/auto-complete-stateful-dom-func.html
diff --git a/code/auto-complete-stateful-dom-func.js b/assert/code/auto-complete-stateful-dom-func.js
similarity index 100%
rename from code/auto-complete-stateful-dom-func.js
rename to assert/code/auto-complete-stateful-dom-func.js
diff --git a/code/auto-complete-stateful-dom-func.ts b/assert/code/auto-complete-stateful-dom-func.ts
similarity index 100%
rename from code/auto-complete-stateful-dom-func.ts
rename to assert/code/auto-complete-stateful-dom-func.ts
diff --git a/code/bestofjs.png b/assert/code/bestofjs.png
similarity index 100%
rename from code/bestofjs.png
rename to assert/code/bestofjs.png
diff --git a/code/calculator.css b/assert/code/calculator.css
similarity index 100%
rename from code/calculator.css
rename to assert/code/calculator.css
diff --git a/code/calculator.html b/assert/code/calculator.html
similarity index 100%
rename from code/calculator.html
rename to assert/code/calculator.html
diff --git a/code/code-browser/index.html b/assert/code/code-browser/index.html
similarity index 100%
rename from code/code-browser/index.html
rename to assert/code/code-browser/index.html
diff --git a/code/code-browser/jsconfig.json b/assert/code/code-browser/jsconfig.json
similarity index 100%
rename from code/code-browser/jsconfig.json
rename to assert/code/code-browser/jsconfig.json
diff --git a/code/code-browser/package-lock.json b/assert/code/code-browser/package-lock.json
similarity index 100%
rename from code/code-browser/package-lock.json
rename to assert/code/code-browser/package-lock.json
diff --git a/code/code-browser/package.json b/assert/code/code-browser/package.json
similarity index 100%
rename from code/code-browser/package.json
rename to assert/code/code-browser/package.json
diff --git a/code/code-browser/public/logo.svg b/assert/code/code-browser/public/logo.svg
similarity index 100%
rename from code/code-browser/public/logo.svg
rename to assert/code/code-browser/public/logo.svg
diff --git a/code/code-browser/public/prism.css b/assert/code/code-browser/public/prism.css
similarity index 100%
rename from code/code-browser/public/prism.css
rename to assert/code/code-browser/public/prism.css
diff --git a/code/code-browser/public/prism.js b/assert/code/code-browser/public/prism.js
similarity index 100%
rename from code/code-browser/public/prism.js
rename to assert/code/code-browser/public/prism.js
diff --git a/code/code-browser/src/main.js b/assert/code/code-browser/src/main.js
similarity index 100%
rename from code/code-browser/src/main.js
rename to assert/code/code-browser/src/main.js
diff --git a/code/code-browser/src/vite-env.d.ts b/assert/code/code-browser/src/vite-env.d.ts
similarity index 100%
rename from code/code-browser/src/vite-env.d.ts
rename to assert/code/code-browser/src/vite-env.d.ts
diff --git a/code/code-browser/vite.config.ts b/assert/code/code-browser/vite.config.ts
similarity index 100%
rename from code/code-browser/vite.config.ts
rename to assert/code/code-browser/vite.config.ts
diff --git a/code/connected-props.html b/assert/code/connected-props.html
similarity index 100%
rename from code/connected-props.html
rename to assert/code/connected-props.html
diff --git a/code/console.html b/assert/code/console.html
similarity index 100%
rename from code/console.html
rename to assert/code/console.html
diff --git a/code/diff-simple.html b/assert/code/diff-simple.html
similarity index 100%
rename from code/diff-simple.html
rename to assert/code/diff-simple.html
diff --git a/code/diff.html b/assert/code/diff.html
similarity index 100%
rename from code/diff.html
rename to assert/code/diff.html
diff --git a/code/diff.min.js b/assert/code/diff.min.js
similarity index 100%
rename from code/diff.min.js
rename to assert/code/diff.min.js
diff --git a/code/epoch-converter.html b/assert/code/epoch-converter.html
similarity index 100%
rename from code/epoch-converter.html
rename to assert/code/epoch-converter.html
diff --git a/code/game.html b/assert/code/game.html
similarity index 100%
rename from code/game.html
rename to assert/code/game.html
diff --git a/code/gc-derive.html b/assert/code/gc-derive.html
similarity index 100%
rename from code/gc-derive.html
rename to assert/code/gc-derive.html
diff --git a/code/gc-ui.html b/assert/code/gc-ui.html
similarity index 100%
rename from code/gc-ui.html
rename to assert/code/gc-ui.html
diff --git a/code/hello-cdn-nomodule.html b/assert/code/hello-cdn-nomodule.html
similarity index 100%
rename from code/hello-cdn-nomodule.html
rename to assert/code/hello-cdn-nomodule.html
diff --git a/code/hello-cdn.html b/assert/code/hello-cdn.html
similarity index 100%
rename from code/hello-cdn.html
rename to assert/code/hello-cdn.html
diff --git a/code/hello-fun.html b/assert/code/hello-fun.html
similarity index 100%
rename from code/hello-fun.html
rename to assert/code/hello-fun.html
diff --git a/code/hello-mini-cdn-nomodule.html b/assert/code/hello-mini-cdn-nomodule.html
similarity index 100%
rename from code/hello-mini-cdn-nomodule.html
rename to assert/code/hello-mini-cdn-nomodule.html
diff --git a/code/hello-mini-cdn.html b/assert/code/hello-mini-cdn.html
similarity index 100%
rename from code/hello-mini-cdn.html
rename to assert/code/hello-mini-cdn.html
diff --git a/code/hello-mini-nomodule.html b/assert/code/hello-mini-nomodule.html
similarity index 100%
rename from code/hello-mini-nomodule.html
rename to assert/code/hello-mini-nomodule.html
diff --git a/code/hello-mini.html b/assert/code/hello-mini.html
similarity index 100%
rename from code/hello-mini.html
rename to assert/code/hello-mini.html
diff --git a/code/hello-nomodule.html b/assert/code/hello-nomodule.html
similarity index 100%
rename from code/hello-nomodule.html
rename to assert/code/hello-nomodule.html
diff --git a/code/hello.html b/assert/code/hello.html
similarity index 100%
rename from code/hello.html
rename to assert/code/hello.html
diff --git a/code/hydration-counter-screenshot.png b/assert/code/hydration-counter-screenshot.png
similarity index 100%
rename from code/hydration-counter-screenshot.png
rename to assert/code/hydration-counter-screenshot.png
diff --git a/hydration-example/build.sh b/assert/code/hydration-example/build.sh
similarity index 100%
rename from hydration-example/build.sh
rename to assert/code/hydration-example/build.sh
diff --git a/code/todo-app/public/logo.svg b/assert/code/hydration-example/logo.svg
similarity index 100%
rename from code/todo-app/public/logo.svg
rename to assert/code/hydration-example/logo.svg
diff --git a/hydration-example/minify.sh b/assert/code/hydration-example/minify.sh
similarity index 100%
rename from hydration-example/minify.sh
rename to assert/code/hydration-example/minify.sh
diff --git a/hydration-example/package-lock.json b/assert/code/hydration-example/package-lock.json
similarity index 100%
rename from hydration-example/package-lock.json
rename to assert/code/hydration-example/package-lock.json
diff --git a/hydration-example/package.json b/assert/code/hydration-example/package.json
similarity index 100%
rename from hydration-example/package.json
rename to assert/code/hydration-example/package.json
diff --git a/hydration-example/src/client.ts b/assert/code/hydration-example/src/client.ts
similarity index 100%
rename from hydration-example/src/client.ts
rename to assert/code/hydration-example/src/client.ts
diff --git a/hydration-example/src/components/counter.ts b/assert/code/hydration-example/src/components/counter.ts
similarity index 100%
rename from hydration-example/src/components/counter.ts
rename to assert/code/hydration-example/src/components/counter.ts
diff --git a/hydration-example/src/components/hello.ts b/assert/code/hydration-example/src/components/hello.ts
similarity index 100%
rename from hydration-example/src/components/hello.ts
rename to assert/code/hydration-example/src/components/hello.ts
diff --git a/hydration-example/src/components/optimized-counter.ts b/assert/code/hydration-example/src/components/optimized-counter.ts
similarity index 100%
rename from hydration-example/src/components/optimized-counter.ts
rename to assert/code/hydration-example/src/components/optimized-counter.ts
diff --git a/hydration-example/src/server.ts b/assert/code/hydration-example/src/server.ts
similarity index 100%
rename from hydration-example/src/server.ts
rename to assert/code/hydration-example/src/server.ts
diff --git a/hydration-example/tsconfig.json b/assert/code/hydration-example/tsconfig.json
similarity index 100%
rename from hydration-example/tsconfig.json
rename to assert/code/hydration-example/tsconfig.json
diff --git a/code/hydration-hello-screenshot.png b/assert/code/hydration-hello-screenshot.png
similarity index 100%
rename from code/hydration-hello-screenshot.png
rename to assert/code/hydration-hello-screenshot.png
diff --git a/code/index.html b/assert/code/index.html
similarity index 100%
rename from code/index.html
rename to assert/code/index.html
diff --git a/code/json-csv-table-viewer.html b/assert/code/json-csv-table-viewer.html
similarity index 100%
rename from code/json-csv-table-viewer.html
rename to assert/code/json-csv-table-viewer.html
diff --git a/code/json-inspector.html b/assert/code/json-inspector.html
similarity index 100%
rename from code/json-inspector.html
rename to assert/code/json-inspector.html
diff --git a/code/key-inspector.html b/assert/code/key-inspector.html
similarity index 100%
rename from code/key-inspector.html
rename to assert/code/key-inspector.html
diff --git a/code/list-declarative.html b/assert/code/list-declarative.html
similarity index 100%
rename from code/list-declarative.html
rename to assert/code/list-declarative.html
diff --git a/code/list-imperative.html b/assert/code/list-imperative.html
similarity index 100%
rename from code/list-imperative.html
rename to assert/code/list-imperative.html
diff --git a/code/message-min.html b/assert/code/message-min.html
similarity index 100%
rename from code/message-min.html
rename to assert/code/message-min.html
diff --git a/code/message.html b/assert/code/message.html
similarity index 100%
rename from code/message.html
rename to assert/code/message.html
diff --git a/code/mini-van-0.1.0.js b/assert/code/mini-van-0.1.0.js
similarity index 100%
rename from code/mini-van-0.1.0.js
rename to assert/code/mini-van-0.1.0.js
diff --git a/code/mini-van-0.1.0.min.js b/assert/code/mini-van-0.1.0.min.js
similarity index 100%
rename from code/mini-van-0.1.0.min.js
rename to assert/code/mini-van-0.1.0.min.js
diff --git a/code/mini-van-0.1.0.nomodule.js b/assert/code/mini-van-0.1.0.nomodule.js
similarity index 100%
rename from code/mini-van-0.1.0.nomodule.js
rename to assert/code/mini-van-0.1.0.nomodule.js
diff --git a/code/mini-van-0.1.0.nomodule.min.js b/assert/code/mini-van-0.1.0.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.1.0.nomodule.min.js
rename to assert/code/mini-van-0.1.0.nomodule.min.js
diff --git a/code/mini-van-0.1.1.js b/assert/code/mini-van-0.1.1.js
similarity index 100%
rename from code/mini-van-0.1.1.js
rename to assert/code/mini-van-0.1.1.js
diff --git a/code/mini-van-0.1.1.min.js b/assert/code/mini-van-0.1.1.min.js
similarity index 100%
rename from code/mini-van-0.1.1.min.js
rename to assert/code/mini-van-0.1.1.min.js
diff --git a/code/mini-van-0.1.1.nomodule.js b/assert/code/mini-van-0.1.1.nomodule.js
similarity index 100%
rename from code/mini-van-0.1.1.nomodule.js
rename to assert/code/mini-van-0.1.1.nomodule.js
diff --git a/code/mini-van-0.1.1.nomodule.min.js b/assert/code/mini-van-0.1.1.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.1.1.nomodule.min.js
rename to assert/code/mini-van-0.1.1.nomodule.min.js
diff --git a/code/mini-van-0.1.2.js b/assert/code/mini-van-0.1.2.js
similarity index 100%
rename from code/mini-van-0.1.2.js
rename to assert/code/mini-van-0.1.2.js
diff --git a/code/mini-van-0.1.2.min.js b/assert/code/mini-van-0.1.2.min.js
similarity index 100%
rename from code/mini-van-0.1.2.min.js
rename to assert/code/mini-van-0.1.2.min.js
diff --git a/code/mini-van-0.1.2.nomodule.js b/assert/code/mini-van-0.1.2.nomodule.js
similarity index 100%
rename from code/mini-van-0.1.2.nomodule.js
rename to assert/code/mini-van-0.1.2.nomodule.js
diff --git a/code/mini-van-0.1.2.nomodule.min.js b/assert/code/mini-van-0.1.2.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.1.2.nomodule.min.js
rename to assert/code/mini-van-0.1.2.nomodule.min.js
diff --git a/code/mini-van-0.2.0.js b/assert/code/mini-van-0.2.0.js
similarity index 100%
rename from code/mini-van-0.2.0.js
rename to assert/code/mini-van-0.2.0.js
diff --git a/code/mini-van-0.2.0.min.js b/assert/code/mini-van-0.2.0.min.js
similarity index 100%
rename from code/mini-van-0.2.0.min.js
rename to assert/code/mini-van-0.2.0.min.js
diff --git a/code/mini-van-0.2.0.nomodule.js b/assert/code/mini-van-0.2.0.nomodule.js
similarity index 100%
rename from code/mini-van-0.2.0.nomodule.js
rename to assert/code/mini-van-0.2.0.nomodule.js
diff --git a/code/mini-van-0.2.0.nomodule.min.js b/assert/code/mini-van-0.2.0.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.2.0.nomodule.min.js
rename to assert/code/mini-van-0.2.0.nomodule.min.js
diff --git a/code/mini-van-0.2.1.js b/assert/code/mini-van-0.2.1.js
similarity index 100%
rename from code/mini-van-0.2.1.js
rename to assert/code/mini-van-0.2.1.js
diff --git a/code/mini-van-0.2.1.min.js b/assert/code/mini-van-0.2.1.min.js
similarity index 100%
rename from code/mini-van-0.2.1.min.js
rename to assert/code/mini-van-0.2.1.min.js
diff --git a/code/mini-van-0.2.1.nomodule.js b/assert/code/mini-van-0.2.1.nomodule.js
similarity index 100%
rename from code/mini-van-0.2.1.nomodule.js
rename to assert/code/mini-van-0.2.1.nomodule.js
diff --git a/code/mini-van-0.2.1.nomodule.min.js b/assert/code/mini-van-0.2.1.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.2.1.nomodule.min.js
rename to assert/code/mini-van-0.2.1.nomodule.min.js
diff --git a/code/mini-van-0.2.10.d.ts b/assert/code/mini-van-0.2.10.d.ts
similarity index 100%
rename from code/mini-van-0.2.10.d.ts
rename to assert/code/mini-van-0.2.10.d.ts
diff --git a/code/mini-van-0.2.10.js b/assert/code/mini-van-0.2.10.js
similarity index 100%
rename from code/mini-van-0.2.10.js
rename to assert/code/mini-van-0.2.10.js
diff --git a/code/mini-van-0.2.10.min.d.ts b/assert/code/mini-van-0.2.10.min.d.ts
similarity index 100%
rename from code/mini-van-0.2.10.min.d.ts
rename to assert/code/mini-van-0.2.10.min.d.ts
diff --git a/code/mini-van-0.2.10.min.js b/assert/code/mini-van-0.2.10.min.js
similarity index 100%
rename from code/mini-van-0.2.10.min.js
rename to assert/code/mini-van-0.2.10.min.js
diff --git a/code/mini-van-0.2.10.nomodule.js b/assert/code/mini-van-0.2.10.nomodule.js
similarity index 100%
rename from code/mini-van-0.2.10.nomodule.js
rename to assert/code/mini-van-0.2.10.nomodule.js
diff --git a/code/mini-van-0.2.10.nomodule.min.js b/assert/code/mini-van-0.2.10.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.2.10.nomodule.min.js
rename to assert/code/mini-van-0.2.10.nomodule.min.js
diff --git a/code/mini-van-0.2.11.d.ts b/assert/code/mini-van-0.2.11.d.ts
similarity index 100%
rename from code/mini-van-0.2.11.d.ts
rename to assert/code/mini-van-0.2.11.d.ts
diff --git a/code/mini-van-0.2.11.js b/assert/code/mini-van-0.2.11.js
similarity index 100%
rename from code/mini-van-0.2.11.js
rename to assert/code/mini-van-0.2.11.js
diff --git a/code/mini-van-0.2.11.min.d.ts b/assert/code/mini-van-0.2.11.min.d.ts
similarity index 100%
rename from code/mini-van-0.2.11.min.d.ts
rename to assert/code/mini-van-0.2.11.min.d.ts
diff --git a/code/mini-van-0.2.11.min.js b/assert/code/mini-van-0.2.11.min.js
similarity index 100%
rename from code/mini-van-0.2.11.min.js
rename to assert/code/mini-van-0.2.11.min.js
diff --git a/code/mini-van-0.2.11.nomodule.js b/assert/code/mini-van-0.2.11.nomodule.js
similarity index 100%
rename from code/mini-van-0.2.11.nomodule.js
rename to assert/code/mini-van-0.2.11.nomodule.js
diff --git a/code/mini-van-0.2.11.nomodule.min.js b/assert/code/mini-van-0.2.11.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.2.11.nomodule.min.js
rename to assert/code/mini-van-0.2.11.nomodule.min.js
diff --git a/code/mini-van-0.2.12.d.ts b/assert/code/mini-van-0.2.12.d.ts
similarity index 100%
rename from code/mini-van-0.2.12.d.ts
rename to assert/code/mini-van-0.2.12.d.ts
diff --git a/code/mini-van-0.2.12.js b/assert/code/mini-van-0.2.12.js
similarity index 100%
rename from code/mini-van-0.2.12.js
rename to assert/code/mini-van-0.2.12.js
diff --git a/code/mini-van-0.2.12.min.d.ts b/assert/code/mini-van-0.2.12.min.d.ts
similarity index 100%
rename from code/mini-van-0.2.12.min.d.ts
rename to assert/code/mini-van-0.2.12.min.d.ts
diff --git a/code/mini-van-0.2.12.min.js b/assert/code/mini-van-0.2.12.min.js
similarity index 100%
rename from code/mini-van-0.2.12.min.js
rename to assert/code/mini-van-0.2.12.min.js
diff --git a/code/mini-van-0.2.12.nomodule.js b/assert/code/mini-van-0.2.12.nomodule.js
similarity index 100%
rename from code/mini-van-0.2.12.nomodule.js
rename to assert/code/mini-van-0.2.12.nomodule.js
diff --git a/code/mini-van-0.2.12.nomodule.min.js b/assert/code/mini-van-0.2.12.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.2.12.nomodule.min.js
rename to assert/code/mini-van-0.2.12.nomodule.min.js
diff --git a/code/mini-van-0.2.2.d.ts b/assert/code/mini-van-0.2.2.d.ts
similarity index 100%
rename from code/mini-van-0.2.2.d.ts
rename to assert/code/mini-van-0.2.2.d.ts
diff --git a/code/mini-van-0.2.2.js b/assert/code/mini-van-0.2.2.js
similarity index 100%
rename from code/mini-van-0.2.2.js
rename to assert/code/mini-van-0.2.2.js
diff --git a/code/mini-van-0.2.2.min.d.ts b/assert/code/mini-van-0.2.2.min.d.ts
similarity index 100%
rename from code/mini-van-0.2.2.min.d.ts
rename to assert/code/mini-van-0.2.2.min.d.ts
diff --git a/code/mini-van-0.2.2.min.js b/assert/code/mini-van-0.2.2.min.js
similarity index 100%
rename from code/mini-van-0.2.2.min.js
rename to assert/code/mini-van-0.2.2.min.js
diff --git a/code/mini-van-0.2.2.nomodule.js b/assert/code/mini-van-0.2.2.nomodule.js
similarity index 100%
rename from code/mini-van-0.2.2.nomodule.js
rename to assert/code/mini-van-0.2.2.nomodule.js
diff --git a/code/mini-van-0.2.2.nomodule.min.js b/assert/code/mini-van-0.2.2.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.2.2.nomodule.min.js
rename to assert/code/mini-van-0.2.2.nomodule.min.js
diff --git a/code/mini-van-0.2.3.d.ts b/assert/code/mini-van-0.2.3.d.ts
similarity index 100%
rename from code/mini-van-0.2.3.d.ts
rename to assert/code/mini-van-0.2.3.d.ts
diff --git a/code/mini-van-0.2.3.js b/assert/code/mini-van-0.2.3.js
similarity index 100%
rename from code/mini-van-0.2.3.js
rename to assert/code/mini-van-0.2.3.js
diff --git a/code/mini-van-0.2.3.min.d.ts b/assert/code/mini-van-0.2.3.min.d.ts
similarity index 100%
rename from code/mini-van-0.2.3.min.d.ts
rename to assert/code/mini-van-0.2.3.min.d.ts
diff --git a/code/mini-van-0.2.3.min.js b/assert/code/mini-van-0.2.3.min.js
similarity index 100%
rename from code/mini-van-0.2.3.min.js
rename to assert/code/mini-van-0.2.3.min.js
diff --git a/code/mini-van-0.2.3.nomodule.js b/assert/code/mini-van-0.2.3.nomodule.js
similarity index 100%
rename from code/mini-van-0.2.3.nomodule.js
rename to assert/code/mini-van-0.2.3.nomodule.js
diff --git a/code/mini-van-0.2.3.nomodule.min.js b/assert/code/mini-van-0.2.3.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.2.3.nomodule.min.js
rename to assert/code/mini-van-0.2.3.nomodule.min.js
diff --git a/code/mini-van-0.2.4.d.ts b/assert/code/mini-van-0.2.4.d.ts
similarity index 100%
rename from code/mini-van-0.2.4.d.ts
rename to assert/code/mini-van-0.2.4.d.ts
diff --git a/code/mini-van-0.2.4.js b/assert/code/mini-van-0.2.4.js
similarity index 100%
rename from code/mini-van-0.2.4.js
rename to assert/code/mini-van-0.2.4.js
diff --git a/code/mini-van-0.2.4.min.d.ts b/assert/code/mini-van-0.2.4.min.d.ts
similarity index 100%
rename from code/mini-van-0.2.4.min.d.ts
rename to assert/code/mini-van-0.2.4.min.d.ts
diff --git a/code/mini-van-0.2.4.min.js b/assert/code/mini-van-0.2.4.min.js
similarity index 100%
rename from code/mini-van-0.2.4.min.js
rename to assert/code/mini-van-0.2.4.min.js
diff --git a/code/mini-van-0.2.4.nomodule.js b/assert/code/mini-van-0.2.4.nomodule.js
similarity index 100%
rename from code/mini-van-0.2.4.nomodule.js
rename to assert/code/mini-van-0.2.4.nomodule.js
diff --git a/code/mini-van-0.2.4.nomodule.min.js b/assert/code/mini-van-0.2.4.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.2.4.nomodule.min.js
rename to assert/code/mini-van-0.2.4.nomodule.min.js
diff --git a/code/mini-van-0.2.5.d.ts b/assert/code/mini-van-0.2.5.d.ts
similarity index 100%
rename from code/mini-van-0.2.5.d.ts
rename to assert/code/mini-van-0.2.5.d.ts
diff --git a/code/mini-van-0.2.5.js b/assert/code/mini-van-0.2.5.js
similarity index 100%
rename from code/mini-van-0.2.5.js
rename to assert/code/mini-van-0.2.5.js
diff --git a/code/mini-van-0.2.5.min.d.ts b/assert/code/mini-van-0.2.5.min.d.ts
similarity index 100%
rename from code/mini-van-0.2.5.min.d.ts
rename to assert/code/mini-van-0.2.5.min.d.ts
diff --git a/code/mini-van-0.2.5.min.js b/assert/code/mini-van-0.2.5.min.js
similarity index 100%
rename from code/mini-van-0.2.5.min.js
rename to assert/code/mini-van-0.2.5.min.js
diff --git a/code/mini-van-0.2.5.nomodule.js b/assert/code/mini-van-0.2.5.nomodule.js
similarity index 100%
rename from code/mini-van-0.2.5.nomodule.js
rename to assert/code/mini-van-0.2.5.nomodule.js
diff --git a/code/mini-van-0.2.5.nomodule.min.js b/assert/code/mini-van-0.2.5.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.2.5.nomodule.min.js
rename to assert/code/mini-van-0.2.5.nomodule.min.js
diff --git a/code/mini-van-0.2.6.d.ts b/assert/code/mini-van-0.2.6.d.ts
similarity index 100%
rename from code/mini-van-0.2.6.d.ts
rename to assert/code/mini-van-0.2.6.d.ts
diff --git a/code/mini-van-0.2.6.js b/assert/code/mini-van-0.2.6.js
similarity index 100%
rename from code/mini-van-0.2.6.js
rename to assert/code/mini-van-0.2.6.js
diff --git a/code/mini-van-0.2.6.min.d.ts b/assert/code/mini-van-0.2.6.min.d.ts
similarity index 100%
rename from code/mini-van-0.2.6.min.d.ts
rename to assert/code/mini-van-0.2.6.min.d.ts
diff --git a/code/mini-van-0.2.6.min.js b/assert/code/mini-van-0.2.6.min.js
similarity index 100%
rename from code/mini-van-0.2.6.min.js
rename to assert/code/mini-van-0.2.6.min.js
diff --git a/code/mini-van-0.2.6.nomodule.js b/assert/code/mini-van-0.2.6.nomodule.js
similarity index 100%
rename from code/mini-van-0.2.6.nomodule.js
rename to assert/code/mini-van-0.2.6.nomodule.js
diff --git a/code/mini-van-0.2.6.nomodule.min.js b/assert/code/mini-van-0.2.6.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.2.6.nomodule.min.js
rename to assert/code/mini-van-0.2.6.nomodule.min.js
diff --git a/code/mini-van-0.2.7.d.ts b/assert/code/mini-van-0.2.7.d.ts
similarity index 100%
rename from code/mini-van-0.2.7.d.ts
rename to assert/code/mini-van-0.2.7.d.ts
diff --git a/code/mini-van-0.2.7.js b/assert/code/mini-van-0.2.7.js
similarity index 100%
rename from code/mini-van-0.2.7.js
rename to assert/code/mini-van-0.2.7.js
diff --git a/code/mini-van-0.2.7.min.d.ts b/assert/code/mini-van-0.2.7.min.d.ts
similarity index 100%
rename from code/mini-van-0.2.7.min.d.ts
rename to assert/code/mini-van-0.2.7.min.d.ts
diff --git a/code/mini-van-0.2.7.min.js b/assert/code/mini-van-0.2.7.min.js
similarity index 100%
rename from code/mini-van-0.2.7.min.js
rename to assert/code/mini-van-0.2.7.min.js
diff --git a/code/mini-van-0.2.7.nomodule.js b/assert/code/mini-van-0.2.7.nomodule.js
similarity index 100%
rename from code/mini-van-0.2.7.nomodule.js
rename to assert/code/mini-van-0.2.7.nomodule.js
diff --git a/code/mini-van-0.2.7.nomodule.min.js b/assert/code/mini-van-0.2.7.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.2.7.nomodule.min.js
rename to assert/code/mini-van-0.2.7.nomodule.min.js
diff --git a/code/mini-van-0.2.8.d.ts b/assert/code/mini-van-0.2.8.d.ts
similarity index 100%
rename from code/mini-van-0.2.8.d.ts
rename to assert/code/mini-van-0.2.8.d.ts
diff --git a/code/mini-van-0.2.8.js b/assert/code/mini-van-0.2.8.js
similarity index 100%
rename from code/mini-van-0.2.8.js
rename to assert/code/mini-van-0.2.8.js
diff --git a/code/mini-van-0.2.8.min.d.ts b/assert/code/mini-van-0.2.8.min.d.ts
similarity index 100%
rename from code/mini-van-0.2.8.min.d.ts
rename to assert/code/mini-van-0.2.8.min.d.ts
diff --git a/code/mini-van-0.2.8.min.js b/assert/code/mini-van-0.2.8.min.js
similarity index 100%
rename from code/mini-van-0.2.8.min.js
rename to assert/code/mini-van-0.2.8.min.js
diff --git a/code/mini-van-0.2.8.nomodule.js b/assert/code/mini-van-0.2.8.nomodule.js
similarity index 100%
rename from code/mini-van-0.2.8.nomodule.js
rename to assert/code/mini-van-0.2.8.nomodule.js
diff --git a/code/mini-van-0.2.8.nomodule.min.js b/assert/code/mini-van-0.2.8.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.2.8.nomodule.min.js
rename to assert/code/mini-van-0.2.8.nomodule.min.js
diff --git a/code/mini-van-0.2.9.d.ts b/assert/code/mini-van-0.2.9.d.ts
similarity index 100%
rename from code/mini-van-0.2.9.d.ts
rename to assert/code/mini-van-0.2.9.d.ts
diff --git a/code/mini-van-0.2.9.js b/assert/code/mini-van-0.2.9.js
similarity index 100%
rename from code/mini-van-0.2.9.js
rename to assert/code/mini-van-0.2.9.js
diff --git a/code/mini-van-0.2.9.min.d.ts b/assert/code/mini-van-0.2.9.min.d.ts
similarity index 100%
rename from code/mini-van-0.2.9.min.d.ts
rename to assert/code/mini-van-0.2.9.min.d.ts
diff --git a/code/mini-van-0.2.9.min.js b/assert/code/mini-van-0.2.9.min.js
similarity index 100%
rename from code/mini-van-0.2.9.min.js
rename to assert/code/mini-van-0.2.9.min.js
diff --git a/code/mini-van-0.2.9.nomodule.js b/assert/code/mini-van-0.2.9.nomodule.js
similarity index 100%
rename from code/mini-van-0.2.9.nomodule.js
rename to assert/code/mini-van-0.2.9.nomodule.js
diff --git a/code/mini-van-0.2.9.nomodule.min.js b/assert/code/mini-van-0.2.9.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.2.9.nomodule.min.js
rename to assert/code/mini-van-0.2.9.nomodule.min.js
diff --git a/code/mini-van-0.3.0.d.ts b/assert/code/mini-van-0.3.0.d.ts
similarity index 100%
rename from code/mini-van-0.3.0.d.ts
rename to assert/code/mini-van-0.3.0.d.ts
diff --git a/code/mini-van-0.3.0.js b/assert/code/mini-van-0.3.0.js
similarity index 100%
rename from code/mini-van-0.3.0.js
rename to assert/code/mini-van-0.3.0.js
diff --git a/code/mini-van-0.3.0.min.d.ts b/assert/code/mini-van-0.3.0.min.d.ts
similarity index 100%
rename from code/mini-van-0.3.0.min.d.ts
rename to assert/code/mini-van-0.3.0.min.d.ts
diff --git a/code/mini-van-0.3.0.min.js b/assert/code/mini-van-0.3.0.min.js
similarity index 100%
rename from code/mini-van-0.3.0.min.js
rename to assert/code/mini-van-0.3.0.min.js
diff --git a/code/mini-van-0.3.0.nomodule.js b/assert/code/mini-van-0.3.0.nomodule.js
similarity index 100%
rename from code/mini-van-0.3.0.nomodule.js
rename to assert/code/mini-van-0.3.0.nomodule.js
diff --git a/code/mini-van-0.3.0.nomodule.min.js b/assert/code/mini-van-0.3.0.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.3.0.nomodule.min.js
rename to assert/code/mini-van-0.3.0.nomodule.min.js
diff --git a/code/mini-van-0.3.1.d.ts b/assert/code/mini-van-0.3.1.d.ts
similarity index 100%
rename from code/mini-van-0.3.1.d.ts
rename to assert/code/mini-van-0.3.1.d.ts
diff --git a/code/mini-van-0.3.1.js b/assert/code/mini-van-0.3.1.js
similarity index 100%
rename from code/mini-van-0.3.1.js
rename to assert/code/mini-van-0.3.1.js
diff --git a/code/mini-van-0.3.1.min.d.ts b/assert/code/mini-van-0.3.1.min.d.ts
similarity index 100%
rename from code/mini-van-0.3.1.min.d.ts
rename to assert/code/mini-van-0.3.1.min.d.ts
diff --git a/code/mini-van-0.3.1.min.js b/assert/code/mini-van-0.3.1.min.js
similarity index 100%
rename from code/mini-van-0.3.1.min.js
rename to assert/code/mini-van-0.3.1.min.js
diff --git a/code/mini-van-0.3.1.nomodule.js b/assert/code/mini-van-0.3.1.nomodule.js
similarity index 100%
rename from code/mini-van-0.3.1.nomodule.js
rename to assert/code/mini-van-0.3.1.nomodule.js
diff --git a/code/mini-van-0.3.1.nomodule.min.js b/assert/code/mini-van-0.3.1.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.3.1.nomodule.min.js
rename to assert/code/mini-van-0.3.1.nomodule.min.js
diff --git a/code/mini-van-0.3.2.d.ts b/assert/code/mini-van-0.3.2.d.ts
similarity index 100%
rename from code/mini-van-0.3.2.d.ts
rename to assert/code/mini-van-0.3.2.d.ts
diff --git a/code/mini-van-0.3.2.js b/assert/code/mini-van-0.3.2.js
similarity index 100%
rename from code/mini-van-0.3.2.js
rename to assert/code/mini-van-0.3.2.js
diff --git a/code/mini-van-0.3.2.min.d.ts b/assert/code/mini-van-0.3.2.min.d.ts
similarity index 100%
rename from code/mini-van-0.3.2.min.d.ts
rename to assert/code/mini-van-0.3.2.min.d.ts
diff --git a/code/mini-van-0.3.2.min.js b/assert/code/mini-van-0.3.2.min.js
similarity index 100%
rename from code/mini-van-0.3.2.min.js
rename to assert/code/mini-van-0.3.2.min.js
diff --git a/code/mini-van-0.3.2.nomodule.js b/assert/code/mini-van-0.3.2.nomodule.js
similarity index 100%
rename from code/mini-van-0.3.2.nomodule.js
rename to assert/code/mini-van-0.3.2.nomodule.js
diff --git a/code/mini-van-0.3.2.nomodule.min.js b/assert/code/mini-van-0.3.2.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.3.2.nomodule.min.js
rename to assert/code/mini-van-0.3.2.nomodule.min.js
diff --git a/code/mini-van-0.3.3.d.ts b/assert/code/mini-van-0.3.3.d.ts
similarity index 100%
rename from code/mini-van-0.3.3.d.ts
rename to assert/code/mini-van-0.3.3.d.ts
diff --git a/code/mini-van-0.3.3.js b/assert/code/mini-van-0.3.3.js
similarity index 100%
rename from code/mini-van-0.3.3.js
rename to assert/code/mini-van-0.3.3.js
diff --git a/code/mini-van-0.3.3.min.d.ts b/assert/code/mini-van-0.3.3.min.d.ts
similarity index 100%
rename from code/mini-van-0.3.3.min.d.ts
rename to assert/code/mini-van-0.3.3.min.d.ts
diff --git a/code/mini-van-0.3.3.min.js b/assert/code/mini-van-0.3.3.min.js
similarity index 100%
rename from code/mini-van-0.3.3.min.js
rename to assert/code/mini-van-0.3.3.min.js
diff --git a/code/mini-van-0.3.3.nomodule.js b/assert/code/mini-van-0.3.3.nomodule.js
similarity index 100%
rename from code/mini-van-0.3.3.nomodule.js
rename to assert/code/mini-van-0.3.3.nomodule.js
diff --git a/code/mini-van-0.3.3.nomodule.min.js b/assert/code/mini-van-0.3.3.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.3.3.nomodule.min.js
rename to assert/code/mini-van-0.3.3.nomodule.min.js
diff --git a/code/mini-van-0.3.4.d.ts b/assert/code/mini-van-0.3.4.d.ts
similarity index 100%
rename from code/mini-van-0.3.4.d.ts
rename to assert/code/mini-van-0.3.4.d.ts
diff --git a/code/mini-van-0.3.4.js b/assert/code/mini-van-0.3.4.js
similarity index 100%
rename from code/mini-van-0.3.4.js
rename to assert/code/mini-van-0.3.4.js
diff --git a/code/mini-van-0.3.4.min.d.ts b/assert/code/mini-van-0.3.4.min.d.ts
similarity index 100%
rename from code/mini-van-0.3.4.min.d.ts
rename to assert/code/mini-van-0.3.4.min.d.ts
diff --git a/code/mini-van-0.3.4.min.js b/assert/code/mini-van-0.3.4.min.js
similarity index 100%
rename from code/mini-van-0.3.4.min.js
rename to assert/code/mini-van-0.3.4.min.js
diff --git a/code/mini-van-0.3.4.nomodule.js b/assert/code/mini-van-0.3.4.nomodule.js
similarity index 100%
rename from code/mini-van-0.3.4.nomodule.js
rename to assert/code/mini-van-0.3.4.nomodule.js
diff --git a/code/mini-van-0.3.4.nomodule.min.js b/assert/code/mini-van-0.3.4.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.3.4.nomodule.min.js
rename to assert/code/mini-van-0.3.4.nomodule.min.js
diff --git a/code/mini-van-0.3.5.d.ts b/assert/code/mini-van-0.3.5.d.ts
similarity index 100%
rename from code/mini-van-0.3.5.d.ts
rename to assert/code/mini-van-0.3.5.d.ts
diff --git a/code/mini-van-0.3.5.js b/assert/code/mini-van-0.3.5.js
similarity index 100%
rename from code/mini-van-0.3.5.js
rename to assert/code/mini-van-0.3.5.js
diff --git a/code/mini-van-0.3.5.min.d.ts b/assert/code/mini-van-0.3.5.min.d.ts
similarity index 100%
rename from code/mini-van-0.3.5.min.d.ts
rename to assert/code/mini-van-0.3.5.min.d.ts
diff --git a/code/mini-van-0.3.5.min.js b/assert/code/mini-van-0.3.5.min.js
similarity index 100%
rename from code/mini-van-0.3.5.min.js
rename to assert/code/mini-van-0.3.5.min.js
diff --git a/code/mini-van-0.3.5.nomodule.js b/assert/code/mini-van-0.3.5.nomodule.js
similarity index 100%
rename from code/mini-van-0.3.5.nomodule.js
rename to assert/code/mini-van-0.3.5.nomodule.js
diff --git a/code/mini-van-0.3.5.nomodule.min.js b/assert/code/mini-van-0.3.5.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.3.5.nomodule.min.js
rename to assert/code/mini-van-0.3.5.nomodule.min.js
diff --git a/code/mini-van-0.3.6.d.ts b/assert/code/mini-van-0.3.6.d.ts
similarity index 100%
rename from code/mini-van-0.3.6.d.ts
rename to assert/code/mini-van-0.3.6.d.ts
diff --git a/code/mini-van-0.3.6.js b/assert/code/mini-van-0.3.6.js
similarity index 100%
rename from code/mini-van-0.3.6.js
rename to assert/code/mini-van-0.3.6.js
diff --git a/code/mini-van-0.3.6.min.d.ts b/assert/code/mini-van-0.3.6.min.d.ts
similarity index 100%
rename from code/mini-van-0.3.6.min.d.ts
rename to assert/code/mini-van-0.3.6.min.d.ts
diff --git a/code/mini-van-0.3.6.min.js b/assert/code/mini-van-0.3.6.min.js
similarity index 100%
rename from code/mini-van-0.3.6.min.js
rename to assert/code/mini-van-0.3.6.min.js
diff --git a/code/mini-van-0.3.6.nomodule.js b/assert/code/mini-van-0.3.6.nomodule.js
similarity index 100%
rename from code/mini-van-0.3.6.nomodule.js
rename to assert/code/mini-van-0.3.6.nomodule.js
diff --git a/code/mini-van-0.3.6.nomodule.min.js b/assert/code/mini-van-0.3.6.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.3.6.nomodule.min.js
rename to assert/code/mini-van-0.3.6.nomodule.min.js
diff --git a/code/mini-van-0.3.7.d.ts b/assert/code/mini-van-0.3.7.d.ts
similarity index 100%
rename from code/mini-van-0.3.7.d.ts
rename to assert/code/mini-van-0.3.7.d.ts
diff --git a/code/mini-van-0.3.7.js b/assert/code/mini-van-0.3.7.js
similarity index 100%
rename from code/mini-van-0.3.7.js
rename to assert/code/mini-van-0.3.7.js
diff --git a/code/mini-van-0.3.7.min.d.ts b/assert/code/mini-van-0.3.7.min.d.ts
similarity index 100%
rename from code/mini-van-0.3.7.min.d.ts
rename to assert/code/mini-van-0.3.7.min.d.ts
diff --git a/code/mini-van-0.3.7.min.js b/assert/code/mini-van-0.3.7.min.js
similarity index 100%
rename from code/mini-van-0.3.7.min.js
rename to assert/code/mini-van-0.3.7.min.js
diff --git a/code/mini-van-0.3.7.nomodule.js b/assert/code/mini-van-0.3.7.nomodule.js
similarity index 100%
rename from code/mini-van-0.3.7.nomodule.js
rename to assert/code/mini-van-0.3.7.nomodule.js
diff --git a/code/mini-van-0.3.7.nomodule.min.js b/assert/code/mini-van-0.3.7.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.3.7.nomodule.min.js
rename to assert/code/mini-van-0.3.7.nomodule.min.js
diff --git a/code/mini-van-0.3.8.d.ts b/assert/code/mini-van-0.3.8.d.ts
similarity index 100%
rename from code/mini-van-0.3.8.d.ts
rename to assert/code/mini-van-0.3.8.d.ts
diff --git a/code/mini-van-0.3.8.js b/assert/code/mini-van-0.3.8.js
similarity index 100%
rename from code/mini-van-0.3.8.js
rename to assert/code/mini-van-0.3.8.js
diff --git a/code/mini-van-0.3.8.min.d.ts b/assert/code/mini-van-0.3.8.min.d.ts
similarity index 100%
rename from code/mini-van-0.3.8.min.d.ts
rename to assert/code/mini-van-0.3.8.min.d.ts
diff --git a/code/mini-van-0.3.8.min.js b/assert/code/mini-van-0.3.8.min.js
similarity index 100%
rename from code/mini-van-0.3.8.min.js
rename to assert/code/mini-van-0.3.8.min.js
diff --git a/code/mini-van-0.3.8.nomodule.js b/assert/code/mini-van-0.3.8.nomodule.js
similarity index 100%
rename from code/mini-van-0.3.8.nomodule.js
rename to assert/code/mini-van-0.3.8.nomodule.js
diff --git a/code/mini-van-0.3.8.nomodule.min.js b/assert/code/mini-van-0.3.8.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.3.8.nomodule.min.js
rename to assert/code/mini-van-0.3.8.nomodule.min.js
diff --git a/code/mini-van-0.3.9.d.ts b/assert/code/mini-van-0.3.9.d.ts
similarity index 100%
rename from code/mini-van-0.3.9.d.ts
rename to assert/code/mini-van-0.3.9.d.ts
diff --git a/code/mini-van-0.3.9.js b/assert/code/mini-van-0.3.9.js
similarity index 100%
rename from code/mini-van-0.3.9.js
rename to assert/code/mini-van-0.3.9.js
diff --git a/code/mini-van-0.3.9.min.d.ts b/assert/code/mini-van-0.3.9.min.d.ts
similarity index 100%
rename from code/mini-van-0.3.9.min.d.ts
rename to assert/code/mini-van-0.3.9.min.d.ts
diff --git a/code/mini-van-0.3.9.min.js b/assert/code/mini-van-0.3.9.min.js
similarity index 100%
rename from code/mini-van-0.3.9.min.js
rename to assert/code/mini-van-0.3.9.min.js
diff --git a/code/mini-van-0.3.9.nomodule.js b/assert/code/mini-van-0.3.9.nomodule.js
similarity index 100%
rename from code/mini-van-0.3.9.nomodule.js
rename to assert/code/mini-van-0.3.9.nomodule.js
diff --git a/code/mini-van-0.3.9.nomodule.min.js b/assert/code/mini-van-0.3.9.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.3.9.nomodule.min.js
rename to assert/code/mini-van-0.3.9.nomodule.min.js
diff --git a/code/mini-van-0.4.0.d.ts b/assert/code/mini-van-0.4.0.d.ts
similarity index 100%
rename from code/mini-van-0.4.0.d.ts
rename to assert/code/mini-van-0.4.0.d.ts
diff --git a/code/mini-van-0.4.0.js b/assert/code/mini-van-0.4.0.js
similarity index 100%
rename from code/mini-van-0.4.0.js
rename to assert/code/mini-van-0.4.0.js
diff --git a/code/mini-van-0.4.0.min.d.ts b/assert/code/mini-van-0.4.0.min.d.ts
similarity index 100%
rename from code/mini-van-0.4.0.min.d.ts
rename to assert/code/mini-van-0.4.0.min.d.ts
diff --git a/code/mini-van-0.4.0.min.js b/assert/code/mini-van-0.4.0.min.js
similarity index 100%
rename from code/mini-van-0.4.0.min.js
rename to assert/code/mini-van-0.4.0.min.js
diff --git a/code/mini-van-0.4.0.nomodule.js b/assert/code/mini-van-0.4.0.nomodule.js
similarity index 100%
rename from code/mini-van-0.4.0.nomodule.js
rename to assert/code/mini-van-0.4.0.nomodule.js
diff --git a/code/mini-van-0.4.0.nomodule.min.js b/assert/code/mini-van-0.4.0.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.4.0.nomodule.min.js
rename to assert/code/mini-van-0.4.0.nomodule.min.js
diff --git a/code/mini-van-0.4.1.d.ts b/assert/code/mini-van-0.4.1.d.ts
similarity index 100%
rename from code/mini-van-0.4.1.d.ts
rename to assert/code/mini-van-0.4.1.d.ts
diff --git a/code/mini-van-0.4.1.js b/assert/code/mini-van-0.4.1.js
similarity index 100%
rename from code/mini-van-0.4.1.js
rename to assert/code/mini-van-0.4.1.js
diff --git a/code/mini-van-0.4.1.min.d.ts b/assert/code/mini-van-0.4.1.min.d.ts
similarity index 100%
rename from code/mini-van-0.4.1.min.d.ts
rename to assert/code/mini-van-0.4.1.min.d.ts
diff --git a/code/mini-van-0.4.1.min.js b/assert/code/mini-van-0.4.1.min.js
similarity index 100%
rename from code/mini-van-0.4.1.min.js
rename to assert/code/mini-van-0.4.1.min.js
diff --git a/code/mini-van-0.4.1.nomodule.js b/assert/code/mini-van-0.4.1.nomodule.js
similarity index 100%
rename from code/mini-van-0.4.1.nomodule.js
rename to assert/code/mini-van-0.4.1.nomodule.js
diff --git a/code/mini-van-0.4.1.nomodule.min.js b/assert/code/mini-van-0.4.1.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.4.1.nomodule.min.js
rename to assert/code/mini-van-0.4.1.nomodule.min.js
diff --git a/code/mini-van-0.4.2.d.ts b/assert/code/mini-van-0.4.2.d.ts
similarity index 100%
rename from code/mini-van-0.4.2.d.ts
rename to assert/code/mini-van-0.4.2.d.ts
diff --git a/code/mini-van-0.4.2.js b/assert/code/mini-van-0.4.2.js
similarity index 100%
rename from code/mini-van-0.4.2.js
rename to assert/code/mini-van-0.4.2.js
diff --git a/code/mini-van-0.4.2.min.d.ts b/assert/code/mini-van-0.4.2.min.d.ts
similarity index 100%
rename from code/mini-van-0.4.2.min.d.ts
rename to assert/code/mini-van-0.4.2.min.d.ts
diff --git a/code/mini-van-0.4.2.min.js b/assert/code/mini-van-0.4.2.min.js
similarity index 100%
rename from code/mini-van-0.4.2.min.js
rename to assert/code/mini-van-0.4.2.min.js
diff --git a/code/mini-van-0.4.2.nomodule.js b/assert/code/mini-van-0.4.2.nomodule.js
similarity index 100%
rename from code/mini-van-0.4.2.nomodule.js
rename to assert/code/mini-van-0.4.2.nomodule.js
diff --git a/code/mini-van-0.4.2.nomodule.min.js b/assert/code/mini-van-0.4.2.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.4.2.nomodule.min.js
rename to assert/code/mini-van-0.4.2.nomodule.min.js
diff --git a/code/mini-van-0.5.0.d.ts b/assert/code/mini-van-0.5.0.d.ts
similarity index 100%
rename from code/mini-van-0.5.0.d.ts
rename to assert/code/mini-van-0.5.0.d.ts
diff --git a/code/mini-van-0.5.0.js b/assert/code/mini-van-0.5.0.js
similarity index 100%
rename from code/mini-van-0.5.0.js
rename to assert/code/mini-van-0.5.0.js
diff --git a/code/mini-van-0.5.0.min.d.ts b/assert/code/mini-van-0.5.0.min.d.ts
similarity index 100%
rename from code/mini-van-0.5.0.min.d.ts
rename to assert/code/mini-van-0.5.0.min.d.ts
diff --git a/code/mini-van-0.5.0.min.js b/assert/code/mini-van-0.5.0.min.js
similarity index 100%
rename from code/mini-van-0.5.0.min.js
rename to assert/code/mini-van-0.5.0.min.js
diff --git a/code/mini-van-0.5.0.nomodule.js b/assert/code/mini-van-0.5.0.nomodule.js
similarity index 100%
rename from code/mini-van-0.5.0.nomodule.js
rename to assert/code/mini-van-0.5.0.nomodule.js
diff --git a/code/mini-van-0.5.0.nomodule.min.js b/assert/code/mini-van-0.5.0.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.5.0.nomodule.min.js
rename to assert/code/mini-van-0.5.0.nomodule.min.js
diff --git a/code/mini-van-0.5.1.d.ts b/assert/code/mini-van-0.5.1.d.ts
similarity index 100%
rename from code/mini-van-0.5.1.d.ts
rename to assert/code/mini-van-0.5.1.d.ts
diff --git a/code/mini-van-0.5.1.js b/assert/code/mini-van-0.5.1.js
similarity index 100%
rename from code/mini-van-0.5.1.js
rename to assert/code/mini-van-0.5.1.js
diff --git a/code/mini-van-0.5.1.min.d.ts b/assert/code/mini-van-0.5.1.min.d.ts
similarity index 100%
rename from code/mini-van-0.5.1.min.d.ts
rename to assert/code/mini-van-0.5.1.min.d.ts
diff --git a/code/mini-van-0.5.1.min.js b/assert/code/mini-van-0.5.1.min.js
similarity index 100%
rename from code/mini-van-0.5.1.min.js
rename to assert/code/mini-van-0.5.1.min.js
diff --git a/code/mini-van-0.5.1.nomodule.js b/assert/code/mini-van-0.5.1.nomodule.js
similarity index 100%
rename from code/mini-van-0.5.1.nomodule.js
rename to assert/code/mini-van-0.5.1.nomodule.js
diff --git a/code/mini-van-0.5.1.nomodule.min.js b/assert/code/mini-van-0.5.1.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.5.1.nomodule.min.js
rename to assert/code/mini-van-0.5.1.nomodule.min.js
diff --git a/code/mini-van-0.5.2.d.ts b/assert/code/mini-van-0.5.2.d.ts
similarity index 100%
rename from code/mini-van-0.5.2.d.ts
rename to assert/code/mini-van-0.5.2.d.ts
diff --git a/code/mini-van-0.5.2.js b/assert/code/mini-van-0.5.2.js
similarity index 100%
rename from code/mini-van-0.5.2.js
rename to assert/code/mini-van-0.5.2.js
diff --git a/code/mini-van-0.5.2.min.d.ts b/assert/code/mini-van-0.5.2.min.d.ts
similarity index 100%
rename from code/mini-van-0.5.2.min.d.ts
rename to assert/code/mini-van-0.5.2.min.d.ts
diff --git a/code/mini-van-0.5.2.min.js b/assert/code/mini-van-0.5.2.min.js
similarity index 100%
rename from code/mini-van-0.5.2.min.js
rename to assert/code/mini-van-0.5.2.min.js
diff --git a/code/mini-van-0.5.2.nomodule.js b/assert/code/mini-van-0.5.2.nomodule.js
similarity index 100%
rename from code/mini-van-0.5.2.nomodule.js
rename to assert/code/mini-van-0.5.2.nomodule.js
diff --git a/code/mini-van-0.5.2.nomodule.min.js b/assert/code/mini-van-0.5.2.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.5.2.nomodule.min.js
rename to assert/code/mini-van-0.5.2.nomodule.min.js
diff --git a/code/mini-van-0.5.3.d.ts b/assert/code/mini-van-0.5.3.d.ts
similarity index 100%
rename from code/mini-van-0.5.3.d.ts
rename to assert/code/mini-van-0.5.3.d.ts
diff --git a/code/mini-van-0.5.3.js b/assert/code/mini-van-0.5.3.js
similarity index 100%
rename from code/mini-van-0.5.3.js
rename to assert/code/mini-van-0.5.3.js
diff --git a/code/mini-van-0.5.3.min.d.ts b/assert/code/mini-van-0.5.3.min.d.ts
similarity index 100%
rename from code/mini-van-0.5.3.min.d.ts
rename to assert/code/mini-van-0.5.3.min.d.ts
diff --git a/code/mini-van-0.5.3.min.js b/assert/code/mini-van-0.5.3.min.js
similarity index 100%
rename from code/mini-van-0.5.3.min.js
rename to assert/code/mini-van-0.5.3.min.js
diff --git a/code/mini-van-0.5.3.nomodule.js b/assert/code/mini-van-0.5.3.nomodule.js
similarity index 100%
rename from code/mini-van-0.5.3.nomodule.js
rename to assert/code/mini-van-0.5.3.nomodule.js
diff --git a/code/mini-van-0.5.3.nomodule.min.js b/assert/code/mini-van-0.5.3.nomodule.min.js
similarity index 100%
rename from code/mini-van-0.5.3.nomodule.min.js
rename to assert/code/mini-van-0.5.3.nomodule.min.js
diff --git a/code/mini-van-latest.d.ts b/assert/code/mini-van-latest.d.ts
similarity index 100%
rename from code/mini-van-latest.d.ts
rename to assert/code/mini-van-latest.d.ts
diff --git a/code/mini-van-latest.js b/assert/code/mini-van-latest.js
similarity index 100%
rename from code/mini-van-latest.js
rename to assert/code/mini-van-latest.js
diff --git a/code/mini-van-latest.min.d.ts b/assert/code/mini-van-latest.min.d.ts
similarity index 100%
rename from code/mini-van-latest.min.d.ts
rename to assert/code/mini-van-latest.min.d.ts
diff --git a/code/mini-van-latest.min.js b/assert/code/mini-van-latest.min.js
similarity index 100%
rename from code/mini-van-latest.min.js
rename to assert/code/mini-van-latest.min.js
diff --git a/code/mini-van-latest.nomodule.js b/assert/code/mini-van-latest.nomodule.js
similarity index 100%
rename from code/mini-van-latest.nomodule.js
rename to assert/code/mini-van-latest.nomodule.js
diff --git a/code/mini-van-latest.nomodule.min.js b/assert/code/mini-van-latest.nomodule.min.js
similarity index 100%
rename from code/mini-van-latest.nomodule.min.js
rename to assert/code/mini-van-latest.nomodule.min.js
diff --git a/code/mini-van.version b/assert/code/mini-van.version
similarity index 100%
rename from code/mini-van.version
rename to assert/code/mini-van.version
diff --git a/code/minimal-counter.html b/assert/code/minimal-counter.html
similarity index 100%
rename from code/minimal-counter.html
rename to assert/code/minimal-counter.html
diff --git a/code/modal-min.html b/assert/code/modal-min.html
similarity index 100%
rename from code/modal-min.html
rename to assert/code/modal-min.html
diff --git a/code/modal.html b/assert/code/modal.html
similarity index 100%
rename from code/modal.html
rename to assert/code/modal.html
diff --git a/code/package-lock-inspector.html b/assert/code/package-lock-inspector.html
similarity index 100%
rename from code/package-lock-inspector.html
rename to assert/code/package-lock-inspector.html
diff --git a/code/simple-counter.html b/assert/code/simple-counter.html
similarity index 100%
rename from code/simple-counter.html
rename to assert/code/simple-counter.html
diff --git a/code/stars.html b/assert/code/stars.html
similarity index 100%
rename from code/stars.html
rename to assert/code/stars.html
diff --git a/code/static.html b/assert/code/static.html
similarity index 100%
rename from code/static.html
rename to assert/code/static.html
diff --git a/code/todo-app/.gitignore b/assert/code/todo-app/.gitignore
similarity index 100%
rename from code/todo-app/.gitignore
rename to assert/code/todo-app/.gitignore
diff --git a/code/todo-app/index.html b/assert/code/todo-app/index.html
similarity index 100%
rename from code/todo-app/index.html
rename to assert/code/todo-app/index.html
diff --git a/code/todo-app/package-lock.json b/assert/code/todo-app/package-lock.json
similarity index 100%
rename from code/todo-app/package-lock.json
rename to assert/code/todo-app/package-lock.json
diff --git a/code/todo-app/package.json b/assert/code/todo-app/package.json
similarity index 100%
rename from code/todo-app/package.json
rename to assert/code/todo-app/package.json
diff --git a/hydration-example/logo.svg b/assert/code/todo-app/public/logo.svg
similarity index 100%
rename from hydration-example/logo.svg
rename to assert/code/todo-app/public/logo.svg
diff --git a/code/todo-app/src/main.ts b/assert/code/todo-app/src/main.ts
similarity index 100%
rename from code/todo-app/src/main.ts
rename to assert/code/todo-app/src/main.ts
diff --git a/code/todo-app/src/vite-env.d.ts b/assert/code/todo-app/src/vite-env.d.ts
similarity index 100%
rename from code/todo-app/src/vite-env.d.ts
rename to assert/code/todo-app/src/vite-env.d.ts
diff --git a/code/todo-app/tsconfig.json b/assert/code/todo-app/tsconfig.json
similarity index 100%
rename from code/todo-app/tsconfig.json
rename to assert/code/todo-app/tsconfig.json
diff --git a/code/todo-app/vite.config.ts b/assert/code/todo-app/vite.config.ts
similarity index 100%
rename from code/todo-app/vite.config.ts
rename to assert/code/todo-app/vite.config.ts
diff --git a/code/todo-functional.html b/assert/code/todo-functional.html
similarity index 100%
rename from code/todo-functional.html
rename to assert/code/todo-functional.html
diff --git a/code/todo-procedural.html b/assert/code/todo-procedural.html
similarity index 100%
rename from code/todo-procedural.html
rename to assert/code/todo-procedural.html
diff --git a/code/tsconfig.json b/assert/code/tsconfig.json
similarity index 100%
rename from code/tsconfig.json
rename to assert/code/tsconfig.json
diff --git a/code/van-0.10.0.debug.js b/assert/code/van-0.10.0.debug.js
similarity index 100%
rename from code/van-0.10.0.debug.js
rename to assert/code/van-0.10.0.debug.js
diff --git a/code/van-0.10.0.js b/assert/code/van-0.10.0.js
similarity index 100%
rename from code/van-0.10.0.js
rename to assert/code/van-0.10.0.js
diff --git a/code/van-0.10.0.min.js b/assert/code/van-0.10.0.min.js
similarity index 100%
rename from code/van-0.10.0.min.js
rename to assert/code/van-0.10.0.min.js
diff --git a/code/van-0.10.0.nomodule.debug.js b/assert/code/van-0.10.0.nomodule.debug.js
similarity index 100%
rename from code/van-0.10.0.nomodule.debug.js
rename to assert/code/van-0.10.0.nomodule.debug.js
diff --git a/code/van-0.10.0.nomodule.js b/assert/code/van-0.10.0.nomodule.js
similarity index 100%
rename from code/van-0.10.0.nomodule.js
rename to assert/code/van-0.10.0.nomodule.js
diff --git a/code/van-0.10.0.nomodule.min.js b/assert/code/van-0.10.0.nomodule.min.js
similarity index 100%
rename from code/van-0.10.0.nomodule.min.js
rename to assert/code/van-0.10.0.nomodule.min.js
diff --git a/code/van-0.10.1.debug.js b/assert/code/van-0.10.1.debug.js
similarity index 100%
rename from code/van-0.10.1.debug.js
rename to assert/code/van-0.10.1.debug.js
diff --git a/code/van-0.10.1.js b/assert/code/van-0.10.1.js
similarity index 100%
rename from code/van-0.10.1.js
rename to assert/code/van-0.10.1.js
diff --git a/code/van-0.10.1.min.js b/assert/code/van-0.10.1.min.js
similarity index 100%
rename from code/van-0.10.1.min.js
rename to assert/code/van-0.10.1.min.js
diff --git a/code/van-0.10.1.nomodule.debug.js b/assert/code/van-0.10.1.nomodule.debug.js
similarity index 100%
rename from code/van-0.10.1.nomodule.debug.js
rename to assert/code/van-0.10.1.nomodule.debug.js
diff --git a/code/van-0.10.1.nomodule.js b/assert/code/van-0.10.1.nomodule.js
similarity index 100%
rename from code/van-0.10.1.nomodule.js
rename to assert/code/van-0.10.1.nomodule.js
diff --git a/code/van-0.10.1.nomodule.min.js b/assert/code/van-0.10.1.nomodule.min.js
similarity index 100%
rename from code/van-0.10.1.nomodule.min.js
rename to assert/code/van-0.10.1.nomodule.min.js
diff --git a/code/van-0.10.2.debug.js b/assert/code/van-0.10.2.debug.js
similarity index 100%
rename from code/van-0.10.2.debug.js
rename to assert/code/van-0.10.2.debug.js
diff --git a/code/van-0.10.2.js b/assert/code/van-0.10.2.js
similarity index 100%
rename from code/van-0.10.2.js
rename to assert/code/van-0.10.2.js
diff --git a/code/van-0.10.2.min.js b/assert/code/van-0.10.2.min.js
similarity index 100%
rename from code/van-0.10.2.min.js
rename to assert/code/van-0.10.2.min.js
diff --git a/code/van-0.10.2.nomodule.debug.js b/assert/code/van-0.10.2.nomodule.debug.js
similarity index 100%
rename from code/van-0.10.2.nomodule.debug.js
rename to assert/code/van-0.10.2.nomodule.debug.js
diff --git a/code/van-0.10.2.nomodule.js b/assert/code/van-0.10.2.nomodule.js
similarity index 100%
rename from code/van-0.10.2.nomodule.js
rename to assert/code/van-0.10.2.nomodule.js
diff --git a/code/van-0.10.2.nomodule.min.js b/assert/code/van-0.10.2.nomodule.min.js
similarity index 100%
rename from code/van-0.10.2.nomodule.min.js
rename to assert/code/van-0.10.2.nomodule.min.js
diff --git a/code/van-0.11.0.debug.js b/assert/code/van-0.11.0.debug.js
similarity index 100%
rename from code/van-0.11.0.debug.js
rename to assert/code/van-0.11.0.debug.js
diff --git a/code/van-0.11.0.js b/assert/code/van-0.11.0.js
similarity index 100%
rename from code/van-0.11.0.js
rename to assert/code/van-0.11.0.js
diff --git a/code/van-0.11.0.min.js b/assert/code/van-0.11.0.min.js
similarity index 100%
rename from code/van-0.11.0.min.js
rename to assert/code/van-0.11.0.min.js
diff --git a/code/van-0.11.0.nomodule.debug.js b/assert/code/van-0.11.0.nomodule.debug.js
similarity index 100%
rename from code/van-0.11.0.nomodule.debug.js
rename to assert/code/van-0.11.0.nomodule.debug.js
diff --git a/code/van-0.11.0.nomodule.js b/assert/code/van-0.11.0.nomodule.js
similarity index 100%
rename from code/van-0.11.0.nomodule.js
rename to assert/code/van-0.11.0.nomodule.js
diff --git a/code/van-0.11.0.nomodule.min.js b/assert/code/van-0.11.0.nomodule.min.js
similarity index 100%
rename from code/van-0.11.0.nomodule.min.js
rename to assert/code/van-0.11.0.nomodule.min.js
diff --git a/code/van-0.11.1.debug.js b/assert/code/van-0.11.1.debug.js
similarity index 100%
rename from code/van-0.11.1.debug.js
rename to assert/code/van-0.11.1.debug.js
diff --git a/code/van-0.11.1.js b/assert/code/van-0.11.1.js
similarity index 100%
rename from code/van-0.11.1.js
rename to assert/code/van-0.11.1.js
diff --git a/code/van-0.11.1.min.js b/assert/code/van-0.11.1.min.js
similarity index 100%
rename from code/van-0.11.1.min.js
rename to assert/code/van-0.11.1.min.js
diff --git a/code/van-0.11.1.nomodule.debug.js b/assert/code/van-0.11.1.nomodule.debug.js
similarity index 100%
rename from code/van-0.11.1.nomodule.debug.js
rename to assert/code/van-0.11.1.nomodule.debug.js
diff --git a/code/van-0.11.1.nomodule.js b/assert/code/van-0.11.1.nomodule.js
similarity index 100%
rename from code/van-0.11.1.nomodule.js
rename to assert/code/van-0.11.1.nomodule.js
diff --git a/code/van-0.11.1.nomodule.min.js b/assert/code/van-0.11.1.nomodule.min.js
similarity index 100%
rename from code/van-0.11.1.nomodule.min.js
rename to assert/code/van-0.11.1.nomodule.min.js
diff --git a/code/van-0.11.10.d.ts b/assert/code/van-0.11.10.d.ts
similarity index 100%
rename from code/van-0.11.10.d.ts
rename to assert/code/van-0.11.10.d.ts
diff --git a/code/van-0.11.10.debug.d.ts b/assert/code/van-0.11.10.debug.d.ts
similarity index 100%
rename from code/van-0.11.10.debug.d.ts
rename to assert/code/van-0.11.10.debug.d.ts
diff --git a/code/van-0.11.10.debug.js b/assert/code/van-0.11.10.debug.js
similarity index 100%
rename from code/van-0.11.10.debug.js
rename to assert/code/van-0.11.10.debug.js
diff --git a/code/van-0.11.10.js b/assert/code/van-0.11.10.js
similarity index 100%
rename from code/van-0.11.10.js
rename to assert/code/van-0.11.10.js
diff --git a/code/van-0.11.10.min.d.ts b/assert/code/van-0.11.10.min.d.ts
similarity index 100%
rename from code/van-0.11.10.min.d.ts
rename to assert/code/van-0.11.10.min.d.ts
diff --git a/code/van-0.11.10.min.js b/assert/code/van-0.11.10.min.js
similarity index 100%
rename from code/van-0.11.10.min.js
rename to assert/code/van-0.11.10.min.js
diff --git a/code/van-0.11.10.nomodule.debug.js b/assert/code/van-0.11.10.nomodule.debug.js
similarity index 100%
rename from code/van-0.11.10.nomodule.debug.js
rename to assert/code/van-0.11.10.nomodule.debug.js
diff --git a/code/van-0.11.10.nomodule.js b/assert/code/van-0.11.10.nomodule.js
similarity index 100%
rename from code/van-0.11.10.nomodule.js
rename to assert/code/van-0.11.10.nomodule.js
diff --git a/code/van-0.11.10.nomodule.min.js b/assert/code/van-0.11.10.nomodule.min.js
similarity index 100%
rename from code/van-0.11.10.nomodule.min.js
rename to assert/code/van-0.11.10.nomodule.min.js
diff --git a/code/van-0.11.11.d.ts b/assert/code/van-0.11.11.d.ts
similarity index 100%
rename from code/van-0.11.11.d.ts
rename to assert/code/van-0.11.11.d.ts
diff --git a/code/van-0.11.11.debug.d.ts b/assert/code/van-0.11.11.debug.d.ts
similarity index 100%
rename from code/van-0.11.11.debug.d.ts
rename to assert/code/van-0.11.11.debug.d.ts
diff --git a/code/van-0.11.11.debug.js b/assert/code/van-0.11.11.debug.js
similarity index 100%
rename from code/van-0.11.11.debug.js
rename to assert/code/van-0.11.11.debug.js
diff --git a/code/van-0.11.11.js b/assert/code/van-0.11.11.js
similarity index 100%
rename from code/van-0.11.11.js
rename to assert/code/van-0.11.11.js
diff --git a/code/van-0.11.11.min.d.ts b/assert/code/van-0.11.11.min.d.ts
similarity index 100%
rename from code/van-0.11.11.min.d.ts
rename to assert/code/van-0.11.11.min.d.ts
diff --git a/code/van-0.11.11.min.js b/assert/code/van-0.11.11.min.js
similarity index 100%
rename from code/van-0.11.11.min.js
rename to assert/code/van-0.11.11.min.js
diff --git a/code/van-0.11.11.nomodule.debug.js b/assert/code/van-0.11.11.nomodule.debug.js
similarity index 100%
rename from code/van-0.11.11.nomodule.debug.js
rename to assert/code/van-0.11.11.nomodule.debug.js
diff --git a/code/van-0.11.11.nomodule.js b/assert/code/van-0.11.11.nomodule.js
similarity index 100%
rename from code/van-0.11.11.nomodule.js
rename to assert/code/van-0.11.11.nomodule.js
diff --git a/code/van-0.11.11.nomodule.min.js b/assert/code/van-0.11.11.nomodule.min.js
similarity index 100%
rename from code/van-0.11.11.nomodule.min.js
rename to assert/code/van-0.11.11.nomodule.min.js
diff --git a/code/van-0.11.2.debug.js b/assert/code/van-0.11.2.debug.js
similarity index 100%
rename from code/van-0.11.2.debug.js
rename to assert/code/van-0.11.2.debug.js
diff --git a/code/van-0.11.2.js b/assert/code/van-0.11.2.js
similarity index 100%
rename from code/van-0.11.2.js
rename to assert/code/van-0.11.2.js
diff --git a/code/van-0.11.2.min.js b/assert/code/van-0.11.2.min.js
similarity index 100%
rename from code/van-0.11.2.min.js
rename to assert/code/van-0.11.2.min.js
diff --git a/code/van-0.11.2.nomodule.debug.js b/assert/code/van-0.11.2.nomodule.debug.js
similarity index 100%
rename from code/van-0.11.2.nomodule.debug.js
rename to assert/code/van-0.11.2.nomodule.debug.js
diff --git a/code/van-0.11.2.nomodule.js b/assert/code/van-0.11.2.nomodule.js
similarity index 100%
rename from code/van-0.11.2.nomodule.js
rename to assert/code/van-0.11.2.nomodule.js
diff --git a/code/van-0.11.2.nomodule.min.js b/assert/code/van-0.11.2.nomodule.min.js
similarity index 100%
rename from code/van-0.11.2.nomodule.min.js
rename to assert/code/van-0.11.2.nomodule.min.js
diff --git a/code/van-0.11.3.debug.js b/assert/code/van-0.11.3.debug.js
similarity index 100%
rename from code/van-0.11.3.debug.js
rename to assert/code/van-0.11.3.debug.js
diff --git a/code/van-0.11.3.js b/assert/code/van-0.11.3.js
similarity index 100%
rename from code/van-0.11.3.js
rename to assert/code/van-0.11.3.js
diff --git a/code/van-0.11.3.min.js b/assert/code/van-0.11.3.min.js
similarity index 100%
rename from code/van-0.11.3.min.js
rename to assert/code/van-0.11.3.min.js
diff --git a/code/van-0.11.3.nomodule.debug.js b/assert/code/van-0.11.3.nomodule.debug.js
similarity index 100%
rename from code/van-0.11.3.nomodule.debug.js
rename to assert/code/van-0.11.3.nomodule.debug.js
diff --git a/code/van-0.11.3.nomodule.js b/assert/code/van-0.11.3.nomodule.js
similarity index 100%
rename from code/van-0.11.3.nomodule.js
rename to assert/code/van-0.11.3.nomodule.js
diff --git a/code/van-0.11.3.nomodule.min.js b/assert/code/van-0.11.3.nomodule.min.js
similarity index 100%
rename from code/van-0.11.3.nomodule.min.js
rename to assert/code/van-0.11.3.nomodule.min.js
diff --git a/code/van-0.11.4.debug.js b/assert/code/van-0.11.4.debug.js
similarity index 100%
rename from code/van-0.11.4.debug.js
rename to assert/code/van-0.11.4.debug.js
diff --git a/code/van-0.11.4.js b/assert/code/van-0.11.4.js
similarity index 100%
rename from code/van-0.11.4.js
rename to assert/code/van-0.11.4.js
diff --git a/code/van-0.11.4.min.js b/assert/code/van-0.11.4.min.js
similarity index 100%
rename from code/van-0.11.4.min.js
rename to assert/code/van-0.11.4.min.js
diff --git a/code/van-0.11.4.nomodule.debug.js b/assert/code/van-0.11.4.nomodule.debug.js
similarity index 100%
rename from code/van-0.11.4.nomodule.debug.js
rename to assert/code/van-0.11.4.nomodule.debug.js
diff --git a/code/van-0.11.4.nomodule.js b/assert/code/van-0.11.4.nomodule.js
similarity index 100%
rename from code/van-0.11.4.nomodule.js
rename to assert/code/van-0.11.4.nomodule.js
diff --git a/code/van-0.11.4.nomodule.min.js b/assert/code/van-0.11.4.nomodule.min.js
similarity index 100%
rename from code/van-0.11.4.nomodule.min.js
rename to assert/code/van-0.11.4.nomodule.min.js
diff --git a/code/van-0.11.5.debug.js b/assert/code/van-0.11.5.debug.js
similarity index 100%
rename from code/van-0.11.5.debug.js
rename to assert/code/van-0.11.5.debug.js
diff --git a/code/van-0.11.5.js b/assert/code/van-0.11.5.js
similarity index 100%
rename from code/van-0.11.5.js
rename to assert/code/van-0.11.5.js
diff --git a/code/van-0.11.5.min.js b/assert/code/van-0.11.5.min.js
similarity index 100%
rename from code/van-0.11.5.min.js
rename to assert/code/van-0.11.5.min.js
diff --git a/code/van-0.11.5.nomodule.debug.js b/assert/code/van-0.11.5.nomodule.debug.js
similarity index 100%
rename from code/van-0.11.5.nomodule.debug.js
rename to assert/code/van-0.11.5.nomodule.debug.js
diff --git a/code/van-0.11.5.nomodule.js b/assert/code/van-0.11.5.nomodule.js
similarity index 100%
rename from code/van-0.11.5.nomodule.js
rename to assert/code/van-0.11.5.nomodule.js
diff --git a/code/van-0.11.5.nomodule.min.js b/assert/code/van-0.11.5.nomodule.min.js
similarity index 100%
rename from code/van-0.11.5.nomodule.min.js
rename to assert/code/van-0.11.5.nomodule.min.js
diff --git a/code/van-0.11.6.d.ts b/assert/code/van-0.11.6.d.ts
similarity index 100%
rename from code/van-0.11.6.d.ts
rename to assert/code/van-0.11.6.d.ts
diff --git a/code/van-0.11.6.debug.d.ts b/assert/code/van-0.11.6.debug.d.ts
similarity index 100%
rename from code/van-0.11.6.debug.d.ts
rename to assert/code/van-0.11.6.debug.d.ts
diff --git a/code/van-0.11.6.debug.js b/assert/code/van-0.11.6.debug.js
similarity index 100%
rename from code/van-0.11.6.debug.js
rename to assert/code/van-0.11.6.debug.js
diff --git a/code/van-0.11.6.js b/assert/code/van-0.11.6.js
similarity index 100%
rename from code/van-0.11.6.js
rename to assert/code/van-0.11.6.js
diff --git a/code/van-0.11.6.min.d.ts b/assert/code/van-0.11.6.min.d.ts
similarity index 100%
rename from code/van-0.11.6.min.d.ts
rename to assert/code/van-0.11.6.min.d.ts
diff --git a/code/van-0.11.6.min.js b/assert/code/van-0.11.6.min.js
similarity index 100%
rename from code/van-0.11.6.min.js
rename to assert/code/van-0.11.6.min.js
diff --git a/code/van-0.11.6.nomodule.debug.js b/assert/code/van-0.11.6.nomodule.debug.js
similarity index 100%
rename from code/van-0.11.6.nomodule.debug.js
rename to assert/code/van-0.11.6.nomodule.debug.js
diff --git a/code/van-0.11.6.nomodule.js b/assert/code/van-0.11.6.nomodule.js
similarity index 100%
rename from code/van-0.11.6.nomodule.js
rename to assert/code/van-0.11.6.nomodule.js
diff --git a/code/van-0.11.6.nomodule.min.js b/assert/code/van-0.11.6.nomodule.min.js
similarity index 100%
rename from code/van-0.11.6.nomodule.min.js
rename to assert/code/van-0.11.6.nomodule.min.js
diff --git a/code/van-0.11.7.d.ts b/assert/code/van-0.11.7.d.ts
similarity index 100%
rename from code/van-0.11.7.d.ts
rename to assert/code/van-0.11.7.d.ts
diff --git a/code/van-0.11.7.debug.d.ts b/assert/code/van-0.11.7.debug.d.ts
similarity index 100%
rename from code/van-0.11.7.debug.d.ts
rename to assert/code/van-0.11.7.debug.d.ts
diff --git a/code/van-0.11.7.debug.js b/assert/code/van-0.11.7.debug.js
similarity index 100%
rename from code/van-0.11.7.debug.js
rename to assert/code/van-0.11.7.debug.js
diff --git a/code/van-0.11.7.js b/assert/code/van-0.11.7.js
similarity index 100%
rename from code/van-0.11.7.js
rename to assert/code/van-0.11.7.js
diff --git a/code/van-0.11.7.min.d.ts b/assert/code/van-0.11.7.min.d.ts
similarity index 100%
rename from code/van-0.11.7.min.d.ts
rename to assert/code/van-0.11.7.min.d.ts
diff --git a/code/van-0.11.7.min.js b/assert/code/van-0.11.7.min.js
similarity index 100%
rename from code/van-0.11.7.min.js
rename to assert/code/van-0.11.7.min.js
diff --git a/code/van-0.11.7.nomodule.debug.js b/assert/code/van-0.11.7.nomodule.debug.js
similarity index 100%
rename from code/van-0.11.7.nomodule.debug.js
rename to assert/code/van-0.11.7.nomodule.debug.js
diff --git a/code/van-0.11.7.nomodule.js b/assert/code/van-0.11.7.nomodule.js
similarity index 100%
rename from code/van-0.11.7.nomodule.js
rename to assert/code/van-0.11.7.nomodule.js
diff --git a/code/van-0.11.7.nomodule.min.js b/assert/code/van-0.11.7.nomodule.min.js
similarity index 100%
rename from code/van-0.11.7.nomodule.min.js
rename to assert/code/van-0.11.7.nomodule.min.js
diff --git a/code/van-0.11.8.d.ts b/assert/code/van-0.11.8.d.ts
similarity index 100%
rename from code/van-0.11.8.d.ts
rename to assert/code/van-0.11.8.d.ts
diff --git a/code/van-0.11.8.debug.d.ts b/assert/code/van-0.11.8.debug.d.ts
similarity index 100%
rename from code/van-0.11.8.debug.d.ts
rename to assert/code/van-0.11.8.debug.d.ts
diff --git a/code/van-0.11.8.debug.js b/assert/code/van-0.11.8.debug.js
similarity index 100%
rename from code/van-0.11.8.debug.js
rename to assert/code/van-0.11.8.debug.js
diff --git a/code/van-0.11.8.js b/assert/code/van-0.11.8.js
similarity index 100%
rename from code/van-0.11.8.js
rename to assert/code/van-0.11.8.js
diff --git a/code/van-0.11.8.min.d.ts b/assert/code/van-0.11.8.min.d.ts
similarity index 100%
rename from code/van-0.11.8.min.d.ts
rename to assert/code/van-0.11.8.min.d.ts
diff --git a/code/van-0.11.8.min.js b/assert/code/van-0.11.8.min.js
similarity index 100%
rename from code/van-0.11.8.min.js
rename to assert/code/van-0.11.8.min.js
diff --git a/code/van-0.11.8.nomodule.debug.js b/assert/code/van-0.11.8.nomodule.debug.js
similarity index 100%
rename from code/van-0.11.8.nomodule.debug.js
rename to assert/code/van-0.11.8.nomodule.debug.js
diff --git a/code/van-0.11.8.nomodule.js b/assert/code/van-0.11.8.nomodule.js
similarity index 100%
rename from code/van-0.11.8.nomodule.js
rename to assert/code/van-0.11.8.nomodule.js
diff --git a/code/van-0.11.8.nomodule.min.js b/assert/code/van-0.11.8.nomodule.min.js
similarity index 100%
rename from code/van-0.11.8.nomodule.min.js
rename to assert/code/van-0.11.8.nomodule.min.js
diff --git a/code/van-0.11.9.d.ts b/assert/code/van-0.11.9.d.ts
similarity index 100%
rename from code/van-0.11.9.d.ts
rename to assert/code/van-0.11.9.d.ts
diff --git a/code/van-0.11.9.debug.d.ts b/assert/code/van-0.11.9.debug.d.ts
similarity index 100%
rename from code/van-0.11.9.debug.d.ts
rename to assert/code/van-0.11.9.debug.d.ts
diff --git a/code/van-0.11.9.debug.js b/assert/code/van-0.11.9.debug.js
similarity index 100%
rename from code/van-0.11.9.debug.js
rename to assert/code/van-0.11.9.debug.js
diff --git a/code/van-0.11.9.js b/assert/code/van-0.11.9.js
similarity index 100%
rename from code/van-0.11.9.js
rename to assert/code/van-0.11.9.js
diff --git a/code/van-0.11.9.min.d.ts b/assert/code/van-0.11.9.min.d.ts
similarity index 100%
rename from code/van-0.11.9.min.d.ts
rename to assert/code/van-0.11.9.min.d.ts
diff --git a/code/van-0.11.9.min.js b/assert/code/van-0.11.9.min.js
similarity index 100%
rename from code/van-0.11.9.min.js
rename to assert/code/van-0.11.9.min.js
diff --git a/code/van-0.11.9.nomodule.debug.js b/assert/code/van-0.11.9.nomodule.debug.js
similarity index 100%
rename from code/van-0.11.9.nomodule.debug.js
rename to assert/code/van-0.11.9.nomodule.debug.js
diff --git a/code/van-0.11.9.nomodule.js b/assert/code/van-0.11.9.nomodule.js
similarity index 100%
rename from code/van-0.11.9.nomodule.js
rename to assert/code/van-0.11.9.nomodule.js
diff --git a/code/van-0.11.9.nomodule.min.js b/assert/code/van-0.11.9.nomodule.min.js
similarity index 100%
rename from code/van-0.11.9.nomodule.min.js
rename to assert/code/van-0.11.9.nomodule.min.js
diff --git a/code/van-0.12.0.d.ts b/assert/code/van-0.12.0.d.ts
similarity index 100%
rename from code/van-0.12.0.d.ts
rename to assert/code/van-0.12.0.d.ts
diff --git a/code/van-0.12.0.debug.d.ts b/assert/code/van-0.12.0.debug.d.ts
similarity index 100%
rename from code/van-0.12.0.debug.d.ts
rename to assert/code/van-0.12.0.debug.d.ts
diff --git a/code/van-0.12.0.debug.js b/assert/code/van-0.12.0.debug.js
similarity index 100%
rename from code/van-0.12.0.debug.js
rename to assert/code/van-0.12.0.debug.js
diff --git a/code/van-0.12.0.js b/assert/code/van-0.12.0.js
similarity index 100%
rename from code/van-0.12.0.js
rename to assert/code/van-0.12.0.js
diff --git a/code/van-0.12.0.min.d.ts b/assert/code/van-0.12.0.min.d.ts
similarity index 100%
rename from code/van-0.12.0.min.d.ts
rename to assert/code/van-0.12.0.min.d.ts
diff --git a/code/van-0.12.0.min.js b/assert/code/van-0.12.0.min.js
similarity index 100%
rename from code/van-0.12.0.min.js
rename to assert/code/van-0.12.0.min.js
diff --git a/code/van-0.12.0.nomodule.debug.js b/assert/code/van-0.12.0.nomodule.debug.js
similarity index 100%
rename from code/van-0.12.0.nomodule.debug.js
rename to assert/code/van-0.12.0.nomodule.debug.js
diff --git a/code/van-0.12.0.nomodule.js b/assert/code/van-0.12.0.nomodule.js
similarity index 100%
rename from code/van-0.12.0.nomodule.js
rename to assert/code/van-0.12.0.nomodule.js
diff --git a/code/van-0.12.0.nomodule.min.js b/assert/code/van-0.12.0.nomodule.min.js
similarity index 100%
rename from code/van-0.12.0.nomodule.min.js
rename to assert/code/van-0.12.0.nomodule.min.js
diff --git a/code/van-0.12.1.d.ts b/assert/code/van-0.12.1.d.ts
similarity index 100%
rename from code/van-0.12.1.d.ts
rename to assert/code/van-0.12.1.d.ts
diff --git a/code/van-0.12.1.debug.d.ts b/assert/code/van-0.12.1.debug.d.ts
similarity index 100%
rename from code/van-0.12.1.debug.d.ts
rename to assert/code/van-0.12.1.debug.d.ts
diff --git a/code/van-0.12.1.debug.js b/assert/code/van-0.12.1.debug.js
similarity index 100%
rename from code/van-0.12.1.debug.js
rename to assert/code/van-0.12.1.debug.js
diff --git a/code/van-0.12.1.js b/assert/code/van-0.12.1.js
similarity index 100%
rename from code/van-0.12.1.js
rename to assert/code/van-0.12.1.js
diff --git a/code/van-0.12.1.min.d.ts b/assert/code/van-0.12.1.min.d.ts
similarity index 100%
rename from code/van-0.12.1.min.d.ts
rename to assert/code/van-0.12.1.min.d.ts
diff --git a/code/van-0.12.1.min.js b/assert/code/van-0.12.1.min.js
similarity index 100%
rename from code/van-0.12.1.min.js
rename to assert/code/van-0.12.1.min.js
diff --git a/code/van-0.12.1.nomodule.debug.js b/assert/code/van-0.12.1.nomodule.debug.js
similarity index 100%
rename from code/van-0.12.1.nomodule.debug.js
rename to assert/code/van-0.12.1.nomodule.debug.js
diff --git a/code/van-0.12.1.nomodule.js b/assert/code/van-0.12.1.nomodule.js
similarity index 100%
rename from code/van-0.12.1.nomodule.js
rename to assert/code/van-0.12.1.nomodule.js
diff --git a/code/van-0.12.1.nomodule.min.js b/assert/code/van-0.12.1.nomodule.min.js
similarity index 100%
rename from code/van-0.12.1.nomodule.min.js
rename to assert/code/van-0.12.1.nomodule.min.js
diff --git a/code/van-0.12.2.d.ts b/assert/code/van-0.12.2.d.ts
similarity index 100%
rename from code/van-0.12.2.d.ts
rename to assert/code/van-0.12.2.d.ts
diff --git a/code/van-0.12.2.debug.d.ts b/assert/code/van-0.12.2.debug.d.ts
similarity index 100%
rename from code/van-0.12.2.debug.d.ts
rename to assert/code/van-0.12.2.debug.d.ts
diff --git a/code/van-0.12.2.debug.js b/assert/code/van-0.12.2.debug.js
similarity index 100%
rename from code/van-0.12.2.debug.js
rename to assert/code/van-0.12.2.debug.js
diff --git a/code/van-0.12.2.js b/assert/code/van-0.12.2.js
similarity index 100%
rename from code/van-0.12.2.js
rename to assert/code/van-0.12.2.js
diff --git a/code/van-0.12.2.min.d.ts b/assert/code/van-0.12.2.min.d.ts
similarity index 100%
rename from code/van-0.12.2.min.d.ts
rename to assert/code/van-0.12.2.min.d.ts
diff --git a/code/van-0.12.2.min.js b/assert/code/van-0.12.2.min.js
similarity index 100%
rename from code/van-0.12.2.min.js
rename to assert/code/van-0.12.2.min.js
diff --git a/code/van-0.12.2.nomodule.debug.js b/assert/code/van-0.12.2.nomodule.debug.js
similarity index 100%
rename from code/van-0.12.2.nomodule.debug.js
rename to assert/code/van-0.12.2.nomodule.debug.js
diff --git a/code/van-0.12.2.nomodule.js b/assert/code/van-0.12.2.nomodule.js
similarity index 100%
rename from code/van-0.12.2.nomodule.js
rename to assert/code/van-0.12.2.nomodule.js
diff --git a/code/van-0.12.2.nomodule.min.js b/assert/code/van-0.12.2.nomodule.min.js
similarity index 100%
rename from code/van-0.12.2.nomodule.min.js
rename to assert/code/van-0.12.2.nomodule.min.js
diff --git a/code/van-0.12.3.d.ts b/assert/code/van-0.12.3.d.ts
similarity index 100%
rename from code/van-0.12.3.d.ts
rename to assert/code/van-0.12.3.d.ts
diff --git a/code/van-0.12.3.debug.d.ts b/assert/code/van-0.12.3.debug.d.ts
similarity index 100%
rename from code/van-0.12.3.debug.d.ts
rename to assert/code/van-0.12.3.debug.d.ts
diff --git a/code/van-0.12.3.debug.js b/assert/code/van-0.12.3.debug.js
similarity index 100%
rename from code/van-0.12.3.debug.js
rename to assert/code/van-0.12.3.debug.js
diff --git a/code/van-0.12.3.js b/assert/code/van-0.12.3.js
similarity index 100%
rename from code/van-0.12.3.js
rename to assert/code/van-0.12.3.js
diff --git a/code/van-0.12.3.min.d.ts b/assert/code/van-0.12.3.min.d.ts
similarity index 100%
rename from code/van-0.12.3.min.d.ts
rename to assert/code/van-0.12.3.min.d.ts
diff --git a/code/van-0.12.3.min.js b/assert/code/van-0.12.3.min.js
similarity index 100%
rename from code/van-0.12.3.min.js
rename to assert/code/van-0.12.3.min.js
diff --git a/code/van-0.12.3.nomodule.debug.js b/assert/code/van-0.12.3.nomodule.debug.js
similarity index 100%
rename from code/van-0.12.3.nomodule.debug.js
rename to assert/code/van-0.12.3.nomodule.debug.js
diff --git a/code/van-0.12.3.nomodule.js b/assert/code/van-0.12.3.nomodule.js
similarity index 100%
rename from code/van-0.12.3.nomodule.js
rename to assert/code/van-0.12.3.nomodule.js
diff --git a/code/van-0.12.3.nomodule.min.js b/assert/code/van-0.12.3.nomodule.min.js
similarity index 100%
rename from code/van-0.12.3.nomodule.min.js
rename to assert/code/van-0.12.3.nomodule.min.js
diff --git a/code/van-0.12.4.d.ts b/assert/code/van-0.12.4.d.ts
similarity index 100%
rename from code/van-0.12.4.d.ts
rename to assert/code/van-0.12.4.d.ts
diff --git a/code/van-0.12.4.debug.d.ts b/assert/code/van-0.12.4.debug.d.ts
similarity index 100%
rename from code/van-0.12.4.debug.d.ts
rename to assert/code/van-0.12.4.debug.d.ts
diff --git a/code/van-0.12.4.debug.js b/assert/code/van-0.12.4.debug.js
similarity index 100%
rename from code/van-0.12.4.debug.js
rename to assert/code/van-0.12.4.debug.js
diff --git a/code/van-0.12.4.js b/assert/code/van-0.12.4.js
similarity index 100%
rename from code/van-0.12.4.js
rename to assert/code/van-0.12.4.js
diff --git a/code/van-0.12.4.min.d.ts b/assert/code/van-0.12.4.min.d.ts
similarity index 100%
rename from code/van-0.12.4.min.d.ts
rename to assert/code/van-0.12.4.min.d.ts
diff --git a/code/van-0.12.4.min.js b/assert/code/van-0.12.4.min.js
similarity index 100%
rename from code/van-0.12.4.min.js
rename to assert/code/van-0.12.4.min.js
diff --git a/code/van-0.12.4.nomodule.debug.js b/assert/code/van-0.12.4.nomodule.debug.js
similarity index 100%
rename from code/van-0.12.4.nomodule.debug.js
rename to assert/code/van-0.12.4.nomodule.debug.js
diff --git a/code/van-0.12.4.nomodule.js b/assert/code/van-0.12.4.nomodule.js
similarity index 100%
rename from code/van-0.12.4.nomodule.js
rename to assert/code/van-0.12.4.nomodule.js
diff --git a/code/van-0.12.4.nomodule.min.js b/assert/code/van-0.12.4.nomodule.min.js
similarity index 100%
rename from code/van-0.12.4.nomodule.min.js
rename to assert/code/van-0.12.4.nomodule.min.js
diff --git a/code/van-0.2.0.js b/assert/code/van-0.2.0.js
similarity index 100%
rename from code/van-0.2.0.js
rename to assert/code/van-0.2.0.js
diff --git a/code/van-0.2.0.min.js b/assert/code/van-0.2.0.min.js
similarity index 100%
rename from code/van-0.2.0.min.js
rename to assert/code/van-0.2.0.min.js
diff --git a/code/van-0.2.1.js b/assert/code/van-0.2.1.js
similarity index 100%
rename from code/van-0.2.1.js
rename to assert/code/van-0.2.1.js
diff --git a/code/van-0.2.1.min.js b/assert/code/van-0.2.1.min.js
similarity index 100%
rename from code/van-0.2.1.min.js
rename to assert/code/van-0.2.1.min.js
diff --git a/code/van-0.2.2.js b/assert/code/van-0.2.2.js
similarity index 100%
rename from code/van-0.2.2.js
rename to assert/code/van-0.2.2.js
diff --git a/code/van-0.2.2.min.js b/assert/code/van-0.2.2.min.js
similarity index 100%
rename from code/van-0.2.2.min.js
rename to assert/code/van-0.2.2.min.js
diff --git a/code/van-0.2.3.js b/assert/code/van-0.2.3.js
similarity index 100%
rename from code/van-0.2.3.js
rename to assert/code/van-0.2.3.js
diff --git a/code/van-0.2.3.min.js b/assert/code/van-0.2.3.min.js
similarity index 100%
rename from code/van-0.2.3.min.js
rename to assert/code/van-0.2.3.min.js
diff --git a/code/van-0.2.4.js b/assert/code/van-0.2.4.js
similarity index 100%
rename from code/van-0.2.4.js
rename to assert/code/van-0.2.4.js
diff --git a/code/van-0.2.4.min.js b/assert/code/van-0.2.4.min.js
similarity index 100%
rename from code/van-0.2.4.min.js
rename to assert/code/van-0.2.4.min.js
diff --git a/code/van-0.2.5.js b/assert/code/van-0.2.5.js
similarity index 100%
rename from code/van-0.2.5.js
rename to assert/code/van-0.2.5.js
diff --git a/code/van-0.2.5.min.js b/assert/code/van-0.2.5.min.js
similarity index 100%
rename from code/van-0.2.5.min.js
rename to assert/code/van-0.2.5.min.js
diff --git a/code/van-0.3.0.js b/assert/code/van-0.3.0.js
similarity index 100%
rename from code/van-0.3.0.js
rename to assert/code/van-0.3.0.js
diff --git a/code/van-0.3.0.min.js b/assert/code/van-0.3.0.min.js
similarity index 100%
rename from code/van-0.3.0.min.js
rename to assert/code/van-0.3.0.min.js
diff --git a/code/van-0.3.1.js b/assert/code/van-0.3.1.js
similarity index 100%
rename from code/van-0.3.1.js
rename to assert/code/van-0.3.1.js
diff --git a/code/van-0.3.1.min.js b/assert/code/van-0.3.1.min.js
similarity index 100%
rename from code/van-0.3.1.min.js
rename to assert/code/van-0.3.1.min.js
diff --git a/code/van-0.3.2.js b/assert/code/van-0.3.2.js
similarity index 100%
rename from code/van-0.3.2.js
rename to assert/code/van-0.3.2.js
diff --git a/code/van-0.3.2.min.js b/assert/code/van-0.3.2.min.js
similarity index 100%
rename from code/van-0.3.2.min.js
rename to assert/code/van-0.3.2.min.js
diff --git a/code/van-0.3.3.js b/assert/code/van-0.3.3.js
similarity index 100%
rename from code/van-0.3.3.js
rename to assert/code/van-0.3.3.js
diff --git a/code/van-0.3.3.min.js b/assert/code/van-0.3.3.min.js
similarity index 100%
rename from code/van-0.3.3.min.js
rename to assert/code/van-0.3.3.min.js
diff --git a/code/van-0.3.4.js b/assert/code/van-0.3.4.js
similarity index 100%
rename from code/van-0.3.4.js
rename to assert/code/van-0.3.4.js
diff --git a/code/van-0.3.4.min.js b/assert/code/van-0.3.4.min.js
similarity index 100%
rename from code/van-0.3.4.min.js
rename to assert/code/van-0.3.4.min.js
diff --git a/code/van-0.3.5.js b/assert/code/van-0.3.5.js
similarity index 100%
rename from code/van-0.3.5.js
rename to assert/code/van-0.3.5.js
diff --git a/code/van-0.3.5.min.js b/assert/code/van-0.3.5.min.js
similarity index 100%
rename from code/van-0.3.5.min.js
rename to assert/code/van-0.3.5.min.js
diff --git a/code/van-0.4.0.js b/assert/code/van-0.4.0.js
similarity index 100%
rename from code/van-0.4.0.js
rename to assert/code/van-0.4.0.js
diff --git a/code/van-0.4.0.min.js b/assert/code/van-0.4.0.min.js
similarity index 100%
rename from code/van-0.4.0.min.js
rename to assert/code/van-0.4.0.min.js
diff --git a/code/van-0.4.1.js b/assert/code/van-0.4.1.js
similarity index 100%
rename from code/van-0.4.1.js
rename to assert/code/van-0.4.1.js
diff --git a/code/van-0.4.1.min.js b/assert/code/van-0.4.1.min.js
similarity index 100%
rename from code/van-0.4.1.min.js
rename to assert/code/van-0.4.1.min.js
diff --git a/code/van-0.5.0.js b/assert/code/van-0.5.0.js
similarity index 100%
rename from code/van-0.5.0.js
rename to assert/code/van-0.5.0.js
diff --git a/code/van-0.5.0.min.js b/assert/code/van-0.5.0.min.js
similarity index 100%
rename from code/van-0.5.0.min.js
rename to assert/code/van-0.5.0.min.js
diff --git a/code/van-0.6.0.js b/assert/code/van-0.6.0.js
similarity index 100%
rename from code/van-0.6.0.js
rename to assert/code/van-0.6.0.js
diff --git a/code/van-0.6.0.min.js b/assert/code/van-0.6.0.min.js
similarity index 100%
rename from code/van-0.6.0.min.js
rename to assert/code/van-0.6.0.min.js
diff --git a/code/van-0.6.1.js b/assert/code/van-0.6.1.js
similarity index 100%
rename from code/van-0.6.1.js
rename to assert/code/van-0.6.1.js
diff --git a/code/van-0.6.1.min.js b/assert/code/van-0.6.1.min.js
similarity index 100%
rename from code/van-0.6.1.min.js
rename to assert/code/van-0.6.1.min.js
diff --git a/code/van-0.6.2.js b/assert/code/van-0.6.2.js
similarity index 100%
rename from code/van-0.6.2.js
rename to assert/code/van-0.6.2.js
diff --git a/code/van-0.6.2.min.js b/assert/code/van-0.6.2.min.js
similarity index 100%
rename from code/van-0.6.2.min.js
rename to assert/code/van-0.6.2.min.js
diff --git a/code/van-0.6.3.js b/assert/code/van-0.6.3.js
similarity index 100%
rename from code/van-0.6.3.js
rename to assert/code/van-0.6.3.js
diff --git a/code/van-0.6.3.min.js b/assert/code/van-0.6.3.min.js
similarity index 100%
rename from code/van-0.6.3.min.js
rename to assert/code/van-0.6.3.min.js
diff --git a/code/van-0.6.4.js b/assert/code/van-0.6.4.js
similarity index 100%
rename from code/van-0.6.4.js
rename to assert/code/van-0.6.4.js
diff --git a/code/van-0.6.4.min.js b/assert/code/van-0.6.4.min.js
similarity index 100%
rename from code/van-0.6.4.min.js
rename to assert/code/van-0.6.4.min.js
diff --git a/code/van-0.6.4.nomodule.js b/assert/code/van-0.6.4.nomodule.js
similarity index 100%
rename from code/van-0.6.4.nomodule.js
rename to assert/code/van-0.6.4.nomodule.js
diff --git a/code/van-0.6.4.nomodule.min.js b/assert/code/van-0.6.4.nomodule.min.js
similarity index 100%
rename from code/van-0.6.4.nomodule.min.js
rename to assert/code/van-0.6.4.nomodule.min.js
diff --git a/code/van-0.7.0.js b/assert/code/van-0.7.0.js
similarity index 100%
rename from code/van-0.7.0.js
rename to assert/code/van-0.7.0.js
diff --git a/code/van-0.7.0.min.js b/assert/code/van-0.7.0.min.js
similarity index 100%
rename from code/van-0.7.0.min.js
rename to assert/code/van-0.7.0.min.js
diff --git a/code/van-0.7.0.nomodule.js b/assert/code/van-0.7.0.nomodule.js
similarity index 100%
rename from code/van-0.7.0.nomodule.js
rename to assert/code/van-0.7.0.nomodule.js
diff --git a/code/van-0.7.0.nomodule.min.js b/assert/code/van-0.7.0.nomodule.min.js
similarity index 100%
rename from code/van-0.7.0.nomodule.min.js
rename to assert/code/van-0.7.0.nomodule.min.js
diff --git a/code/van-0.7.1.js b/assert/code/van-0.7.1.js
similarity index 100%
rename from code/van-0.7.1.js
rename to assert/code/van-0.7.1.js
diff --git a/code/van-0.7.1.min.js b/assert/code/van-0.7.1.min.js
similarity index 100%
rename from code/van-0.7.1.min.js
rename to assert/code/van-0.7.1.min.js
diff --git a/code/van-0.7.1.nomodule.js b/assert/code/van-0.7.1.nomodule.js
similarity index 100%
rename from code/van-0.7.1.nomodule.js
rename to assert/code/van-0.7.1.nomodule.js
diff --git a/code/van-0.7.1.nomodule.min.js b/assert/code/van-0.7.1.nomodule.min.js
similarity index 100%
rename from code/van-0.7.1.nomodule.min.js
rename to assert/code/van-0.7.1.nomodule.min.js
diff --git a/code/van-0.7.2.js b/assert/code/van-0.7.2.js
similarity index 100%
rename from code/van-0.7.2.js
rename to assert/code/van-0.7.2.js
diff --git a/code/van-0.7.2.min.js b/assert/code/van-0.7.2.min.js
similarity index 100%
rename from code/van-0.7.2.min.js
rename to assert/code/van-0.7.2.min.js
diff --git a/code/van-0.7.2.nomodule.js b/assert/code/van-0.7.2.nomodule.js
similarity index 100%
rename from code/van-0.7.2.nomodule.js
rename to assert/code/van-0.7.2.nomodule.js
diff --git a/code/van-0.7.2.nomodule.min.js b/assert/code/van-0.7.2.nomodule.min.js
similarity index 100%
rename from code/van-0.7.2.nomodule.min.js
rename to assert/code/van-0.7.2.nomodule.min.js
diff --git a/code/van-0.8.0.js b/assert/code/van-0.8.0.js
similarity index 100%
rename from code/van-0.8.0.js
rename to assert/code/van-0.8.0.js
diff --git a/code/van-0.8.0.min.js b/assert/code/van-0.8.0.min.js
similarity index 100%
rename from code/van-0.8.0.min.js
rename to assert/code/van-0.8.0.min.js
diff --git a/code/van-0.8.0.nomodule.js b/assert/code/van-0.8.0.nomodule.js
similarity index 100%
rename from code/van-0.8.0.nomodule.js
rename to assert/code/van-0.8.0.nomodule.js
diff --git a/code/van-0.8.0.nomodule.min.js b/assert/code/van-0.8.0.nomodule.min.js
similarity index 100%
rename from code/van-0.8.0.nomodule.min.js
rename to assert/code/van-0.8.0.nomodule.min.js
diff --git a/code/van-0.8.1.js b/assert/code/van-0.8.1.js
similarity index 100%
rename from code/van-0.8.1.js
rename to assert/code/van-0.8.1.js
diff --git a/code/van-0.8.1.min.js b/assert/code/van-0.8.1.min.js
similarity index 100%
rename from code/van-0.8.1.min.js
rename to assert/code/van-0.8.1.min.js
diff --git a/code/van-0.8.1.nomodule.js b/assert/code/van-0.8.1.nomodule.js
similarity index 100%
rename from code/van-0.8.1.nomodule.js
rename to assert/code/van-0.8.1.nomodule.js
diff --git a/code/van-0.8.1.nomodule.min.js b/assert/code/van-0.8.1.nomodule.min.js
similarity index 100%
rename from code/van-0.8.1.nomodule.min.js
rename to assert/code/van-0.8.1.nomodule.min.js
diff --git a/code/van-0.9.0.js b/assert/code/van-0.9.0.js
similarity index 100%
rename from code/van-0.9.0.js
rename to assert/code/van-0.9.0.js
diff --git a/code/van-0.9.0.min.js b/assert/code/van-0.9.0.min.js
similarity index 100%
rename from code/van-0.9.0.min.js
rename to assert/code/van-0.9.0.min.js
diff --git a/code/van-0.9.0.nomodule.js b/assert/code/van-0.9.0.nomodule.js
similarity index 100%
rename from code/van-0.9.0.nomodule.js
rename to assert/code/van-0.9.0.nomodule.js
diff --git a/code/van-0.9.0.nomodule.min.js b/assert/code/van-0.9.0.nomodule.min.js
similarity index 100%
rename from code/van-0.9.0.nomodule.min.js
rename to assert/code/van-0.9.0.nomodule.min.js
diff --git a/code/van-0.9.1.js b/assert/code/van-0.9.1.js
similarity index 100%
rename from code/van-0.9.1.js
rename to assert/code/van-0.9.1.js
diff --git a/code/van-0.9.1.min.js b/assert/code/van-0.9.1.min.js
similarity index 100%
rename from code/van-0.9.1.min.js
rename to assert/code/van-0.9.1.min.js
diff --git a/code/van-0.9.1.nomodule.js b/assert/code/van-0.9.1.nomodule.js
similarity index 100%
rename from code/van-0.9.1.nomodule.js
rename to assert/code/van-0.9.1.nomodule.js
diff --git a/code/van-0.9.1.nomodule.min.js b/assert/code/van-0.9.1.nomodule.min.js
similarity index 100%
rename from code/van-0.9.1.nomodule.min.js
rename to assert/code/van-0.9.1.nomodule.min.js
diff --git a/code/van-0.9.2.js b/assert/code/van-0.9.2.js
similarity index 100%
rename from code/van-0.9.2.js
rename to assert/code/van-0.9.2.js
diff --git a/code/van-0.9.2.min.js b/assert/code/van-0.9.2.min.js
similarity index 100%
rename from code/van-0.9.2.min.js
rename to assert/code/van-0.9.2.min.js
diff --git a/code/van-0.9.2.nomodule.js b/assert/code/van-0.9.2.nomodule.js
similarity index 100%
rename from code/van-0.9.2.nomodule.js
rename to assert/code/van-0.9.2.nomodule.js
diff --git a/code/van-0.9.2.nomodule.min.js b/assert/code/van-0.9.2.nomodule.min.js
similarity index 100%
rename from code/van-0.9.2.nomodule.min.js
rename to assert/code/van-0.9.2.nomodule.min.js
diff --git a/code/van-0.9.3.debug.js b/assert/code/van-0.9.3.debug.js
similarity index 100%
rename from code/van-0.9.3.debug.js
rename to assert/code/van-0.9.3.debug.js
diff --git a/code/van-0.9.3.js b/assert/code/van-0.9.3.js
similarity index 100%
rename from code/van-0.9.3.js
rename to assert/code/van-0.9.3.js
diff --git a/code/van-0.9.3.min.js b/assert/code/van-0.9.3.min.js
similarity index 100%
rename from code/van-0.9.3.min.js
rename to assert/code/van-0.9.3.min.js
diff --git a/code/van-0.9.3.nomodule.debug.js b/assert/code/van-0.9.3.nomodule.debug.js
similarity index 100%
rename from code/van-0.9.3.nomodule.debug.js
rename to assert/code/van-0.9.3.nomodule.debug.js
diff --git a/code/van-0.9.3.nomodule.js b/assert/code/van-0.9.3.nomodule.js
similarity index 100%
rename from code/van-0.9.3.nomodule.js
rename to assert/code/van-0.9.3.nomodule.js
diff --git a/code/van-0.9.3.nomodule.min.js b/assert/code/van-0.9.3.nomodule.min.js
similarity index 100%
rename from code/van-0.9.3.nomodule.min.js
rename to assert/code/van-0.9.3.nomodule.min.js
diff --git a/code/van-1.0.0.d.ts b/assert/code/van-1.0.0.d.ts
similarity index 100%
rename from code/van-1.0.0.d.ts
rename to assert/code/van-1.0.0.d.ts
diff --git a/code/van-1.0.0.debug.d.ts b/assert/code/van-1.0.0.debug.d.ts
similarity index 100%
rename from code/van-1.0.0.debug.d.ts
rename to assert/code/van-1.0.0.debug.d.ts
diff --git a/code/van-1.0.0.debug.js b/assert/code/van-1.0.0.debug.js
similarity index 100%
rename from code/van-1.0.0.debug.js
rename to assert/code/van-1.0.0.debug.js
diff --git a/code/van-1.0.0.js b/assert/code/van-1.0.0.js
similarity index 100%
rename from code/van-1.0.0.js
rename to assert/code/van-1.0.0.js
diff --git a/code/van-1.0.0.min.d.ts b/assert/code/van-1.0.0.min.d.ts
similarity index 100%
rename from code/van-1.0.0.min.d.ts
rename to assert/code/van-1.0.0.min.d.ts
diff --git a/code/van-1.0.0.min.js b/assert/code/van-1.0.0.min.js
similarity index 100%
rename from code/van-1.0.0.min.js
rename to assert/code/van-1.0.0.min.js
diff --git a/code/van-1.0.0.nomodule.debug.js b/assert/code/van-1.0.0.nomodule.debug.js
similarity index 100%
rename from code/van-1.0.0.nomodule.debug.js
rename to assert/code/van-1.0.0.nomodule.debug.js
diff --git a/code/van-1.0.0.nomodule.js b/assert/code/van-1.0.0.nomodule.js
similarity index 100%
rename from code/van-1.0.0.nomodule.js
rename to assert/code/van-1.0.0.nomodule.js
diff --git a/code/van-1.0.0.nomodule.min.js b/assert/code/van-1.0.0.nomodule.min.js
similarity index 100%
rename from code/van-1.0.0.nomodule.min.js
rename to assert/code/van-1.0.0.nomodule.min.js
diff --git a/code/van-1.0.1.d.ts b/assert/code/van-1.0.1.d.ts
similarity index 100%
rename from code/van-1.0.1.d.ts
rename to assert/code/van-1.0.1.d.ts
diff --git a/code/van-1.0.1.debug.d.ts b/assert/code/van-1.0.1.debug.d.ts
similarity index 100%
rename from code/van-1.0.1.debug.d.ts
rename to assert/code/van-1.0.1.debug.d.ts
diff --git a/code/van-1.0.1.debug.js b/assert/code/van-1.0.1.debug.js
similarity index 100%
rename from code/van-1.0.1.debug.js
rename to assert/code/van-1.0.1.debug.js
diff --git a/code/van-1.0.1.js b/assert/code/van-1.0.1.js
similarity index 100%
rename from code/van-1.0.1.js
rename to assert/code/van-1.0.1.js
diff --git a/code/van-1.0.1.min.d.ts b/assert/code/van-1.0.1.min.d.ts
similarity index 100%
rename from code/van-1.0.1.min.d.ts
rename to assert/code/van-1.0.1.min.d.ts
diff --git a/code/van-1.0.1.min.js b/assert/code/van-1.0.1.min.js
similarity index 100%
rename from code/van-1.0.1.min.js
rename to assert/code/van-1.0.1.min.js
diff --git a/code/van-1.0.1.nomodule.debug.js b/assert/code/van-1.0.1.nomodule.debug.js
similarity index 100%
rename from code/van-1.0.1.nomodule.debug.js
rename to assert/code/van-1.0.1.nomodule.debug.js
diff --git a/code/van-1.0.1.nomodule.js b/assert/code/van-1.0.1.nomodule.js
similarity index 100%
rename from code/van-1.0.1.nomodule.js
rename to assert/code/van-1.0.1.nomodule.js
diff --git a/code/van-1.0.1.nomodule.min.js b/assert/code/van-1.0.1.nomodule.min.js
similarity index 100%
rename from code/van-1.0.1.nomodule.min.js
rename to assert/code/van-1.0.1.nomodule.min.js
diff --git a/code/van-1.0.2.d.ts b/assert/code/van-1.0.2.d.ts
similarity index 100%
rename from code/van-1.0.2.d.ts
rename to assert/code/van-1.0.2.d.ts
diff --git a/code/van-1.0.2.debug.d.ts b/assert/code/van-1.0.2.debug.d.ts
similarity index 100%
rename from code/van-1.0.2.debug.d.ts
rename to assert/code/van-1.0.2.debug.d.ts
diff --git a/code/van-1.0.2.debug.js b/assert/code/van-1.0.2.debug.js
similarity index 100%
rename from code/van-1.0.2.debug.js
rename to assert/code/van-1.0.2.debug.js
diff --git a/code/van-1.0.2.js b/assert/code/van-1.0.2.js
similarity index 100%
rename from code/van-1.0.2.js
rename to assert/code/van-1.0.2.js
diff --git a/code/van-1.0.2.min.d.ts b/assert/code/van-1.0.2.min.d.ts
similarity index 100%
rename from code/van-1.0.2.min.d.ts
rename to assert/code/van-1.0.2.min.d.ts
diff --git a/code/van-1.0.2.min.js b/assert/code/van-1.0.2.min.js
similarity index 100%
rename from code/van-1.0.2.min.js
rename to assert/code/van-1.0.2.min.js
diff --git a/code/van-1.0.2.nomodule.debug.js b/assert/code/van-1.0.2.nomodule.debug.js
similarity index 100%
rename from code/van-1.0.2.nomodule.debug.js
rename to assert/code/van-1.0.2.nomodule.debug.js
diff --git a/code/van-1.0.2.nomodule.js b/assert/code/van-1.0.2.nomodule.js
similarity index 100%
rename from code/van-1.0.2.nomodule.js
rename to assert/code/van-1.0.2.nomodule.js
diff --git a/code/van-1.0.2.nomodule.min.js b/assert/code/van-1.0.2.nomodule.min.js
similarity index 100%
rename from code/van-1.0.2.nomodule.min.js
rename to assert/code/van-1.0.2.nomodule.min.js
diff --git a/code/van-1.1.0.d.ts b/assert/code/van-1.1.0.d.ts
similarity index 100%
rename from code/van-1.1.0.d.ts
rename to assert/code/van-1.1.0.d.ts
diff --git a/code/van-1.1.0.debug.d.ts b/assert/code/van-1.1.0.debug.d.ts
similarity index 100%
rename from code/van-1.1.0.debug.d.ts
rename to assert/code/van-1.1.0.debug.d.ts
diff --git a/code/van-1.1.0.debug.js b/assert/code/van-1.1.0.debug.js
similarity index 100%
rename from code/van-1.1.0.debug.js
rename to assert/code/van-1.1.0.debug.js
diff --git a/code/van-1.1.0.js b/assert/code/van-1.1.0.js
similarity index 100%
rename from code/van-1.1.0.js
rename to assert/code/van-1.1.0.js
diff --git a/code/van-1.1.0.min.d.ts b/assert/code/van-1.1.0.min.d.ts
similarity index 100%
rename from code/van-1.1.0.min.d.ts
rename to assert/code/van-1.1.0.min.d.ts
diff --git a/code/van-1.1.0.min.js b/assert/code/van-1.1.0.min.js
similarity index 100%
rename from code/van-1.1.0.min.js
rename to assert/code/van-1.1.0.min.js
diff --git a/code/van-1.1.0.nomodule.debug.js b/assert/code/van-1.1.0.nomodule.debug.js
similarity index 100%
rename from code/van-1.1.0.nomodule.debug.js
rename to assert/code/van-1.1.0.nomodule.debug.js
diff --git a/code/van-1.1.0.nomodule.js b/assert/code/van-1.1.0.nomodule.js
similarity index 100%
rename from code/van-1.1.0.nomodule.js
rename to assert/code/van-1.1.0.nomodule.js
diff --git a/code/van-1.1.0.nomodule.min.js b/assert/code/van-1.1.0.nomodule.min.js
similarity index 100%
rename from code/van-1.1.0.nomodule.min.js
rename to assert/code/van-1.1.0.nomodule.min.js
diff --git a/code/van-1.1.1.d.ts b/assert/code/van-1.1.1.d.ts
similarity index 100%
rename from code/van-1.1.1.d.ts
rename to assert/code/van-1.1.1.d.ts
diff --git a/code/van-1.1.1.debug.d.ts b/assert/code/van-1.1.1.debug.d.ts
similarity index 100%
rename from code/van-1.1.1.debug.d.ts
rename to assert/code/van-1.1.1.debug.d.ts
diff --git a/code/van-1.1.1.debug.js b/assert/code/van-1.1.1.debug.js
similarity index 100%
rename from code/van-1.1.1.debug.js
rename to assert/code/van-1.1.1.debug.js
diff --git a/code/van-1.1.1.js b/assert/code/van-1.1.1.js
similarity index 100%
rename from code/van-1.1.1.js
rename to assert/code/van-1.1.1.js
diff --git a/code/van-1.1.1.min.d.ts b/assert/code/van-1.1.1.min.d.ts
similarity index 100%
rename from code/van-1.1.1.min.d.ts
rename to assert/code/van-1.1.1.min.d.ts
diff --git a/code/van-1.1.1.min.js b/assert/code/van-1.1.1.min.js
similarity index 100%
rename from code/van-1.1.1.min.js
rename to assert/code/van-1.1.1.min.js
diff --git a/code/van-1.1.1.nomodule.debug.js b/assert/code/van-1.1.1.nomodule.debug.js
similarity index 100%
rename from code/van-1.1.1.nomodule.debug.js
rename to assert/code/van-1.1.1.nomodule.debug.js
diff --git a/code/van-1.1.1.nomodule.js b/assert/code/van-1.1.1.nomodule.js
similarity index 100%
rename from code/van-1.1.1.nomodule.js
rename to assert/code/van-1.1.1.nomodule.js
diff --git a/code/van-1.1.1.nomodule.min.js b/assert/code/van-1.1.1.nomodule.min.js
similarity index 100%
rename from code/van-1.1.1.nomodule.min.js
rename to assert/code/van-1.1.1.nomodule.min.js
diff --git a/code/van-1.1.2.d.ts b/assert/code/van-1.1.2.d.ts
similarity index 100%
rename from code/van-1.1.2.d.ts
rename to assert/code/van-1.1.2.d.ts
diff --git a/code/van-1.1.2.debug.d.ts b/assert/code/van-1.1.2.debug.d.ts
similarity index 100%
rename from code/van-1.1.2.debug.d.ts
rename to assert/code/van-1.1.2.debug.d.ts
diff --git a/code/van-1.1.2.debug.js b/assert/code/van-1.1.2.debug.js
similarity index 100%
rename from code/van-1.1.2.debug.js
rename to assert/code/van-1.1.2.debug.js
diff --git a/code/van-1.1.2.js b/assert/code/van-1.1.2.js
similarity index 100%
rename from code/van-1.1.2.js
rename to assert/code/van-1.1.2.js
diff --git a/code/van-1.1.2.min.d.ts b/assert/code/van-1.1.2.min.d.ts
similarity index 100%
rename from code/van-1.1.2.min.d.ts
rename to assert/code/van-1.1.2.min.d.ts
diff --git a/code/van-1.1.2.min.js b/assert/code/van-1.1.2.min.js
similarity index 100%
rename from code/van-1.1.2.min.js
rename to assert/code/van-1.1.2.min.js
diff --git a/code/van-1.1.2.nomodule.debug.js b/assert/code/van-1.1.2.nomodule.debug.js
similarity index 100%
rename from code/van-1.1.2.nomodule.debug.js
rename to assert/code/van-1.1.2.nomodule.debug.js
diff --git a/code/van-1.1.2.nomodule.js b/assert/code/van-1.1.2.nomodule.js
similarity index 100%
rename from code/van-1.1.2.nomodule.js
rename to assert/code/van-1.1.2.nomodule.js
diff --git a/code/van-1.1.2.nomodule.min.js b/assert/code/van-1.1.2.nomodule.min.js
similarity index 100%
rename from code/van-1.1.2.nomodule.min.js
rename to assert/code/van-1.1.2.nomodule.min.js
diff --git a/code/van-1.1.3.d.ts b/assert/code/van-1.1.3.d.ts
similarity index 100%
rename from code/van-1.1.3.d.ts
rename to assert/code/van-1.1.3.d.ts
diff --git a/code/van-1.1.3.debug.d.ts b/assert/code/van-1.1.3.debug.d.ts
similarity index 100%
rename from code/van-1.1.3.debug.d.ts
rename to assert/code/van-1.1.3.debug.d.ts
diff --git a/code/van-1.1.3.debug.js b/assert/code/van-1.1.3.debug.js
similarity index 100%
rename from code/van-1.1.3.debug.js
rename to assert/code/van-1.1.3.debug.js
diff --git a/code/van-1.1.3.js b/assert/code/van-1.1.3.js
similarity index 100%
rename from code/van-1.1.3.js
rename to assert/code/van-1.1.3.js
diff --git a/code/van-1.1.3.min.d.ts b/assert/code/van-1.1.3.min.d.ts
similarity index 100%
rename from code/van-1.1.3.min.d.ts
rename to assert/code/van-1.1.3.min.d.ts
diff --git a/code/van-1.1.3.min.js b/assert/code/van-1.1.3.min.js
similarity index 100%
rename from code/van-1.1.3.min.js
rename to assert/code/van-1.1.3.min.js
diff --git a/code/van-1.1.3.nomodule.debug.js b/assert/code/van-1.1.3.nomodule.debug.js
similarity index 100%
rename from code/van-1.1.3.nomodule.debug.js
rename to assert/code/van-1.1.3.nomodule.debug.js
diff --git a/code/van-1.1.3.nomodule.js b/assert/code/van-1.1.3.nomodule.js
similarity index 100%
rename from code/van-1.1.3.nomodule.js
rename to assert/code/van-1.1.3.nomodule.js
diff --git a/code/van-1.1.3.nomodule.min.js b/assert/code/van-1.1.3.nomodule.min.js
similarity index 100%
rename from code/van-1.1.3.nomodule.min.js
rename to assert/code/van-1.1.3.nomodule.min.js
diff --git a/code/van-1.2.0.d.ts b/assert/code/van-1.2.0.d.ts
similarity index 100%
rename from code/van-1.2.0.d.ts
rename to assert/code/van-1.2.0.d.ts
diff --git a/code/van-1.2.0.debug.d.ts b/assert/code/van-1.2.0.debug.d.ts
similarity index 100%
rename from code/van-1.2.0.debug.d.ts
rename to assert/code/van-1.2.0.debug.d.ts
diff --git a/code/van-1.2.0.debug.js b/assert/code/van-1.2.0.debug.js
similarity index 100%
rename from code/van-1.2.0.debug.js
rename to assert/code/van-1.2.0.debug.js
diff --git a/code/van-1.2.0.js b/assert/code/van-1.2.0.js
similarity index 100%
rename from code/van-1.2.0.js
rename to assert/code/van-1.2.0.js
diff --git a/code/van-1.2.0.min.d.ts b/assert/code/van-1.2.0.min.d.ts
similarity index 100%
rename from code/van-1.2.0.min.d.ts
rename to assert/code/van-1.2.0.min.d.ts
diff --git a/code/van-1.2.0.min.js b/assert/code/van-1.2.0.min.js
similarity index 100%
rename from code/van-1.2.0.min.js
rename to assert/code/van-1.2.0.min.js
diff --git a/code/van-1.2.0.nomodule.debug.js b/assert/code/van-1.2.0.nomodule.debug.js
similarity index 100%
rename from code/van-1.2.0.nomodule.debug.js
rename to assert/code/van-1.2.0.nomodule.debug.js
diff --git a/code/van-1.2.0.nomodule.js b/assert/code/van-1.2.0.nomodule.js
similarity index 100%
rename from code/van-1.2.0.nomodule.js
rename to assert/code/van-1.2.0.nomodule.js
diff --git a/code/van-1.2.0.nomodule.min.js b/assert/code/van-1.2.0.nomodule.min.js
similarity index 100%
rename from code/van-1.2.0.nomodule.min.js
rename to assert/code/van-1.2.0.nomodule.min.js
diff --git a/code/van-1.2.1.d.ts b/assert/code/van-1.2.1.d.ts
similarity index 100%
rename from code/van-1.2.1.d.ts
rename to assert/code/van-1.2.1.d.ts
diff --git a/code/van-1.2.1.debug.d.ts b/assert/code/van-1.2.1.debug.d.ts
similarity index 100%
rename from code/van-1.2.1.debug.d.ts
rename to assert/code/van-1.2.1.debug.d.ts
diff --git a/code/van-1.2.1.debug.js b/assert/code/van-1.2.1.debug.js
similarity index 100%
rename from code/van-1.2.1.debug.js
rename to assert/code/van-1.2.1.debug.js
diff --git a/code/van-1.2.1.js b/assert/code/van-1.2.1.js
similarity index 100%
rename from code/van-1.2.1.js
rename to assert/code/van-1.2.1.js
diff --git a/code/van-1.2.1.min.d.ts b/assert/code/van-1.2.1.min.d.ts
similarity index 100%
rename from code/van-1.2.1.min.d.ts
rename to assert/code/van-1.2.1.min.d.ts
diff --git a/code/van-1.2.1.min.js b/assert/code/van-1.2.1.min.js
similarity index 100%
rename from code/van-1.2.1.min.js
rename to assert/code/van-1.2.1.min.js
diff --git a/code/van-1.2.1.nomodule.debug.js b/assert/code/van-1.2.1.nomodule.debug.js
similarity index 100%
rename from code/van-1.2.1.nomodule.debug.js
rename to assert/code/van-1.2.1.nomodule.debug.js
diff --git a/code/van-1.2.1.nomodule.js b/assert/code/van-1.2.1.nomodule.js
similarity index 100%
rename from code/van-1.2.1.nomodule.js
rename to assert/code/van-1.2.1.nomodule.js
diff --git a/code/van-1.2.1.nomodule.min.js b/assert/code/van-1.2.1.nomodule.min.js
similarity index 100%
rename from code/van-1.2.1.nomodule.min.js
rename to assert/code/van-1.2.1.nomodule.min.js
diff --git a/code/van-1.2.3.d.ts b/assert/code/van-1.2.3.d.ts
similarity index 100%
rename from code/van-1.2.3.d.ts
rename to assert/code/van-1.2.3.d.ts
diff --git a/code/van-1.2.3.debug.d.ts b/assert/code/van-1.2.3.debug.d.ts
similarity index 100%
rename from code/van-1.2.3.debug.d.ts
rename to assert/code/van-1.2.3.debug.d.ts
diff --git a/code/van-1.2.3.debug.js b/assert/code/van-1.2.3.debug.js
similarity index 100%
rename from code/van-1.2.3.debug.js
rename to assert/code/van-1.2.3.debug.js
diff --git a/code/van-1.2.3.js b/assert/code/van-1.2.3.js
similarity index 100%
rename from code/van-1.2.3.js
rename to assert/code/van-1.2.3.js
diff --git a/code/van-1.2.3.min.d.ts b/assert/code/van-1.2.3.min.d.ts
similarity index 100%
rename from code/van-1.2.3.min.d.ts
rename to assert/code/van-1.2.3.min.d.ts
diff --git a/code/van-1.2.3.min.js b/assert/code/van-1.2.3.min.js
similarity index 100%
rename from code/van-1.2.3.min.js
rename to assert/code/van-1.2.3.min.js
diff --git a/code/van-1.2.3.nomodule.debug.js b/assert/code/van-1.2.3.nomodule.debug.js
similarity index 100%
rename from code/van-1.2.3.nomodule.debug.js
rename to assert/code/van-1.2.3.nomodule.debug.js
diff --git a/code/van-1.2.3.nomodule.js b/assert/code/van-1.2.3.nomodule.js
similarity index 100%
rename from code/van-1.2.3.nomodule.js
rename to assert/code/van-1.2.3.nomodule.js
diff --git a/code/van-1.2.3.nomodule.min.js b/assert/code/van-1.2.3.nomodule.min.js
similarity index 100%
rename from code/van-1.2.3.nomodule.min.js
rename to assert/code/van-1.2.3.nomodule.min.js
diff --git a/code/van-1.2.4.d.ts b/assert/code/van-1.2.4.d.ts
similarity index 100%
rename from code/van-1.2.4.d.ts
rename to assert/code/van-1.2.4.d.ts
diff --git a/code/van-1.2.4.debug.d.ts b/assert/code/van-1.2.4.debug.d.ts
similarity index 100%
rename from code/van-1.2.4.debug.d.ts
rename to assert/code/van-1.2.4.debug.d.ts
diff --git a/code/van-1.2.4.debug.js b/assert/code/van-1.2.4.debug.js
similarity index 100%
rename from code/van-1.2.4.debug.js
rename to assert/code/van-1.2.4.debug.js
diff --git a/code/van-1.2.4.js b/assert/code/van-1.2.4.js
similarity index 100%
rename from code/van-1.2.4.js
rename to assert/code/van-1.2.4.js
diff --git a/code/van-1.2.4.min.d.ts b/assert/code/van-1.2.4.min.d.ts
similarity index 100%
rename from code/van-1.2.4.min.d.ts
rename to assert/code/van-1.2.4.min.d.ts
diff --git a/code/van-1.2.4.min.js b/assert/code/van-1.2.4.min.js
similarity index 100%
rename from code/van-1.2.4.min.js
rename to assert/code/van-1.2.4.min.js
diff --git a/code/van-1.2.4.nomodule.debug.js b/assert/code/van-1.2.4.nomodule.debug.js
similarity index 100%
rename from code/van-1.2.4.nomodule.debug.js
rename to assert/code/van-1.2.4.nomodule.debug.js
diff --git a/code/van-1.2.4.nomodule.js b/assert/code/van-1.2.4.nomodule.js
similarity index 100%
rename from code/van-1.2.4.nomodule.js
rename to assert/code/van-1.2.4.nomodule.js
diff --git a/code/van-1.2.4.nomodule.min.js b/assert/code/van-1.2.4.nomodule.min.js
similarity index 100%
rename from code/van-1.2.4.nomodule.min.js
rename to assert/code/van-1.2.4.nomodule.min.js
diff --git a/code/van-1.2.5.d.ts b/assert/code/van-1.2.5.d.ts
similarity index 100%
rename from code/van-1.2.5.d.ts
rename to assert/code/van-1.2.5.d.ts
diff --git a/code/van-1.2.5.debug.d.ts b/assert/code/van-1.2.5.debug.d.ts
similarity index 100%
rename from code/van-1.2.5.debug.d.ts
rename to assert/code/van-1.2.5.debug.d.ts
diff --git a/code/van-1.2.5.debug.js b/assert/code/van-1.2.5.debug.js
similarity index 100%
rename from code/van-1.2.5.debug.js
rename to assert/code/van-1.2.5.debug.js
diff --git a/code/van-1.2.5.js b/assert/code/van-1.2.5.js
similarity index 100%
rename from code/van-1.2.5.js
rename to assert/code/van-1.2.5.js
diff --git a/code/van-1.2.5.min.d.ts b/assert/code/van-1.2.5.min.d.ts
similarity index 100%
rename from code/van-1.2.5.min.d.ts
rename to assert/code/van-1.2.5.min.d.ts
diff --git a/code/van-1.2.5.min.js b/assert/code/van-1.2.5.min.js
similarity index 100%
rename from code/van-1.2.5.min.js
rename to assert/code/van-1.2.5.min.js
diff --git a/code/van-1.2.5.nomodule.debug.js b/assert/code/van-1.2.5.nomodule.debug.js
similarity index 100%
rename from code/van-1.2.5.nomodule.debug.js
rename to assert/code/van-1.2.5.nomodule.debug.js
diff --git a/code/van-1.2.5.nomodule.js b/assert/code/van-1.2.5.nomodule.js
similarity index 100%
rename from code/van-1.2.5.nomodule.js
rename to assert/code/van-1.2.5.nomodule.js
diff --git a/code/van-1.2.5.nomodule.min.js b/assert/code/van-1.2.5.nomodule.min.js
similarity index 100%
rename from code/van-1.2.5.nomodule.min.js
rename to assert/code/van-1.2.5.nomodule.min.js
diff --git a/code/van-1.2.6.d.ts b/assert/code/van-1.2.6.d.ts
similarity index 100%
rename from code/van-1.2.6.d.ts
rename to assert/code/van-1.2.6.d.ts
diff --git a/code/van-1.2.6.debug.d.ts b/assert/code/van-1.2.6.debug.d.ts
similarity index 100%
rename from code/van-1.2.6.debug.d.ts
rename to assert/code/van-1.2.6.debug.d.ts
diff --git a/code/van-1.2.6.debug.js b/assert/code/van-1.2.6.debug.js
similarity index 100%
rename from code/van-1.2.6.debug.js
rename to assert/code/van-1.2.6.debug.js
diff --git a/code/van-1.2.6.js b/assert/code/van-1.2.6.js
similarity index 100%
rename from code/van-1.2.6.js
rename to assert/code/van-1.2.6.js
diff --git a/code/van-1.2.6.min.d.ts b/assert/code/van-1.2.6.min.d.ts
similarity index 100%
rename from code/van-1.2.6.min.d.ts
rename to assert/code/van-1.2.6.min.d.ts
diff --git a/code/van-1.2.6.min.js b/assert/code/van-1.2.6.min.js
similarity index 100%
rename from code/van-1.2.6.min.js
rename to assert/code/van-1.2.6.min.js
diff --git a/code/van-1.2.6.nomodule.debug.js b/assert/code/van-1.2.6.nomodule.debug.js
similarity index 100%
rename from code/van-1.2.6.nomodule.debug.js
rename to assert/code/van-1.2.6.nomodule.debug.js
diff --git a/code/van-1.2.6.nomodule.js b/assert/code/van-1.2.6.nomodule.js
similarity index 100%
rename from code/van-1.2.6.nomodule.js
rename to assert/code/van-1.2.6.nomodule.js
diff --git a/code/van-1.2.6.nomodule.min.js b/assert/code/van-1.2.6.nomodule.min.js
similarity index 100%
rename from code/van-1.2.6.nomodule.min.js
rename to assert/code/van-1.2.6.nomodule.min.js
diff --git a/code/van-1.2.7.d.ts b/assert/code/van-1.2.7.d.ts
similarity index 100%
rename from code/van-1.2.7.d.ts
rename to assert/code/van-1.2.7.d.ts
diff --git a/code/van-1.2.7.debug.d.ts b/assert/code/van-1.2.7.debug.d.ts
similarity index 100%
rename from code/van-1.2.7.debug.d.ts
rename to assert/code/van-1.2.7.debug.d.ts
diff --git a/code/van-1.2.7.debug.js b/assert/code/van-1.2.7.debug.js
similarity index 100%
rename from code/van-1.2.7.debug.js
rename to assert/code/van-1.2.7.debug.js
diff --git a/code/van-1.2.7.js b/assert/code/van-1.2.7.js
similarity index 100%
rename from code/van-1.2.7.js
rename to assert/code/van-1.2.7.js
diff --git a/code/van-1.2.7.min.d.ts b/assert/code/van-1.2.7.min.d.ts
similarity index 100%
rename from code/van-1.2.7.min.d.ts
rename to assert/code/van-1.2.7.min.d.ts
diff --git a/code/van-1.2.7.min.js b/assert/code/van-1.2.7.min.js
similarity index 100%
rename from code/van-1.2.7.min.js
rename to assert/code/van-1.2.7.min.js
diff --git a/code/van-1.2.7.nomodule.debug.js b/assert/code/van-1.2.7.nomodule.debug.js
similarity index 100%
rename from code/van-1.2.7.nomodule.debug.js
rename to assert/code/van-1.2.7.nomodule.debug.js
diff --git a/code/van-1.2.7.nomodule.js b/assert/code/van-1.2.7.nomodule.js
similarity index 100%
rename from code/van-1.2.7.nomodule.js
rename to assert/code/van-1.2.7.nomodule.js
diff --git a/code/van-1.2.7.nomodule.min.js b/assert/code/van-1.2.7.nomodule.min.js
similarity index 100%
rename from code/van-1.2.7.nomodule.min.js
rename to assert/code/van-1.2.7.nomodule.min.js
diff --git a/code/van-latest.d.ts b/assert/code/van-latest.d.ts
similarity index 100%
rename from code/van-latest.d.ts
rename to assert/code/van-latest.d.ts
diff --git a/code/van-latest.debug.d.ts b/assert/code/van-latest.debug.d.ts
similarity index 100%
rename from code/van-latest.debug.d.ts
rename to assert/code/van-latest.debug.d.ts
diff --git a/code/van-latest.debug.js b/assert/code/van-latest.debug.js
similarity index 100%
rename from code/van-latest.debug.js
rename to assert/code/van-latest.debug.js
diff --git a/code/van-latest.js b/assert/code/van-latest.js
similarity index 100%
rename from code/van-latest.js
rename to assert/code/van-latest.js
diff --git a/code/van-latest.min.d.ts b/assert/code/van-latest.min.d.ts
similarity index 100%
rename from code/van-latest.min.d.ts
rename to assert/code/van-latest.min.d.ts
diff --git a/code/van-latest.min.js b/assert/code/van-latest.min.js
similarity index 100%
rename from code/van-latest.min.js
rename to assert/code/van-latest.min.js
diff --git a/code/van-latest.min.pre-ro-prop.js b/assert/code/van-latest.min.pre-ro-prop.js
similarity index 100%
rename from code/van-latest.min.pre-ro-prop.js
rename to assert/code/van-latest.min.pre-ro-prop.js
diff --git a/code/van-latest.nomodule.debug.js b/assert/code/van-latest.nomodule.debug.js
similarity index 100%
rename from code/van-latest.nomodule.debug.js
rename to assert/code/van-latest.nomodule.debug.js
diff --git a/code/van-latest.nomodule.js b/assert/code/van-latest.nomodule.js
similarity index 100%
rename from code/van-latest.nomodule.js
rename to assert/code/van-latest.nomodule.js
diff --git a/code/van-latest.nomodule.min.js b/assert/code/van-latest.nomodule.min.js
similarity index 100%
rename from code/van-latest.nomodule.min.js
rename to assert/code/van-latest.nomodule.min.js
diff --git a/code/van-ui.d.ts b/assert/code/van-ui.d.ts
similarity index 100%
rename from code/van-ui.d.ts
rename to assert/code/van-ui.d.ts
diff --git a/code/van-x-0.1.2.d.ts b/assert/code/van-x-0.1.2.d.ts
similarity index 100%
rename from code/van-x-0.1.2.d.ts
rename to assert/code/van-x-0.1.2.d.ts
diff --git a/code/van-x-0.1.3.d.ts b/assert/code/van-x-0.1.3.d.ts
similarity index 100%
rename from code/van-x-0.1.3.d.ts
rename to assert/code/van-x-0.1.3.d.ts
diff --git a/code/van-x-0.2.0.d.ts b/assert/code/van-x-0.2.0.d.ts
similarity index 100%
rename from code/van-x-0.2.0.d.ts
rename to assert/code/van-x-0.2.0.d.ts
diff --git a/code/van-x.nomodule.js b/assert/code/van-x.nomodule.js
similarity index 100%
rename from code/van-x.nomodule.js
rename to assert/code/van-x.nomodule.js
diff --git a/code/van-x.nomodule.min.js b/assert/code/van-x.nomodule.min.js
similarity index 100%
rename from code/van-x.nomodule.min.js
rename to assert/code/van-x.nomodule.min.js
diff --git a/code/van-x.version b/assert/code/van-x.version
similarity index 100%
rename from code/van-x.version
rename to assert/code/van-x.version
diff --git a/code/van.version b/assert/code/van.version
similarity index 100%
rename from code/van.version
rename to assert/code/van.version
diff --git a/convert.js b/assert/convert.js
similarity index 100%
rename from convert.js
rename to assert/convert.js
diff --git a/demo.js b/assert/demo.js
similarity index 100%
rename from demo.js
rename to assert/demo.js
diff --git a/home.js b/assert/home.js
similarity index 100%
rename from home.js
rename to assert/home.js
diff --git a/logo.svg b/assert/logo.svg
similarity index 100%
rename from logo.svg
rename to assert/logo.svg
diff --git a/prism.css b/assert/prism.css
similarity index 100%
rename from prism.css
rename to assert/prism.css
diff --git a/prism.js b/assert/prism.js
similarity index 100%
rename from prism.js
rename to assert/prism.js
diff --git a/start.js b/assert/start.js
similarity index 100%
rename from start.js
rename to assert/start.js
diff --git a/tao.jpeg b/assert/tao.jpeg
similarity index 100%
rename from tao.jpeg
rename to assert/tao.jpeg
diff --git a/tutorial.js b/assert/tutorial.js
similarity index 100%
rename from tutorial.js
rename to assert/tutorial.js
diff --git a/vanjs.css b/assert/vanjs.css
similarity index 100%
rename from vanjs.css
rename to assert/vanjs.css
diff --git a/vs-code-16x16.png b/assert/vs-code-16x16.png
similarity index 100%
rename from vs-code-16x16.png
rename to assert/vs-code-16x16.png
diff --git a/w3.css b/assert/w3.css
similarity index 100%
rename from w3.css
rename to assert/w3.css
diff --git a/x.js b/assert/x.js
similarity index 100%
rename from x.js
rename to assert/x.js
diff --git a/autodownload/index.html b/autodownload/index.html
deleted file mode 100644
index a065f06d..00000000
--- a/autodownload/index.html
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
- Auto Download
-
-
-
-
-
-
diff --git a/compare-dom.js b/compare-dom.js
new file mode 100644
index 00000000..9ef4c1b7
--- /dev/null
+++ b/compare-dom.js
@@ -0,0 +1,55 @@
+import { JSDOM } from 'jsdom'
+import fs from 'fs/promises'
+
+async function getPage(link) {
+ const dom = await JSDOM.fromURL(link)
+ const html = dom.serialize();
+ return html
+}
+
+const pages = [
+ '/',
+ '/start',
+ '/tutorial',
+ '/demo',
+ '/convert',
+ '/vanui',
+ '/minivan',
+ '/ssr',
+ '/x',
+ '/advanced',
+ '/media',
+ '/about',
+]
+
+const link1 = process.argv[2]
+const link2 = process.argv[3]
+
+if (!link1 || !link2) {
+ console.log("Usage: node compare-dom.js ")
+ process.exit(1)
+}
+
+async function compare(link1, link2, page) {
+ const page1 = await getPage(link1 + page)
+ const page2 = await getPage(link2 + page)
+ if (page1 !== page2) {
+ console.log(`Page ${page} is different!`)
+ const name = page.slice(1) || 'home';
+ await fs.writeFile(`diff/${name}-page1.html`, page1)
+ await fs.writeFile(`diff/${name}-page2.html`, page2)
+ }
+}
+
+async function main() {
+ try {
+ for (const page of pages) {
+ await compare(link1, link2, page)
+ }
+ } catch (e) {
+ console.error(e)
+ process.exit(1)
+ }
+}
+
+main()
\ No newline at end of file
diff --git a/convert.code.js b/convert.code.js
deleted file mode 100644
index fbbdaaa2..00000000
--- a/convert.code.js
+++ /dev/null
@@ -1,72 +0,0 @@
-const quoteIfNeeded = key => /^[a-zA-Z_][a-zA-Z_0-9]+$/.test(key) ? key : `"${key}"`
-
-const attrsToVanCode = (attrs, childNodes) => attrs.length > 0 ?
- `{${[...attrs].map(
- a => `${quoteIfNeeded(a.nodeName)}: ${JSON.stringify(a.nodeValue)}`)
- .join(", ")}}${childNodes.length > 0 ? "," : ""}` : ""
-
-const filterChild = (childNodes, {skipEmptyText}) =>
- [...childNodes].filter(c => (c.nodeType === 1 || c.nodeType === 3) &&
- (!skipEmptyText || c.nodeName !== "#text" || /\S/.test(c.nodeValue)))
-
-const autoGrow = e => {
- e.style.height = "5px"
- e.style.height = (e.scrollHeight + 5) + "px"
-}
-
-const domToVanCode =
- (dom, {indent = 0, indentLevel, skipEmptyText, skipTrailingComma}, tagsUsed) => {
- const prefix = " ".repeat(indent), suffix = skipTrailingComma ? "" : ","
- if (dom.nodeName === "#text") return [`${prefix}${JSON.stringify(dom.nodeValue)}${suffix}`]
- const lowerCaseTagName = dom.nodeName.toLowerCase()
- tagsUsed.add(lowerCaseTagName)
- if (lowerCaseTagName === "pre") skipEmptyText = false
- const childNodes = filterChild(dom.childNodes, {skipEmptyText})
- return childNodes.length > 0 ? [
- `${prefix}${lowerCaseTagName}(${attrsToVanCode(dom.attributes, childNodes)}`,
- ...childNodes.flatMap(c => domToVanCode(
- c, {indent: indent + indentLevel, indentLevel, skipEmptyText}, tagsUsed)),
- `${prefix})${suffix}`,
- ] : [
- `${prefix}${lowerCaseTagName}(${attrsToVanCode(dom.attributes, childNodes)})${suffix}`,
- ]
-}
-
-const Converter = ({initInput}) => {
- const oninput = () => {
- autoGrow(textareaDom)
- const containerDom = div()
- containerDom.innerHTML = textareaDom.value
- const tagsUsed = new Set;
- const childNodes = filterChild(containerDom.childNodes,
- {skipEmptyText: skipEmptyTextDom.checked})
- const lines = childNodes.flatMap(c =>
- domToVanCode(c, {
- indentLevel: parseInt(indentInputDom.value),
- skipEmptyText: skipEmptyTextDom.checked,
- skipTrailingComma: childNodes.length <= 1
- }, tagsUsed))
- const sortedTags = [...tagsUsed].sort()
- tagsCode.val = `const {${sortedTags.join(", ")}} = van.tags`
- domCode.val = lines.join("\n")
- setTimeout(() => Prism.highlightAll(), 5)
- }
-
- const textareaDom = textarea({oninput, style: "width: 100%;"}, initInput)
- const indentInputDom = input({type: "number", min: 1, max: 8, value: 2, oninput})
- const skipEmptyTextDom = input({type: "checkbox", oninput})
- const tagsCode = van.state(""), domCode = van.state("")
-
- // Trigger the UI update after initialization
- setTimeout(() => textareaDom.dispatchEvent(new Event("input")))
- return div(
- h5("Paste your HTML snippet here:"),
- textareaDom,
- "Indent level: ", indentInputDom, " ",
- skipEmptyTextDom, "Skip empty text",
- h5("Declaring tag functions:"),
- () => div(pre(code({class: "language-js"}, tagsCode.val))),
- h5("Building the DOM tree:"),
- () => div(pre(code({class: "language-js"}, domCode.val))),
- )
-}
diff --git a/convert.html b/convert.html
deleted file mode 100644
index 80b89998..00000000
--- a/convert.html
+++ /dev/null
@@ -1,111 +0,0 @@
-
-
-
- VanJS - HTML/MD Snippet to 🍦VanJS Code
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ☰
- HTML/MD to VanJS
-
-
-
-
-
-
-
-
-
HTML/MD Snippet to 🍦VanJS Code
The library version of the converter with the support of custom VanJS components is here.
This is only supported in the converter library, not in the UI. The root cause is html-dom-parser doesn't support case-sensitive parsing on the client side.
The input HTML string can be a mix of HTML elements and custom UI components built with VanJS. To use custom UI components, just specify the component similar to regular HTML tags. For instance, assume we have custom UI components similar to the ones shown in https://vanjs.org/ home page:
indent: Type number. Default 2. Optional. The indent level of the generated VanJS code.
spacing: Type boolean. Default false. Optional. The style of the property object in the generated VanJS code. If true, the property object will look like {href: "https://vanjs.org/"}; Otherwise, the property object will look like { href: "https://vanjs.org/" }.
skipEmptyText: Type boolean. Default false. Optional. Whether to skip empty text nodes in the generated VanJS code. For instance, the HTML snippet:
htmlTagPred: Type (name: string) => boolean. Default s => s.toLowerCase() === s. Optional. A predicate function to check whether a specific tag snippet such as <Counter> should be treated as a native HTML element or a custom UI component built with VanJS. By default, it will be treated as a native HTML element if the letters in the name are all lowercase.
This is only supported in the converter library, not in the UI.
There are 2 special cases while specifying custom VanJS components in the input HTML string. The first special case is that, sometimes, a custom component needs properties being specified in its first argument, even for empty properties {} (e.g.: the Counter component defined in the section above). In this case, you can specify the special DUMMY property as a placeholder. For instance:
<CustomElement DUMMY>content</CustomElement>
-
will be converted to:
CustomElement({},
- "content",
-)
-
whereas
<CustomElement>content</CustomElement>
-
will be converted to:
CustomElement(
- "content",
-)
-
The second special case is that, sometimes, a custom VanJS component needs consecutive string arguments. You can achieve that by inserting <DUMMY> element between text pieces. For instance:
indent: Type number. Default 2. Optional. The indent level of the generated VanJS code.
spacing: Type boolean. Default false. Optional. The style of the property object in the generated VanJS code. If true, the property object will look like {href: "https://vanjs.org/"}; Otherwise, the property object will look like { href: "https://vanjs.org/" }.
htmlTagPred: Type (name: string) => boolean. Default s => s.toLowerCase() === s. Optional. A predicate function to check whether a specific tag snippet such as <Counter> represents a native HTML element or a custom UI component built with VanJS. By default, it will be considered a native HTML element if the letters in the name are all lowercase.
renderer: Optional. Custom renderer is only supported in the converter library, not in the UI. A custom object used to override how tokens in the MD string are being rendered. The specification of the renderer object can be found in Marked doc. For instance, the renderer object:
will convert `text` in MD string into Symbol("text") (here Symbol is a custom VanJS component) instead of code("text"), and will convert [text](link) in MD string into Link("text", "link") instead of a({href: "link"}, "text").
The https://vanjs.org/ website is using this library to keep README.md files in sync with their corresponding web pages (source code of the code generation):
The VanUI page is kept in sync with the README.md file in GitHub with the help of this library.
This is only supported in the converter library, not in the UI. The root cause is html-dom-parser doesn't support case-sensitive parsing on the client side.
The input HTML string can be a mix of HTML elements and custom UI components built with VanJS. To use custom UI components, just specify the component similar to regular HTML tags. For instance, assume we have custom UI components similar to the ones shown in https://vanjs.org/ home page:
indent: Type number. Default 2. Optional. The indent level of the generated VanJS code.
spacing: Type boolean. Default false. Optional. The style of the property object in the generated VanJS code. If true, the property object will look like {href: "https://vanjs.org/"}; Otherwise, the property object will look like { href: "https://vanjs.org/" }.
skipEmptyText: Type boolean. Default false. Optional. Whether to skip empty text nodes in the generated VanJS code. For instance, the HTML snippet:
htmlTagPred: Type (name: string) => boolean. Default s => s.toLowerCase() === s. Optional. A predicate function to check whether a specific tag snippet such as <Counter> should be treated as a native HTML element or a custom UI component built with VanJS. By default, it will be treated as a native HTML element if the letters in the name are all lowercase.
This is only supported in the converter library, not in the UI.
There are 2 special cases while specifying custom VanJS components in the input HTML string. The first special case is that, sometimes, a custom component needs properties being specified in its first argument, even for empty properties {} (e.g.: the Counter component defined in the section above). In this case, you can specify the special DUMMY property as a placeholder. For instance:
<CustomElement DUMMY>content</CustomElement>
-
will be converted to:
CustomElement({},
- "content",
-)
-
whereas
<CustomElement>content</CustomElement>
-
will be converted to:
CustomElement(
- "content",
-)
-
The second special case is that, sometimes, a custom VanJS component needs consecutive string arguments. You can achieve that by inserting <DUMMY> element between text pieces. For instance:
indent: Type number. Default 2. Optional. The indent level of the generated VanJS code.
spacing: Type boolean. Default false. Optional. The style of the property object in the generated VanJS code. If true, the property object will look like {href: "https://vanjs.org/"}; Otherwise, the property object will look like { href: "https://vanjs.org/" }.
htmlTagPred: Type (name: string) => boolean. Default s => s.toLowerCase() === s. Optional. A predicate function to check whether a specific tag snippet such as <Counter> represents a native HTML element or a custom UI component built with VanJS. By default, it will be considered a native HTML element if the letters in the name are all lowercase.
renderer: Optional. Custom renderer is only supported in the converter library, not in the UI. A custom object used to override how tokens in the MD string are being rendered. The specification of the renderer object can be found in Marked doc. For instance, the renderer object:
will convert `text` in MD string into Symbol("text") (here Symbol is a custom VanJS component) instead of code("text"), and will convert [text](link) in MD string into Link("text", "link") instead of a({href: "link"}, "text").
The https://vanjs.org/ website is using this library to keep README.md files in sync with their corresponding web pages (source code of the code generation):
The VanUI page is kept in sync with the README.md file in GitHub with the help of this library.
-
-
-
-
-
-
\ No newline at end of file
diff --git a/demo.html b/demo.html
deleted file mode 100644
index a00879ce..00000000
--- a/demo.html
+++ /dev/null
@@ -1,930 +0,0 @@
-
-
-
- VanJS - Learning by Example
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ☰
- VanJS by Example
-
-
-
-
-
-
-
-
-
VanJS: Learning by Example
Simplicity is the ultimate sophistication.
-- Steve Jobs
Despite being an ultra-lightweight UI framework, VanJS allows you to write incredibly elegant and expressive code for comprehensive application logic. This page is a curated list of cool things you can do with just a few lines of JavaScript code, including several handy utilities built with VanJS.
Even without state and state binding, you can build interactive web pages thanks to VanJS's flexible API for DOM composition and manipulation: tag functions and van.add. Check out the example below:
const StaticDom = () => {
- const dom = div(
- div(
- button("Dummy Button"),
- button(
- {onclick: () =>
- van.add(dom,
- div(button("New Button")),
- div(a({href: "https://www.example.com/"}, "This is a link")),
- )
- },
- "Button to Add More Elements"),
- button({onclick: () => alert("Hello from 🍦VanJS")}, "Hello"),
- ),
- )
- return dom
-}
-
VanJS doesn't have an equivalent to React's <Fragment>. For most of the cases, returning an array of HTML elements from your custom component would serve the similar purpose. Here is the sample code equivalent to the Blog example in React's official website:
const Blog = () => [
- Post({title: "An update", body: "It's been a while since I posted..."}),
- Post({title: "My new blog", body: "I am starting a new blog!"}),
-]
-
-const Post = ({title, body}) => [
- PostTitle({title}),
- PostBody({body}),
-]
-
-const PostTitle = ({title}) => h1(title)
-const PostBody = ({body}) => article(p(body))
-
The sample code in React is 29 lines. Thus VanJS's equivalent code is ~3 times shorter by eliminating unnecessary boilerplate.
Note that: The result of the binding function of a state-derived child node can't be an array of elements. You can wrap the result into a pass-through container (<span> for inline elements and <div> for block elements) if multiple elements need to be returned.
As an unopinionated framework, VanJS supports multiple programming paradigms. You can construct the DOM tree in an imperative way (modifying the DOM tree via van.add), or in a functional/declarative way.
Below is an example of building a list even numbers in 1..N, using an imperative way:
const EvenNumbers = ({N}) => {
- const listDom = ul()
- for (let i = 1; i <= N; ++i)
- if (i % 2 === 0)
- van.add(listDom, li(i))
-
- return div(
- p("List of even numbers in 1.." + N + ":"),
- listDom,
- )
-}
Similarly, to build reactive applications, you can build in a procedural way, which updates UI via the integration with native DOM API (it's easy to do with VanJS as it doesn't introduce an ad-hoc virtual-DOM layer), or in a functional/reactive way, which delegates UI changes to State Binding. You can also choose a hybrid approach between the 2 paradigms, depending on which approach fits well for a specific problem.
道可道,非常道 (A rule that can be told by words, is not the rule that should universally apply)
-- 老子,道德经
Below is an example of building a TODO List in a completely procedural way:
You can also go fully reactive for the TODO App. That is, the entire state of the app is captured by a global appState. With the full reactivity it's easier to persist the appState into localStorage so that the state is kept across page reloads.
Note that even if the app is fully reactive, we don't need to re-render the whole DOM tree for state updates, thanks to the optimization with stateful binding.
We're able to implement a mini game engine with VanJS in just a few lines. Here is a fun game implemented under 60 lines with the help of VanJS and VanX:
With VanJS, you can built a single-page application with client-side routing support, thanks to VanJS's powerful builtin state management and state derivation:
Here is a Diff App with the integration of jsdiff. The app can compare 2 pieces of text (very handy tool to check how your text is revised by ChatGPT 🙂):
Notably, this Calculator App is equivalent to the React-based implementation here: github.com/ahfarmer/calculator. Here is the size comparison of the total package between the 2 apps:
VanJS-based App
React-based App
# of files:
2
16
# of lines:
143
616
As you can see, not only VanJS is ~50 times smaller than React, apps built with VanJS also tends to be much slimmer.
The code below implements a textarea with autocomplete support. This implementation leverages Stateful DOM binding to optimize the performance of DOM tree rendering:
The code was implemented in TypeScript to validate VanJS's TypeScript support.
Next up, we're going to demonstrate a simplified Jupyter-like JavaScript console implemented in ~100 lines of code with VanJS. The JavaScript console supports drawing tables (with the technique similar to Table Viewer), inspecting objects in a tree view (with the technique similar to Json Inspector) and plotting (with the integration of Google Charts).
Next up is a web-based Unix terminal that connects to your local computer, with notable improvements, all under 300 lines of code. This is to demonstrate that, with VanJS, we can easily provide great extension to commandline utilities with fancy GUI by leveraging all available HTML elements. The program is heavily tested in macOS, and should in theory works in Linux, or in any environment that has /bin/sh.
Besides the official VanJS examples, there are also sample apps from the great VanJS community. Below is a curated list (contact tao@vanjs.org to add yours):
-
-
-
-
-
-
\ No newline at end of file
diff --git a/demo/index.html b/demo/index.html
deleted file mode 100644
index a00879ce..00000000
--- a/demo/index.html
+++ /dev/null
@@ -1,930 +0,0 @@
-
-
-
- VanJS - Learning by Example
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ☰
- VanJS by Example
-
-
-
-
-
-
-
-
-
VanJS: Learning by Example
Simplicity is the ultimate sophistication.
-- Steve Jobs
Despite being an ultra-lightweight UI framework, VanJS allows you to write incredibly elegant and expressive code for comprehensive application logic. This page is a curated list of cool things you can do with just a few lines of JavaScript code, including several handy utilities built with VanJS.
Even without state and state binding, you can build interactive web pages thanks to VanJS's flexible API for DOM composition and manipulation: tag functions and van.add. Check out the example below:
const StaticDom = () => {
- const dom = div(
- div(
- button("Dummy Button"),
- button(
- {onclick: () =>
- van.add(dom,
- div(button("New Button")),
- div(a({href: "https://www.example.com/"}, "This is a link")),
- )
- },
- "Button to Add More Elements"),
- button({onclick: () => alert("Hello from 🍦VanJS")}, "Hello"),
- ),
- )
- return dom
-}
-
VanJS doesn't have an equivalent to React's <Fragment>. For most of the cases, returning an array of HTML elements from your custom component would serve the similar purpose. Here is the sample code equivalent to the Blog example in React's official website:
const Blog = () => [
- Post({title: "An update", body: "It's been a while since I posted..."}),
- Post({title: "My new blog", body: "I am starting a new blog!"}),
-]
-
-const Post = ({title, body}) => [
- PostTitle({title}),
- PostBody({body}),
-]
-
-const PostTitle = ({title}) => h1(title)
-const PostBody = ({body}) => article(p(body))
-
The sample code in React is 29 lines. Thus VanJS's equivalent code is ~3 times shorter by eliminating unnecessary boilerplate.
Note that: The result of the binding function of a state-derived child node can't be an array of elements. You can wrap the result into a pass-through container (<span> for inline elements and <div> for block elements) if multiple elements need to be returned.
As an unopinionated framework, VanJS supports multiple programming paradigms. You can construct the DOM tree in an imperative way (modifying the DOM tree via van.add), or in a functional/declarative way.
Below is an example of building a list even numbers in 1..N, using an imperative way:
const EvenNumbers = ({N}) => {
- const listDom = ul()
- for (let i = 1; i <= N; ++i)
- if (i % 2 === 0)
- van.add(listDom, li(i))
-
- return div(
- p("List of even numbers in 1.." + N + ":"),
- listDom,
- )
-}
Similarly, to build reactive applications, you can build in a procedural way, which updates UI via the integration with native DOM API (it's easy to do with VanJS as it doesn't introduce an ad-hoc virtual-DOM layer), or in a functional/reactive way, which delegates UI changes to State Binding. You can also choose a hybrid approach between the 2 paradigms, depending on which approach fits well for a specific problem.
道可道,非常道 (A rule that can be told by words, is not the rule that should universally apply)
-- 老子,道德经
Below is an example of building a TODO List in a completely procedural way:
You can also go fully reactive for the TODO App. That is, the entire state of the app is captured by a global appState. With the full reactivity it's easier to persist the appState into localStorage so that the state is kept across page reloads.
Note that even if the app is fully reactive, we don't need to re-render the whole DOM tree for state updates, thanks to the optimization with stateful binding.
We're able to implement a mini game engine with VanJS in just a few lines. Here is a fun game implemented under 60 lines with the help of VanJS and VanX:
With VanJS, you can built a single-page application with client-side routing support, thanks to VanJS's powerful builtin state management and state derivation:
Here is a Diff App with the integration of jsdiff. The app can compare 2 pieces of text (very handy tool to check how your text is revised by ChatGPT 🙂):
Notably, this Calculator App is equivalent to the React-based implementation here: github.com/ahfarmer/calculator. Here is the size comparison of the total package between the 2 apps:
VanJS-based App
React-based App
# of files:
2
16
# of lines:
143
616
As you can see, not only VanJS is ~50 times smaller than React, apps built with VanJS also tends to be much slimmer.
The code below implements a textarea with autocomplete support. This implementation leverages Stateful DOM binding to optimize the performance of DOM tree rendering:
The code was implemented in TypeScript to validate VanJS's TypeScript support.
Next up, we're going to demonstrate a simplified Jupyter-like JavaScript console implemented in ~100 lines of code with VanJS. The JavaScript console supports drawing tables (with the technique similar to Table Viewer), inspecting objects in a tree view (with the technique similar to Json Inspector) and plotting (with the integration of Google Charts).
Next up is a web-based Unix terminal that connects to your local computer, with notable improvements, all under 300 lines of code. This is to demonstrate that, with VanJS, we can easily provide great extension to commandline utilities with fancy GUI by leveraging all available HTML elements. The program is heavily tested in macOS, and should in theory works in Linux, or in any environment that has /bin/sh.
Besides the official VanJS examples, there are also sample apps from the great VanJS community. Below is a curated list (contact tao@vanjs.org to add yours):
Enable everyone to build useful UI apps with a few lines of code, anywhere, any time, on any device.
VanJS (abbreviated Vanilla JavaScript) is an ultra-lightweight, zero-dependency, and unopinionated Reactive UI framework based on pure vanilla JavaScript and DOM. Programming with VanJS feels like building React apps in a scripting language, without JSX. Check-out the Hello World code below:
// Reusable components can be just pure vanilla JavaScript functions.
-// Here we capitalize the first letter to follow React conventions.
-const Hello = () => div(
- p("👋Hello"),
- ul(
- li("🗺️World"),
- li(a({href: "https://vanjs.org/"}, "🍦VanJS")),
- ),
-)
-
-van.add(document.body, Hello())
-// Alternatively, you can write:
-// document.body.appendChild(Hello())
-
Declarative DOM tree composition, reusable components, reactive state binding - VanJS offers every good aspect that React does, but without the need of React, JSX, transpiling, virtual DOM, or any hidden logic. Everything is built with simple JavaScript functions and DOM.
No installation, no configuration, no dependencies, no transpiling, no IDE setups. Adding a line to your script or HTML file is all you need to start coding. And any code with VanJS can be pasted and executed directly in your browser's developer console. VanJS allows you to focus on the business logic of your application, rather than getting bogged down in frameworks and tools.
VanJS is the smallest reactive UI framework in the world, with just 0.9kB in the gzipped minified bundle. It's 50~100 times smaller than most popular alternatives. Guess what you can get from this 0.9kB framework? All essential features of reactive UI programming - DOM templating, state, state binding, state derivation, effect, SPA, client-side routing and even hydration!
Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.
Simplicity at its core. 5 major functions (van.tags, van.add, van.state, van.derive, van.hydrate) + 4 auxiliary functions (van.tagsNS, van._, van.val, van.oldVal). The entire tutorial plus the API reference is just one single web page, and can be learned within 1 hour for most developers.
VanJS provides first-class support for TypeScript. With the .d.ts file in place, you'll be able to take advantage of type-checking, IntelliSense, large-scale refactoring provided by your preferred development environment. Refer to the Download Table to find the right .d.ts file to work with.
VanJS can be extended via add-ons. Add-ons add more features to VanJS and/or provide an alternative styled API. Below is a curated list of add-ons built by VanJS community:
van_dml.js: adds a a new flavour of composition to VanJS. Author: Eckehard.
van-jsx: a JSX wrapper for VanJS, for people who like the JSX syntax more. Author: cqh963852.
Van Cone: an SPA framework add-on for VanJS. Author: b-rad-c.
vanjs-router: A router solution for VanJS (README.md in simplified Chinese). Author: 欧阳鹏.
🙏 VanJS aims to build a better world by reducing the entry barrier for UI programming, with no intention or plan on commercialization whatsoever. If you find VanJS interesting, or could be useful for you some day, please consider starring the project on GitHub. It takes just a few seconds but your support means the world to us and helps spread VanJS to a wider audience.
In the name of Vanilla of the House JavaScript, the First of its name, Smallest Reactive UI Framework, 0.9kB JSX-free Grab 'n Go Library, Scripting Language for GUI, GPT-Empowered Toolkit, by the word of Tao of the House Xin, Founder and Maintainer of VanJS, I do hereby grant you the permission of VanJS under MIT License.
-
-
-
-
-
-
\ No newline at end of file
diff --git a/jsfiddle/about/counter/demo.details b/jsfiddle/about/counter/demo.details
new file mode 100644
index 00000000..cfffa9d9
--- /dev/null
+++ b/jsfiddle/about/counter/demo.details
@@ -0,0 +1,9 @@
+/*
+---
+authors:
+ - Tao Xin
+resources:
+ - https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.2.7.nomodule.min.js
+panel_js: 2
+...
+*/
diff --git a/jsfiddle/about/counter/demo.js b/jsfiddle/about/counter/demo.js
new file mode 100644
index 00000000..04c15415
--- /dev/null
+++ b/jsfiddle/about/counter/demo.js
@@ -0,0 +1,3 @@
+const {button, span} = van.tags
+
+undefined
\ No newline at end of file
diff --git a/jsfiddle/about/hello/demo.details b/jsfiddle/about/hello/demo.details
new file mode 100644
index 00000000..cfffa9d9
--- /dev/null
+++ b/jsfiddle/about/hello/demo.details
@@ -0,0 +1,9 @@
+/*
+---
+authors:
+ - Tao Xin
+resources:
+ - https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.2.7.nomodule.min.js
+panel_js: 2
+...
+*/
diff --git a/jsfiddle/about/hello/demo.js b/jsfiddle/about/hello/demo.js
new file mode 100644
index 00000000..79dc6b6e
--- /dev/null
+++ b/jsfiddle/about/hello/demo.js
@@ -0,0 +1,3 @@
+const {a, div, li, p, ul} = van.tags
+
+undefined
\ No newline at end of file
diff --git a/jsfiddle/advanced/advanced-state-derivation/demo.css b/jsfiddle/advanced/advanced-state-derivation/demo.css
index 36d53933..17c6c3fd 100644
--- a/jsfiddle/advanced/advanced-state-derivation/demo.css
+++ b/jsfiddle/advanced/advanced-state-derivation/demo.css
@@ -1,5 +1,5 @@
.label {
- font-weight: bold;
- display: inline-block;
- width: 100px;
-}
+ font-weight: bold;
+ display: inline-block;
+ width: 100px;
+ }
\ No newline at end of file
diff --git a/jsfiddle/advanced/counter/demo.details b/jsfiddle/advanced/counter/demo.details
new file mode 100644
index 00000000..cfffa9d9
--- /dev/null
+++ b/jsfiddle/advanced/counter/demo.details
@@ -0,0 +1,9 @@
+/*
+---
+authors:
+ - Tao Xin
+resources:
+ - https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.2.7.nomodule.min.js
+panel_js: 2
+...
+*/
diff --git a/jsfiddle/advanced/counter/demo.js b/jsfiddle/advanced/counter/demo.js
new file mode 100644
index 00000000..04c15415
--- /dev/null
+++ b/jsfiddle/advanced/counter/demo.js
@@ -0,0 +1,3 @@
+const {button, span} = van.tags
+
+undefined
\ No newline at end of file
diff --git a/jsfiddle/advanced/hello/demo.details b/jsfiddle/advanced/hello/demo.details
new file mode 100644
index 00000000..cfffa9d9
--- /dev/null
+++ b/jsfiddle/advanced/hello/demo.details
@@ -0,0 +1,9 @@
+/*
+---
+authors:
+ - Tao Xin
+resources:
+ - https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.2.7.nomodule.min.js
+panel_js: 2
+...
+*/
diff --git a/jsfiddle/advanced/hello/demo.js b/jsfiddle/advanced/hello/demo.js
new file mode 100644
index 00000000..79dc6b6e
--- /dev/null
+++ b/jsfiddle/advanced/hello/demo.js
@@ -0,0 +1,3 @@
+const {a, div, li, p, ul} = van.tags
+
+undefined
\ No newline at end of file
diff --git a/jsfiddle/convert/counter/demo.details b/jsfiddle/convert/counter/demo.details
new file mode 100644
index 00000000..cfffa9d9
--- /dev/null
+++ b/jsfiddle/convert/counter/demo.details
@@ -0,0 +1,9 @@
+/*
+---
+authors:
+ - Tao Xin
+resources:
+ - https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.2.7.nomodule.min.js
+panel_js: 2
+...
+*/
diff --git a/jsfiddle/convert/counter/demo.js b/jsfiddle/convert/counter/demo.js
new file mode 100644
index 00000000..04c15415
--- /dev/null
+++ b/jsfiddle/convert/counter/demo.js
@@ -0,0 +1,3 @@
+const {button, span} = van.tags
+
+undefined
\ No newline at end of file
diff --git a/jsfiddle/convert/hello/demo.details b/jsfiddle/convert/hello/demo.details
new file mode 100644
index 00000000..cfffa9d9
--- /dev/null
+++ b/jsfiddle/convert/hello/demo.details
@@ -0,0 +1,9 @@
+/*
+---
+authors:
+ - Tao Xin
+resources:
+ - https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.2.7.nomodule.min.js
+panel_js: 2
+...
+*/
diff --git a/jsfiddle/convert/hello/demo.js b/jsfiddle/convert/hello/demo.js
new file mode 100644
index 00000000..79dc6b6e
--- /dev/null
+++ b/jsfiddle/convert/hello/demo.js
@@ -0,0 +1,3 @@
+const {a, div, li, p, ul} = van.tags
+
+undefined
\ No newline at end of file
diff --git a/jsfiddle/demo/blog/demo.js b/jsfiddle/demo/blog/demo.js
index 91c965b5..1ee5eb49 100644
--- a/jsfiddle/demo/blog/demo.js
+++ b/jsfiddle/demo/blog/demo.js
@@ -12,5 +12,4 @@ const Post = ({title, body}) => [
const PostTitle = ({title}) => h1(title)
const PostBody = ({body}) => article(p(body))
-
van.add(document.body, Blog())
diff --git a/jsfiddle/demo/counter-advanced/demo.js b/jsfiddle/demo/counter-advanced/demo.js
index cbc74361..8daf4dd9 100644
--- a/jsfiddle/demo/counter-advanced/demo.js
+++ b/jsfiddle/demo/counter-advanced/demo.js
@@ -30,5 +30,4 @@ const CounterSet = () => {
),
)
}
-
van.add(document.body, CounterSet())
diff --git a/jsfiddle/demo/counter-simple/demo.js b/jsfiddle/demo/counter-simple/demo.js
index ba3aa173..9a796700 100644
--- a/jsfiddle/demo/counter-simple/demo.js
+++ b/jsfiddle/demo/counter-simple/demo.js
@@ -8,5 +8,4 @@ const Counter = () => {
button({onclick: () => --counter.val}, "👎"),
)
}
-
van.add(document.body, Counter())
diff --git a/jsfiddle/demo/counter/demo.details b/jsfiddle/demo/counter/demo.details
new file mode 100644
index 00000000..cfffa9d9
--- /dev/null
+++ b/jsfiddle/demo/counter/demo.details
@@ -0,0 +1,9 @@
+/*
+---
+authors:
+ - Tao Xin
+resources:
+ - https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.2.7.nomodule.min.js
+panel_js: 2
+...
+*/
diff --git a/jsfiddle/demo/counter/demo.js b/jsfiddle/demo/counter/demo.js
new file mode 100644
index 00000000..04c15415
--- /dev/null
+++ b/jsfiddle/demo/counter/demo.js
@@ -0,0 +1,3 @@
+const {button, span} = van.tags
+
+undefined
\ No newline at end of file
diff --git a/jsfiddle/demo/diff-simple/demo.css b/jsfiddle/demo/diff-simple/demo.css
index f48ce775..0e1affb2 100644
--- a/jsfiddle/demo/diff-simple/demo.css
+++ b/jsfiddle/demo/diff-simple/demo.css
@@ -1,18 +1,18 @@
.row { display: flex; }
-.column {
- width: 500px;
- margin: 2px;
-}
+ .column {
+ width: 500px;
+ margin: 2px;
+ }
-.column textarea {
- box-sizing: border-box;
- width: 100%;
-}
+ .column textarea {
+ box-sizing: border-box;
+ width: 100%;
+ }
-.add { background-color: #B5EFDB; }
+ .add { background-color: #B5EFDB; }
-.remove {
- background-color: #FFC4C1;
- text-decoration: line-through;
-}
+ .remove {
+ background-color: #FFC4C1;
+ text-decoration: line-through;
+ }
\ No newline at end of file
diff --git a/jsfiddle/demo/diff/demo.css b/jsfiddle/demo/diff/demo.css
index de4ceec0..a004382f 100644
--- a/jsfiddle/demo/diff/demo.css
+++ b/jsfiddle/demo/diff/demo.css
@@ -1,15 +1,15 @@
.row { display: flex; }
-.column {
- width: 500px;
- margin: 2px;
-}
+ .column {
+ width: 500px;
+ margin: 2px;
+ }
-.column textarea {
- box-sizing: border-box;
- width: 100%;
-}
+ .column textarea {
+ box-sizing: border-box;
+ width: 100%;
+ }
-.add { background-color: #B5EFDB; }
-.remove { background-color: #FFC4C1; }
-.merged .remove { text-decoration: line-through; }
+ .add { background-color: #B5EFDB; }
+ .remove { background-color: #FFC4C1; }
+ .merged .remove { text-decoration: line-through; }
\ No newline at end of file
diff --git a/jsfiddle/demo/hello-fun/demo.js b/jsfiddle/demo/hello-fun/demo.js
index 0c2df018..d6b7bc8f 100644
--- a/jsfiddle/demo/hello-fun/demo.js
+++ b/jsfiddle/demo/hello-fun/demo.js
@@ -1,5 +1,7 @@
const {button, div, pre} = van.tags
+const {button, div, pre} = van.tags
+
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
const Run = ({sleepMs}) => {
@@ -21,3 +23,4 @@ const Hello = () => {
}
van.add(document.body, Hello())
+van.add(document.body, Hello())
diff --git a/jsfiddle/demo/hello/demo.js b/jsfiddle/demo/hello/demo.js
index 863df883..e6b34cb1 100644
--- a/jsfiddle/demo/hello/demo.js
+++ b/jsfiddle/demo/hello/demo.js
@@ -7,5 +7,4 @@ const Hello = () => div(
li(a({href: "https://vanjs.org/"}, "🍦VanJS")),
),
)
-
van.add(document.body, Hello())
diff --git a/jsfiddle/demo/js-console/demo.css b/jsfiddle/demo/js-console/demo.css
index 291405aa..9fb8e0c2 100644
--- a/jsfiddle/demo/js-console/demo.css
+++ b/jsfiddle/demo/js-console/demo.css
@@ -1,41 +1,41 @@
body { max-width: 960px; }
-.row {
- display: flex;
- flex-flow: wrap;
-}
+ .row {
+ display: flex;
+ flex-flow: wrap;
+ }
-.left {
- width: 60px;
- text-align: right;
-}
+ .left {
+ width: 60px;
+ text-align: right;
+ }
-.run {
- display: none;
- margin: 9px;
-}
+ .run {
+ display: none;
+ margin: 9px;
+ }
-@media (max-width: 450px), (pointer:none), (pointer:coarse) {
- .break { width: 100%; }
- .run { display: unset; }
-}
+ @media (max-width: 450px), (pointer:none), (pointer:coarse) {
+ .break { width: 100%; }
+ .run { display: unset; }
+ }
-.right { flex-grow: 1; }
+ .right { flex-grow: 1; }
-.right textarea, .right table {
- margin: 11px;
- border-width: 1px;
- box-sizing: border-box;
- font: 15px monospace;
- width: 100%;
-}
+ .right textarea, .right table {
+ margin: 11px;
+ border-width: 1px;
+ box-sizing: border-box;
+ font: 15px monospace;
+ width: 100%;
+ }
-.right pre, .right .chart { margin: 12px; }
+ .right pre, .right .chart { margin: 12px; }
-a { cursor: pointer ;}
+ a { cursor: pointer ;}
-table { border-collapse: collapse; }
+ table { border-collapse: collapse; }
-th, td { border: 1px solid black; }
+ th, td { border: 1px solid black; }
-.err { color: red; }
+ .err { color: red; }
\ No newline at end of file
diff --git a/jsfiddle/demo/jsfiddle-static/demo.details b/jsfiddle/demo/jsfiddle-static/demo.details
new file mode 100644
index 00000000..cfffa9d9
--- /dev/null
+++ b/jsfiddle/demo/jsfiddle-static/demo.details
@@ -0,0 +1,9 @@
+/*
+---
+authors:
+ - Tao Xin
+resources:
+ - https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.2.7.nomodule.min.js
+panel_js: 2
+...
+*/
diff --git a/jsfiddle/demo/jsfiddle-static/demo.js b/jsfiddle/demo/jsfiddle-static/demo.js
new file mode 100644
index 00000000..69b6158a
--- /dev/null
+++ b/jsfiddle/demo/jsfiddle-static/demo.js
@@ -0,0 +1,20 @@
+const {a, button, div, h1} = van.tags
+
+const StaticDom = () => {
+ const dom = div(
+ div(
+ button("Dummy Button"),
+ button(
+ {onclick: () =>
+ van.add(dom,
+ div(button("New Button")),
+ div(a({href: "https://www.example.com/"}, "This is a link")),
+ )
+ },
+ "Button to Add More Elements"),
+ button({onclick: () => alert("Hello from 🍦VanJS")}, "Hello"),
+ ),
+ )
+ return dom
+ }
+van.add(document.body, StaticDom())
diff --git a/jsfiddle/demo/json-inspector/demo.css b/jsfiddle/demo/json-inspector/demo.css
index 4cb774a7..92a2abb4 100644
--- a/jsfiddle/demo/json-inspector/demo.css
+++ b/jsfiddle/demo/json-inspector/demo.css
@@ -1,4 +1,4 @@
textarea {
width: 100%;
max-width: 700px;
-}
+}
\ No newline at end of file
diff --git a/jsfiddle/demo/key-inspector/demo.css b/jsfiddle/demo/key-inspector/demo.css
index c7d8cd5f..95fad3e5 100644
--- a/jsfiddle/demo/key-inspector/demo.css
+++ b/jsfiddle/demo/key-inspector/demo.css
@@ -8,4 +8,4 @@
.label, .value {
font: monospace;
display: inline-block;
-}
+}
\ No newline at end of file
diff --git a/jsfiddle/demo/list-declarative/demo.js b/jsfiddle/demo/list-declarative/demo.js
index fa94af46..23c2ff66 100644
--- a/jsfiddle/demo/list-declarative/demo.js
+++ b/jsfiddle/demo/list-declarative/demo.js
@@ -8,5 +8,4 @@ const EvenNumbers = ({N}) => div(
.map(i => li(i)),
),
)
-
van.add(document.body, EvenNumbers({N: 20}))
diff --git a/jsfiddle/demo/static/demo.js b/jsfiddle/demo/static/demo.js
index 8899ac84..50130a88 100644
--- a/jsfiddle/demo/static/demo.js
+++ b/jsfiddle/demo/static/demo.js
@@ -17,5 +17,4 @@ const StaticDom = () => {
)
return dom
}
-
van.add(document.body, StaticDom())
diff --git a/jsfiddle/demo/stopwatch/demo.js b/jsfiddle/demo/stopwatch/demo.js
index b260b825..e8df4804 100644
--- a/jsfiddle/demo/stopwatch/demo.js
+++ b/jsfiddle/demo/stopwatch/demo.js
@@ -11,5 +11,4 @@ const Stopwatch = () => {
button({onclick: () => (clearInterval(id), id = 0, elapsed.val = 0)}, "Reset"),
)
}
-
van.add(document.body, Stopwatch())
diff --git a/jsfiddle/demo/table-viewer/demo.css b/jsfiddle/demo/table-viewer/demo.css
index f8e219d2..13788e09 100644
--- a/jsfiddle/demo/table-viewer/demo.css
+++ b/jsfiddle/demo/table-viewer/demo.css
@@ -1,10 +1,10 @@
.err { color: red; }
-table { border-collapse: collapse; }
+ table { border-collapse: collapse; }
-table, th, td { border: 1px solid black; }
+ table, th, td { border: 1px solid black; }
-textarea {
- width: 100%;
- max-width: 700px;
-}
+ textarea {
+ width: 100%;
+ max-width: 700px;
+ }
\ No newline at end of file
diff --git a/jsfiddle/demo/todo-procedural/demo.js b/jsfiddle/demo/todo-procedural/demo.js
index 4f48d2d9..1b56a252 100644
--- a/jsfiddle/demo/todo-procedural/demo.js
+++ b/jsfiddle/demo/todo-procedural/demo.js
@@ -17,5 +17,4 @@ const TodoList = () => {
)
return dom
}
-
van.add(document.body, TodoList())
diff --git a/jsfiddle/home/counter/demo.js b/jsfiddle/home/counter/demo.js
index ba3aa173..04c15415 100644
--- a/jsfiddle/home/counter/demo.js
+++ b/jsfiddle/home/counter/demo.js
@@ -1,12 +1,3 @@
const {button, span} = van.tags
-const Counter = () => {
- const counter = van.state(0)
- return span(
- "❤️ ", counter, " ",
- button({onclick: () => ++counter.val}, "👍"),
- button({onclick: () => --counter.val}, "👎"),
- )
-}
-
-van.add(document.body, Counter())
+undefined
\ No newline at end of file
diff --git a/jsfiddle/home/hello/demo.js b/jsfiddle/home/hello/demo.js
index f298bd66..79dc6b6e 100644
--- a/jsfiddle/home/hello/demo.js
+++ b/jsfiddle/home/hello/demo.js
@@ -1,15 +1,3 @@
const {a, div, li, p, ul} = van.tags
-// Reusable components can be just pure vanilla JavaScript functions.
-// Here we capitalize the first letter to follow React conventions.
-const Hello = () => div(
- p("👋Hello"),
- ul(
- li("🗺️World"),
- li(a({href: "https://vanjs.org/"}, "🍦VanJS")),
- ),
-)
-
-van.add(document.body, Hello())
-// Alternatively, you can write:
-// document.body.appendChild(Hello())
+undefined
\ No newline at end of file
diff --git a/jsfiddle/media/counter/demo.details b/jsfiddle/media/counter/demo.details
new file mode 100644
index 00000000..cfffa9d9
--- /dev/null
+++ b/jsfiddle/media/counter/demo.details
@@ -0,0 +1,9 @@
+/*
+---
+authors:
+ - Tao Xin
+resources:
+ - https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.2.7.nomodule.min.js
+panel_js: 2
+...
+*/
diff --git a/jsfiddle/media/counter/demo.js b/jsfiddle/media/counter/demo.js
new file mode 100644
index 00000000..04c15415
--- /dev/null
+++ b/jsfiddle/media/counter/demo.js
@@ -0,0 +1,3 @@
+const {button, span} = van.tags
+
+undefined
\ No newline at end of file
diff --git a/jsfiddle/media/hello/demo.details b/jsfiddle/media/hello/demo.details
new file mode 100644
index 00000000..cfffa9d9
--- /dev/null
+++ b/jsfiddle/media/hello/demo.details
@@ -0,0 +1,9 @@
+/*
+---
+authors:
+ - Tao Xin
+resources:
+ - https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.2.7.nomodule.min.js
+panel_js: 2
+...
+*/
diff --git a/jsfiddle/media/hello/demo.js b/jsfiddle/media/hello/demo.js
new file mode 100644
index 00000000..79dc6b6e
--- /dev/null
+++ b/jsfiddle/media/hello/demo.js
@@ -0,0 +1,3 @@
+const {a, div, li, p, ul} = van.tags
+
+undefined
\ No newline at end of file
diff --git a/jsfiddle/minivan/counter/demo.details b/jsfiddle/minivan/counter/demo.details
new file mode 100644
index 00000000..cfffa9d9
--- /dev/null
+++ b/jsfiddle/minivan/counter/demo.details
@@ -0,0 +1,9 @@
+/*
+---
+authors:
+ - Tao Xin
+resources:
+ - https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.2.7.nomodule.min.js
+panel_js: 2
+...
+*/
diff --git a/jsfiddle/minivan/counter/demo.js b/jsfiddle/minivan/counter/demo.js
new file mode 100644
index 00000000..04c15415
--- /dev/null
+++ b/jsfiddle/minivan/counter/demo.js
@@ -0,0 +1,3 @@
+const {button, span} = van.tags
+
+undefined
\ No newline at end of file
diff --git a/jsfiddle/minivan/hello/demo.js b/jsfiddle/minivan/hello/demo.js
index f298bd66..4545fd05 100644
--- a/jsfiddle/minivan/hello/demo.js
+++ b/jsfiddle/minivan/hello/demo.js
@@ -12,4 +12,4 @@ const Hello = () => div(
van.add(document.body, Hello())
// Alternatively, you can write:
-// document.body.appendChild(Hello())
+// document.body.appendChild(Hello())
\ No newline at end of file
diff --git a/jsfiddle/ssr/counter/demo.details b/jsfiddle/ssr/counter/demo.details
new file mode 100644
index 00000000..cfffa9d9
--- /dev/null
+++ b/jsfiddle/ssr/counter/demo.details
@@ -0,0 +1,9 @@
+/*
+---
+authors:
+ - Tao Xin
+resources:
+ - https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.2.7.nomodule.min.js
+panel_js: 2
+...
+*/
diff --git a/jsfiddle/ssr/counter/demo.js b/jsfiddle/ssr/counter/demo.js
new file mode 100644
index 00000000..04c15415
--- /dev/null
+++ b/jsfiddle/ssr/counter/demo.js
@@ -0,0 +1,3 @@
+const {button, span} = van.tags
+
+undefined
\ No newline at end of file
diff --git a/jsfiddle/ssr/hello/demo.details b/jsfiddle/ssr/hello/demo.details
new file mode 100644
index 00000000..cfffa9d9
--- /dev/null
+++ b/jsfiddle/ssr/hello/demo.details
@@ -0,0 +1,9 @@
+/*
+---
+authors:
+ - Tao Xin
+resources:
+ - https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.2.7.nomodule.min.js
+panel_js: 2
+...
+*/
diff --git a/jsfiddle/ssr/hello/demo.js b/jsfiddle/ssr/hello/demo.js
new file mode 100644
index 00000000..79dc6b6e
--- /dev/null
+++ b/jsfiddle/ssr/hello/demo.js
@@ -0,0 +1,3 @@
+const {a, div, li, p, ul} = van.tags
+
+undefined
\ No newline at end of file
diff --git a/jsfiddle/start/counter/demo.details b/jsfiddle/start/counter/demo.details
new file mode 100644
index 00000000..cfffa9d9
--- /dev/null
+++ b/jsfiddle/start/counter/demo.details
@@ -0,0 +1,9 @@
+/*
+---
+authors:
+ - Tao Xin
+resources:
+ - https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.2.7.nomodule.min.js
+panel_js: 2
+...
+*/
diff --git a/jsfiddle/start/counter/demo.js b/jsfiddle/start/counter/demo.js
new file mode 100644
index 00000000..04c15415
--- /dev/null
+++ b/jsfiddle/start/counter/demo.js
@@ -0,0 +1,3 @@
+const {button, span} = van.tags
+
+undefined
\ No newline at end of file
diff --git a/jsfiddle/start/hello-fun/demo.js b/jsfiddle/start/hello-fun/demo.js
index 0c2df018..fb87a907 100644
--- a/jsfiddle/start/hello-fun/demo.js
+++ b/jsfiddle/start/hello-fun/demo.js
@@ -20,4 +20,4 @@ const Hello = () => {
)
}
-van.add(document.body, Hello())
+van.add(document.body, Hello())
\ No newline at end of file
diff --git a/jsfiddle/start/hello/demo.details b/jsfiddle/start/hello/demo.details
new file mode 100644
index 00000000..cfffa9d9
--- /dev/null
+++ b/jsfiddle/start/hello/demo.details
@@ -0,0 +1,9 @@
+/*
+---
+authors:
+ - Tao Xin
+resources:
+ - https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.2.7.nomodule.min.js
+panel_js: 2
+...
+*/
diff --git a/jsfiddle/start/hello/demo.js b/jsfiddle/start/hello/demo.js
new file mode 100644
index 00000000..79dc6b6e
--- /dev/null
+++ b/jsfiddle/start/hello/demo.js
@@ -0,0 +1,3 @@
+const {a, div, li, p, ul} = van.tags
+
+undefined
\ No newline at end of file
diff --git a/jsfiddle/start/jsfiddle-hello-fun/demo.details b/jsfiddle/start/jsfiddle-hello-fun/demo.details
new file mode 100644
index 00000000..cfffa9d9
--- /dev/null
+++ b/jsfiddle/start/jsfiddle-hello-fun/demo.details
@@ -0,0 +1,9 @@
+/*
+---
+authors:
+ - Tao Xin
+resources:
+ - https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.2.7.nomodule.min.js
+panel_js: 2
+...
+*/
diff --git a/jsfiddle/tutorial/connected-props/demo.js b/jsfiddle/tutorial/connected-props/demo.js
index 5bdadf0a..7fc39de3 100644
--- a/jsfiddle/tutorial/connected-props/demo.js
+++ b/jsfiddle/tutorial/connected-props/demo.js
@@ -8,4 +8,4 @@ const ConnectedProps = () => {
)
}
-van.add(document.body, ConnectedProps())
+van.add(document.body, ConnectedProps())
\ No newline at end of file
diff --git a/jsfiddle/tutorial/counter/demo.details b/jsfiddle/tutorial/counter/demo.details
new file mode 100644
index 00000000..cfffa9d9
--- /dev/null
+++ b/jsfiddle/tutorial/counter/demo.details
@@ -0,0 +1,9 @@
+/*
+---
+authors:
+ - Tao Xin
+resources:
+ - https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.2.7.nomodule.min.js
+panel_js: 2
+...
+*/
diff --git a/jsfiddle/tutorial/counter/demo.js b/jsfiddle/tutorial/counter/demo.js
new file mode 100644
index 00000000..04c15415
--- /dev/null
+++ b/jsfiddle/tutorial/counter/demo.js
@@ -0,0 +1,3 @@
+const {button, span} = van.tags
+
+undefined
\ No newline at end of file
diff --git a/jsfiddle/tutorial/editable-list/demo.js b/jsfiddle/tutorial/editable-list/demo.js
index c7675cc6..2185e9d3 100644
--- a/jsfiddle/tutorial/editable-list/demo.js
+++ b/jsfiddle/tutorial/editable-list/demo.js
@@ -17,4 +17,4 @@ const EditableList = () => {
)
}
-van.add(document.body, EditableList())
+van.add(document.body, EditableList())
\ No newline at end of file
diff --git a/jsfiddle/tutorial/euler/demo.js b/jsfiddle/tutorial/euler/demo.js
index 43edc7a3..3f625fa4 100644
--- a/jsfiddle/tutorial/euler/demo.js
+++ b/jsfiddle/tutorial/euler/demo.js
@@ -4,4 +4,4 @@ const Euler = () => math(
msup(mi("e"), mrow(mi("i"), mi("π"))), mo("+"), mn("1"), mo("="), mn("0"),
)
-van.add(document.body, Euler())
+van.add(document.body, Euler())
\ No newline at end of file
diff --git a/jsfiddle/tutorial/hello/demo.js b/jsfiddle/tutorial/hello/demo.js
index 863df883..b9026147 100644
--- a/jsfiddle/tutorial/hello/demo.js
+++ b/jsfiddle/tutorial/hello/demo.js
@@ -8,4 +8,4 @@ const Hello = () => div(
),
)
-van.add(document.body, Hello())
+van.add(document.body, Hello())
\ No newline at end of file
diff --git a/jsfiddle/tutorial/list/demo.js b/jsfiddle/tutorial/list/demo.js
index f97ef68c..316a9881 100644
--- a/jsfiddle/tutorial/list/demo.js
+++ b/jsfiddle/tutorial/list/demo.js
@@ -2,4 +2,4 @@ const {li, ul} = van.tags
const List = ({items}) => ul(items.map(it => li(it)))
-van.add(document.body, List({items: ["Item 1", "Item 2", "Item 3"]}))
+van.add(document.body, List({items: ["Item 1", "Item 2", "Item 3"]}))
\ No newline at end of file
diff --git a/jsfiddle/tutorial/smiley/demo.js b/jsfiddle/tutorial/smiley/demo.js
index 8907fe81..025d9baa 100644
--- a/jsfiddle/tutorial/smiley/demo.js
+++ b/jsfiddle/tutorial/smiley/demo.js
@@ -7,4 +7,4 @@ const Smiley = () => svg({width: "16px", viewBox: "0 0 50 50"},
path({"d": "M 15 30 Q 25 40, 35 30", stroke: "black", "stroke-width": "2", fill: "transparent"}),
)
-van.add(document.body, Smiley())
+van.add(document.body, Smiley())
\ No newline at end of file
diff --git a/jsfiddle/tutorial/sorted-list/demo.js b/jsfiddle/tutorial/sorted-list/demo.js
index 67143f73..52b8c479 100644
--- a/jsfiddle/tutorial/sorted-list/demo.js
+++ b/jsfiddle/tutorial/sorted-list/demo.js
@@ -17,4 +17,4 @@ const SortedList = () => {
)
}
-van.add(document.body, SortedList())
+van.add(document.body, SortedList())
\ No newline at end of file
diff --git a/jsfiddle/tutorial/table/demo.js b/jsfiddle/tutorial/table/demo.js
index 416fe4a0..d2448e23 100644
--- a/jsfiddle/tutorial/table/demo.js
+++ b/jsfiddle/tutorial/table/demo.js
@@ -14,4 +14,4 @@ van.add(document.body, Table({
[2, "Jane Smith", "CA"],
[3, "Bob Johnson", "AU"],
],
-}))
+}))
\ No newline at end of file
diff --git a/jsfiddle/tutorial/timer/demo.js b/jsfiddle/tutorial/timer/demo.js
index b8d6cb74..20f3dfed 100644
--- a/jsfiddle/tutorial/timer/demo.js
+++ b/jsfiddle/tutorial/timer/demo.js
@@ -15,4 +15,4 @@ const Timer = ({totalSecs}) => {
)
}
-van.add(document.body, Timer({totalSecs: 5}))
+van.add(document.body, Timer({totalSecs: 5}))
\ No newline at end of file
diff --git a/jsfiddle/vanui/counter/demo.details b/jsfiddle/vanui/counter/demo.details
new file mode 100644
index 00000000..cfffa9d9
--- /dev/null
+++ b/jsfiddle/vanui/counter/demo.details
@@ -0,0 +1,9 @@
+/*
+---
+authors:
+ - Tao Xin
+resources:
+ - https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.2.7.nomodule.min.js
+panel_js: 2
+...
+*/
diff --git a/jsfiddle/vanui/counter/demo.js b/jsfiddle/vanui/counter/demo.js
new file mode 100644
index 00000000..04c15415
--- /dev/null
+++ b/jsfiddle/vanui/counter/demo.js
@@ -0,0 +1,3 @@
+const {button, span} = van.tags
+
+undefined
\ No newline at end of file
diff --git a/jsfiddle/vanui/hello/demo.details b/jsfiddle/vanui/hello/demo.details
new file mode 100644
index 00000000..cfffa9d9
--- /dev/null
+++ b/jsfiddle/vanui/hello/demo.details
@@ -0,0 +1,9 @@
+/*
+---
+authors:
+ - Tao Xin
+resources:
+ - https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.2.7.nomodule.min.js
+panel_js: 2
+...
+*/
diff --git a/jsfiddle/vanui/hello/demo.js b/jsfiddle/vanui/hello/demo.js
new file mode 100644
index 00000000..79dc6b6e
--- /dev/null
+++ b/jsfiddle/vanui/hello/demo.js
@@ -0,0 +1,3 @@
+const {a, div, li, p, ul} = van.tags
+
+undefined
\ No newline at end of file
diff --git a/jsfiddle/x/counter/demo.details b/jsfiddle/x/counter/demo.details
new file mode 100644
index 00000000..cfffa9d9
--- /dev/null
+++ b/jsfiddle/x/counter/demo.details
@@ -0,0 +1,9 @@
+/*
+---
+authors:
+ - Tao Xin
+resources:
+ - https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.2.7.nomodule.min.js
+panel_js: 2
+...
+*/
diff --git a/jsfiddle/x/counter/demo.js b/jsfiddle/x/counter/demo.js
new file mode 100644
index 00000000..04c15415
--- /dev/null
+++ b/jsfiddle/x/counter/demo.js
@@ -0,0 +1,3 @@
+const {button, span} = van.tags
+
+undefined
\ No newline at end of file
diff --git a/jsfiddle/x/hello/demo.details b/jsfiddle/x/hello/demo.details
new file mode 100644
index 00000000..cfffa9d9
--- /dev/null
+++ b/jsfiddle/x/hello/demo.details
@@ -0,0 +1,9 @@
+/*
+---
+authors:
+ - Tao Xin
+resources:
+ - https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.2.7.nomodule.min.js
+panel_js: 2
+...
+*/
diff --git a/jsfiddle/x/hello/demo.js b/jsfiddle/x/hello/demo.js
new file mode 100644
index 00000000..79dc6b6e
--- /dev/null
+++ b/jsfiddle/x/hello/demo.js
@@ -0,0 +1,3 @@
+const {a, div, li, p, ul} = van.tags
+
+undefined
\ No newline at end of file
diff --git a/media.html b/media.html
deleted file mode 100644
index eec1e399..00000000
--- a/media.html
+++ /dev/null
@@ -1,111 +0,0 @@
-
-
-
- VanJS - Media Coverage
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ☰
- Media Coverage
-
-
-
-
-
-
-
-
-
VanJS: Media Coverage
🙏🙏🙏 VanJS is a personal project, which means I don't have the time and resources to promote it to a wider audience. My heartfelt gratitude extends towards to all content creators and tech bloggers who are helping spread good words about VanJS. Your help is invaluable in our pursuit of VanJS's mission: Enabling everyone to build useful UI apps with a few lines of code, anywhere, any time, on any device.
-
-
-
-
-
-
\ No newline at end of file
diff --git a/media/index.html b/media/index.html
deleted file mode 100644
index eec1e399..00000000
--- a/media/index.html
+++ /dev/null
@@ -1,111 +0,0 @@
-
-
-
- VanJS - Media Coverage
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ☰
- Media Coverage
-
-
-
-
-
-
-
-
-
VanJS: Media Coverage
🙏🙏🙏 VanJS is a personal project, which means I don't have the time and resources to promote it to a wider audience. My heartfelt gratitude extends towards to all content creators and tech bloggers who are helping spread good words about VanJS. Your help is invaluable in our pursuit of VanJS's mission: Enabling everyone to build useful UI apps with a few lines of code, anywhere, any time, on any device.
Mini-Van: A Minimalist Template Engine for Client/Server-side Rendering without JSX
Mini-Van is an ultra-lightweight template engine for DOM composition and manipulation. With only 0.7kB in the minified bundle size (0.5kB gzipped), Mini-Van enables you to build comprehensive UI with elegant and expressive vanilla JavaScript code:
// Reusable components can be just pure vanilla JavaScript functions.
-// Here we capitalize the first letter to follow React conventions.
-const Hello = () => div(
- p("👋Hello"),
- ul(
- li("🗺️World"),
- li(a({href: "https://vanjs.org/"}, "🍦VanJS")),
- ),
-)
-
-van.add(document.body, Hello())
-// Alternatively, you can write:
-// document.body.appendChild(Hello())
-
You can convert any HTML snippet into Mini-Van code with our online converter.
Mini-Van is the slimmed-down version of VanJS, which aims to provide an ultra-lightweight, zero-dependency, and unopinionated Reactive UI framework based on pure vanilla JavaScript and DOM. Compared to VanJS, Mini-Van further reduces the gzipped minified bundle size to 0.5kB and (more importantly) can be used on the server-side as a template engine.
Mini-Van can be used on the server side as a template engine to render dynamic web content for HTTP servers. An NPM package was published here: www.npmjs.com/package/mini-van-plate. Thus it can be used in Node.js or Bun.
There are 2 modes for server-side integration: van-plate mode (based on text templating, thus doesn't need the DOM dependency), and mini-van mode (based on DOM, thus needs the DOM dependency).
In van-plate mode, HTML content is generated purely through text templating. It can be easily integrated with your HTTP server to render dynamic web content. See the sample code below:
import http from "node:http"
-import van from "mini-van-plate/van-plate"
-
-const {a, body, button, input, li, p, ul} = van.tags
-
-const port = 8080
-
-console.log("Testing DOM rendering...")
-// Expecting `<a href="https://vanjs.org/">🍦VanJS</a>` printed in the console
-console.log(a({href: "https://vanjs.org/"}, "🍦VanJS").render())
-// Expecting `<button onclick="alert("Hello")">Click</button>` printed in the console
-console.log(button({onclick: 'alert("Hello")'}, "Click").render())
-// Expecting `<input type="text" value="value">` printed in the console
-console.log(input({type: "text", value: "value"}).render())
-
-const server = http.createServer((req, res) => {
- res.statusCode = 200
- res.setHeader('Content-Type', 'text/html; charset=utf-8')
- res.end(van.html(
- body(
- p("Your user-agent is: ", req.headers["user-agent"] ?? "Unknown"),
- p("👋Hello"),
- ul(
- li("🗺️World"),
- li(a({href: "https://vanjs.org/"}, "🍦VanJS")),
- ),
- ),
- ))
-})
-
-server.listen(port, () => console.log(`Server running at http://localhost:${port}/`))
-
As illustrated in the example, render method can be called on the object returned from the tag function to generate a string that can be used for serving.
van.html is a helper function defined in van-plate.js that is equivalent to:
The behavior in mini-van mode is similar to the behavior in browser context. i.e.: DOM objects will be created by tag functions. As Node doesn't have the built-in support for DOM objects, you need to provide a 3rd-party Document object before integrating with Mini-Van in this mode.
There are multiple 3rd-party options for the Document object. In the example below, we will demonstrate the integration with the help of jsdom.
Note that, mini-van mode doesn't work in Bun yet due to the integration issue with jsdom.
First, install jsdom:
npm install jsdom
Sample code:
import http from "node:http"
-import jsdom from "jsdom"
-import van from "mini-van-plate"
-
-const dom = new jsdom.JSDOM("")
-const {html, tags: {a, body, button, input, li, p, ul}} = van.vanWithDoc(dom.window.document)
-
-const port = 8080
-
-console.log("Testing DOM rendering...")
-// Expecting `<a href="https://vanjs.org/">🍦VanJS</a>` printed in the console
-console.log(a({href: "https://vanjs.org/"}, "🍦VanJS").outerHTML)
-// Expecting `<button onclick="alert("Hello")">Click</button>` printed in the console
-console.log(button({onclick: 'alert("Hello")'}, "Click").outerHTML)
-// Expecting `<input type="text" value="value">` printed in the console
-console.log(input({type: "text", value: "value"}).outerHTML)
-
-const server = http.createServer((req, res) => {
- res.statusCode = 200
- res.setHeader('Content-Type', 'text/html; charset=utf-8')
- res.end(html(
- body(
- p("Your user-agent is: ", req.headers["user-agent"] ?? "Unknown"),
- p("👋Hello"),
- ul(
- li("🗺️World"),
- li(a({href: "https://vanjs.org/"}, "🍦VanJS")),
- ),
- ),
- ))
-})
-
-server.listen(port, () => console.log(`Server running at http://localhost:${port}/`))
-
Mini-Van exposes the same set of APIs as VanJS for DOM composition and manipulation. Thus for API reference, you can refer to DOM Composition and Manipulation section of VanJS tutorial. Note that: state and state binding are not supported in Mini-Van.
🙏 VanJS aims to build a better world by reducing the entry barrier for UI programming, with no intention or plan on commercialization whatsoever. If you find VanJS interesting, or could be useful for you some day, please consider starring the project on GitHub. It takes just a few seconds but your support means the world to us and helps spread VanJS to a wider audience.
We're looking for the 1.0 milestone (commitment to API stability) soon, your precious feedback will be greatly appreciated. You can submit your feedback by creating issues with the link below:
Mini-Van: A Minimalist Template Engine for Client/Server-side Rendering without JSX
Mini-Van is an ultra-lightweight template engine for DOM composition and manipulation. With only 0.7kB in the minified bundle size (0.5kB gzipped), Mini-Van enables you to build comprehensive UI with elegant and expressive vanilla JavaScript code:
// Reusable components can be just pure vanilla JavaScript functions.
-// Here we capitalize the first letter to follow React conventions.
-const Hello = () => div(
- p("👋Hello"),
- ul(
- li("🗺️World"),
- li(a({href: "https://vanjs.org/"}, "🍦VanJS")),
- ),
-)
-
-van.add(document.body, Hello())
-// Alternatively, you can write:
-// document.body.appendChild(Hello())
-
You can convert any HTML snippet into Mini-Van code with our online converter.
Mini-Van is the slimmed-down version of VanJS, which aims to provide an ultra-lightweight, zero-dependency, and unopinionated Reactive UI framework based on pure vanilla JavaScript and DOM. Compared to VanJS, Mini-Van further reduces the gzipped minified bundle size to 0.5kB and (more importantly) can be used on the server-side as a template engine.
Mini-Van can be used on the server side as a template engine to render dynamic web content for HTTP servers. An NPM package was published here: www.npmjs.com/package/mini-van-plate. Thus it can be used in Node.js or Bun.
There are 2 modes for server-side integration: van-plate mode (based on text templating, thus doesn't need the DOM dependency), and mini-van mode (based on DOM, thus needs the DOM dependency).
In van-plate mode, HTML content is generated purely through text templating. It can be easily integrated with your HTTP server to render dynamic web content. See the sample code below:
import http from "node:http"
-import van from "mini-van-plate/van-plate"
-
-const {a, body, button, input, li, p, ul} = van.tags
-
-const port = 8080
-
-console.log("Testing DOM rendering...")
-// Expecting `<a href="https://vanjs.org/">🍦VanJS</a>` printed in the console
-console.log(a({href: "https://vanjs.org/"}, "🍦VanJS").render())
-// Expecting `<button onclick="alert("Hello")">Click</button>` printed in the console
-console.log(button({onclick: 'alert("Hello")'}, "Click").render())
-// Expecting `<input type="text" value="value">` printed in the console
-console.log(input({type: "text", value: "value"}).render())
-
-const server = http.createServer((req, res) => {
- res.statusCode = 200
- res.setHeader('Content-Type', 'text/html; charset=utf-8')
- res.end(van.html(
- body(
- p("Your user-agent is: ", req.headers["user-agent"] ?? "Unknown"),
- p("👋Hello"),
- ul(
- li("🗺️World"),
- li(a({href: "https://vanjs.org/"}, "🍦VanJS")),
- ),
- ),
- ))
-})
-
-server.listen(port, () => console.log(`Server running at http://localhost:${port}/`))
-
As illustrated in the example, render method can be called on the object returned from the tag function to generate a string that can be used for serving.
van.html is a helper function defined in van-plate.js that is equivalent to:
The behavior in mini-van mode is similar to the behavior in browser context. i.e.: DOM objects will be created by tag functions. As Node doesn't have the built-in support for DOM objects, you need to provide a 3rd-party Document object before integrating with Mini-Van in this mode.
There are multiple 3rd-party options for the Document object. In the example below, we will demonstrate the integration with the help of jsdom.
Note that, mini-van mode doesn't work in Bun yet due to the integration issue with jsdom.
First, install jsdom:
npm install jsdom
Sample code:
import http from "node:http"
-import jsdom from "jsdom"
-import van from "mini-van-plate"
-
-const dom = new jsdom.JSDOM("")
-const {html, tags: {a, body, button, input, li, p, ul}} = van.vanWithDoc(dom.window.document)
-
-const port = 8080
-
-console.log("Testing DOM rendering...")
-// Expecting `<a href="https://vanjs.org/">🍦VanJS</a>` printed in the console
-console.log(a({href: "https://vanjs.org/"}, "🍦VanJS").outerHTML)
-// Expecting `<button onclick="alert("Hello")">Click</button>` printed in the console
-console.log(button({onclick: 'alert("Hello")'}, "Click").outerHTML)
-// Expecting `<input type="text" value="value">` printed in the console
-console.log(input({type: "text", value: "value"}).outerHTML)
-
-const server = http.createServer((req, res) => {
- res.statusCode = 200
- res.setHeader('Content-Type', 'text/html; charset=utf-8')
- res.end(html(
- body(
- p("Your user-agent is: ", req.headers["user-agent"] ?? "Unknown"),
- p("👋Hello"),
- ul(
- li("🗺️World"),
- li(a({href: "https://vanjs.org/"}, "🍦VanJS")),
- ),
- ),
- ))
-})
-
-server.listen(port, () => console.log(`Server running at http://localhost:${port}/`))
-
Mini-Van exposes the same set of APIs as VanJS for DOM composition and manipulation. Thus for API reference, you can refer to DOM Composition and Manipulation section of VanJS tutorial. Note that: state and state binding are not supported in Mini-Van.
🙏 VanJS aims to build a better world by reducing the entry barrier for UI programming, with no intention or plan on commercialization whatsoever. If you find VanJS interesting, or could be useful for you some day, please consider starring the project on GitHub. It takes just a few seconds but your support means the world to us and helps spread VanJS to a wider audience.
We're looking for the 1.0 milestone (commitment to API stability) soon, your precious feedback will be greatly appreciated. You can submit your feedback by creating issues with the link below:
\n",
- ),
- ),
- p(
- "will be converted to:",
- ),
- pre(
- code({class: "language-js"},
- "div(\n p(\n \"👋Hello\",\n ),\n ul(\n li(\n \"🗺️World\",\n ),\n li(\n a({href: \"https://vanjs.org/\"},\n \"🍦VanJS\",\n ),\n ),\n ),\n)\n",
- ),
- ),
- p(
- "if ",
- Symbol(
- "skipEmptyText",
- ),
- " is ",
- Symbol(
- "true",
- ),
- ". But it will be converted to:",
- ),
- pre(
- code({class: "language-js"},
- "div(\n \"\\n \",\n p(\n \"👋Hello\",\n ),\n \"\\n \",\n ul(\n \"\\n \",\n li(\n \"🗺️World\",\n ),\n \"\\n \",\n li(\n a({href: \"https://vanjs.org/\"},\n \"🍦VanJS\",\n ),\n ),\n \"\\n \",\n ),\n \"\\n\",\n)\n",
- ),
- ),
- p(
- "if ",
- Symbol(
- "skipEmptyText",
- ),
- " is ",
- Symbol(
- "false",
- ),
- ".",
- ),
- ),
- li(
- p(
- Symbol(
- "htmlTagPred",
- ),
- ": Type ",
- Symbol(
- "(name: string) => boolean",
- ),
- ". Default ",
- Symbol(
- "s => s.toLowerCase() === s",
- ),
- ". Optional. A predicate function to check whether a specific tag snippet such as ",
- Symbol(
- "",
- ),
- " should be treated as a native HTML element or a custom UI component built with ",
- strong(
- "VanJS",
- ),
- ". By default, it will be treated as a native HTML element if the letters in the ",
- Symbol(
- "name",
- ),
- " are all lowercase.",
- ),
- ),
- ),
- H3(
- "Return Value",
- ),
- p(
- "A plain object with the following fields:",
- ),
- ul(
- li(
- Symbol(
- "code",
- ),
- ": A ",
- Symbol(
- "string[]",
- ),
- " for all lines of the generated ",
- strong(
- "VanJS",
- ),
- " code.",
- ),
- li(
- Symbol(
- "tags",
- ),
- ": A ",
- Symbol(
- "string[]",
- ),
- " for all HTML tag names used in the generated ",
- strong(
- "VanJS",
- ),
- " code, which can be used in the importing line of tag functions such as:",
- pre(
- code({class: "language-js"},
- "const {} = van.tags\n",
- ),
- ),
- ),
- li(
- Symbol(
- "components",
- ),
- ": A ",
- Symbol(
- "string[]",
- ),
- " for all custom ",
- strong(
- "VanJS",
- ),
- " components used in the generated ",
- strong(
- "VanJS",
- ),
- " code, which can be used in the importing line such as:",
- pre(
- code({class: "language-js"},
- "import {} from \"./my-component-lib.js\"\n",
- ),
- ),
- ),
- ),
- H3(
- Symbol(
- "DUMMY",
- ),
- ),
- p(
- em(
- "This is only supported in the converter library, not in the UI.",
- ),
- ),
- p(
- "There are 2 special cases while specifying custom ",
- strong(
- "VanJS",
- ),
- " components in the input HTML string. The first special case is that, sometimes, a custom component needs properties being specified in its first argument, even for empty properties ",
- Symbol(
- "{}",
- ),
- " (e.g.: the ",
- Symbol(
- "Counter",
- ),
- " component defined in the ",
- Link(
- "section",
- "#using-vanjs-components",
- ),
- " above). In this case, you can specify the special ",
- Symbol(
- "DUMMY",
- ),
- " property as a placeholder. For instance:",
- ),
- pre(
- code({class: "language-html"},
- "content\n",
- ),
- ),
- p(
- "will be converted to:",
- ),
- pre(
- code({class: "language-js"},
- "CustomElement({},\n \"content\",\n)\n",
- ),
- ),
- p(
- "whereas",
- ),
- pre(
- code({class: "language-html"},
- "content\n",
- ),
- ),
- p(
- "will be converted to:",
- ),
- pre(
- code({class: "language-js"},
- "CustomElement(\n \"content\",\n)\n",
- ),
- ),
- p(
- "The second special case is that, sometimes, a custom ",
- strong(
- "VanJS",
- ),
- " component needs consecutive string arguments. You can achieve that by inserting ",
- Symbol(
- "",
- ),
- " element between text pieces. For instance:",
- ),
- pre(
- code({class: "language-html"},
- "🍦VanJShttps://vanjs.org/\n",
- ),
- ),
- p(
- "will be converted to:",
- ),
- pre(
- code({class: "language-js"},
- "Link(\n \"🍦VanJS\",\n \"https://vanjs.org/\",\n)\n",
- ),
- ),
- H2(
- Symbol(
- "mdToVanCode",
- ),
- ": Convert MD snippet to VanJS Code",
- ),
- H3(
- "Signature",
- ),
- pre(
- code({class: "language-js"},
- "mdToVanCode(, ) => {code: , tags: , components: }\n",
- ),
- ),
- p(
- "Under the hood, there are 2 steps for converting an MD snippet to ",
- strong(
- "VanJS",
- ),
- " code:",
- ),
- ol(
- li(
- "Convert the MD string into an HTML string with ",
- Link(
- "Marked",
- "https://marked.js.org/",
- ),
- " library.",
- ),
- li(
- "Convert the HTML string into ",
- strong(
- "VanJS",
- ),
- " code with ",
- Symbol(
- "htmlToVanCode",
- ),
- ".",
- ),
- ),
- H3(
- "Example",
- ),
- pre(
- code({class: "language-js"},
- "mdToVanCode(`👋Hello\n* 🗺️World\n* [🍦VanJS](https://vanjs.org/)\n`)\n/*\nThe following result will be returned:\n{\n code: [\n 'p(',\n ' \"👋Hello\",',\n '),',\n 'ul(',\n ' li(',\n ' \"🗺️World\",',\n ' ),',\n ' li(',\n ' a({href: \"https://vanjs.org/\"},',\n ' \"🍦VanJS\",',\n ' ),',\n ' ),',\n '),',\n ],\n tags: [\"a\", \"li\", \"p\", \"ul\"],\n components: [],\n}\n*/\n",
- ),
- ),
- p(
- "Note that, you can insert custom HTML snippets, or even ",
- Link(
- "custom ",
- strong(
- "VanJS",
- ),
- " components",
- "#using-vanjs-components",
- ),
- " in the input MD string.",
- ),
- H3(
- "Options",
- ),
- ul(
- li(
- p(
- Symbol(
- "indent",
- ),
- ": Type ",
- Symbol(
- "number",
- ),
- ". Default ",
- Symbol(
- "2",
- ),
- ". Optional. The indent level of the generated ",
- strong(
- "VanJS code",
- ),
- ".",
- ),
- ),
- li(
- p(
- Symbol(
- "spacing",
- ),
- ": Type ",
- Symbol(
- "boolean",
- ),
- ". Default ",
- Symbol(
- "false",
- ),
- ". Optional. The style of the property object in the generated ",
- strong(
- "VanJS",
- ),
- " code. If ",
- Symbol(
- "true",
- ),
- ", the property object will look like ",
- Symbol(
- "{href: \"https://vanjs.org/\"}",
- ),
- "; Otherwise, the property object will look like ",
- Symbol(
- "{ href: \"https://vanjs.org/\" }",
- ),
- ".",
- ),
- ),
- li(
- p(
- Symbol(
- "htmlTagPred",
- ),
- ": Type ",
- Symbol(
- "(name: string) => boolean",
- ),
- ". Default ",
- Symbol(
- "s => s.toLowerCase() === s",
- ),
- ". Optional. A predicate function to check whether a specific tag snippet such as ",
- Symbol(
- "",
- ),
- " represents a native HTML element or a custom UI component built with ",
- strong(
- "VanJS",
- ),
- ". By default, it will be considered a native HTML element if the letters in the ",
- Symbol(
- "name",
- ),
- " are all lowercase.",
- ),
- ),
- li(
- p(
- Symbol(
- "renderer",
- ),
- ": Optional. ",
- em(
- "Custom renderer is only supported in the converter library, not in the UI.",
- ),
- " A custom object used to override how tokens in the MD string are being rendered. The specification of the ",
- Symbol(
- "renderer",
- ),
- " object can be found in Marked ",
- Link(
- "doc",
- "https://marked.js.org/using_pro#renderer",
- ),
- ". For instance, the ",
- Symbol(
- "renderer",
- ),
- " object:",
- ),
- pre(
- code({class: "language-js"},
- "{\n codespan: s => `${s}`,\n link: (href, _unused_title, text) => `${text}${href}`,\n}\n",
- ),
- ),
- p(
- "will convert ",
- Symbol(
- "`text`",
- ),
- " in MD string into ",
- Symbol(
- "Symbol(\"text\")",
- ),
- " (here ",
- Symbol(
- "Symbol",
- ),
- " is a custom ",
- strong(
- "VanJS",
- ),
- " component) instead of ",
- Symbol(
- "code(\"text\")",
- ),
- ", and will convert ",
- Symbol(
- "[text](link)",
- ),
- " in MD string into ",
- Symbol(
- "Link(\"text\", \"link\")",
- ),
- " instead of ",
- Symbol(
- "a({href: \"link\"}, \"text\")",
- ),
- ".",
- ),
- ),
- ),
- H3(
- "Return Value",
- ),
- p(
- "The same as the ",
- Link(
- "return value",
- "#return-value",
- ),
- " of ",
- Symbol(
- "htmlToVanCode",
- ),
- ".",
- ),
- H2(
- "Showroom",
- ),
- p(
- "The ",
- Link(
- "https://vanjs.org/",
- "https://vanjs.org/",
- ),
- " website is using this library to keep ",
- Symbol(
- "README.md",
- ),
- " files in sync with their corresponding web pages (",
- Link(
- "source code",
- "https://github.com/vanjs-org/vanjs-org.github.io/tree/master/codegen",
- ),
- " of the code generation):",
- ),
- ul(
- li(
- "The ",
- Link(
- "VanUI",
- "https://vanjs.org/vanui",
- ),
- " page is kept in sync with the ",
- Link(
- Symbol(
- "README.md",
- ),
- "https://github.com/vanjs-org/van/tree/main/components#readme",
- ),
- " file in GitHub with the help of this library.",
- ),
- li(
- "This ",
- Link(
- Symbol(
- "README.md",
- ),
- "https://github.com/vanjs-org/converter#readme",
- ),
- " file is kept in sync with this ",
- Link(
- "page",
- "https://vanjs.org/converter-lib",
- ),
- " in ",
- Link(
- "https://vanjs.org/",
- "https://vanjs.org/",
- ),
- " website.",
- ),
- ),
- )
-}
diff --git a/sitegen/convert.ts b/sitegen/convert.ts
deleted file mode 100644
index c814a438..00000000
--- a/sitegen/convert.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import van from "./mini-van.js"
-import common from "./common.ts"
-import { HTMLDocument } from "https://deno.land/x/deno_dom@v0.1.38/deno-dom-wasm.ts"
-
-export default (doc: HTMLDocument) => {
- const {tags: {div, i, p}} = van.vanWithDoc(doc)
- const {H1, Link, VanJS} = common(doc)
-
- return div({id: "content"},
- H1("HTML/MD Snippet to 🍦VanJS Code"),
- p(i("The library version of the converter with the support of custom ", VanJS(), " components is ", Link("here", "https://github.com/vanjs-org/converter"), ".")),
- p({id: "converter"}),
- )
-}
diff --git a/sitegen/copy-to-index-files.ts b/sitegen/copy-to-index-files.ts
deleted file mode 100644
index 927c4d24..00000000
--- a/sitegen/copy-to-index-files.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-// For backward compatibility of URLs that end with "/".
-for await (const f of Deno.readDir("."))
- if (f.isFile && f.name.endsWith(".html") && f.name !== "index.html" && f.name !== "template.html")
- Deno.copyFileSync(f.name, f.name.slice(0, -5) + "/index.html")
diff --git a/sitegen/deno-examples/mini-van-server/package-lock.json b/sitegen/deno-examples/mini-van-server/package-lock.json
deleted file mode 100644
index 3c0175ff..00000000
--- a/sitegen/deno-examples/mini-van-server/package-lock.json
+++ /dev/null
@@ -1,59 +0,0 @@
-{
- "name": "minivan-deno-demo",
- "version": "0.1.0",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "": {
- "name": "minivan-deno-demo",
- "version": "0.1.0",
- "devDependencies": {
- "deno-bin": "^1.36.0"
- }
- },
- "node_modules/adm-zip": {
- "version": "0.5.10",
- "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz",
- "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==",
- "dev": true,
- "engines": {
- "node": ">=6.0"
- }
- },
- "node_modules/deno-bin": {
- "version": "1.36.3",
- "resolved": "https://registry.npmjs.org/deno-bin/-/deno-bin-1.36.3.tgz",
- "integrity": "sha512-ByxEARBe7r4Qar6kbSleLVj3m409nyLBgBvvbQ9RXhKqQnLzRo62+86GwXkbZtTQ0KfBd+6xkh41wZp6kD/5jQ==",
- "dev": true,
- "hasInstallScript": true,
- "dependencies": {
- "adm-zip": "^0.5.4",
- "follow-redirects": "^1.10.0"
- },
- "bin": {
- "deno": "bin/deno.js",
- "deno-bin": "bin/deno.js"
- }
- },
- "node_modules/follow-redirects": {
- "version": "1.15.2",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
- "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
- "dev": true,
- "funding": [
- {
- "type": "individual",
- "url": "https://github.com/sponsors/RubenVerborgh"
- }
- ],
- "engines": {
- "node": ">=4.0"
- },
- "peerDependenciesMeta": {
- "debug": {
- "optional": true
- }
- }
- }
- }
-}
diff --git a/sitegen/deno-examples/mini-van-server/package.json b/sitegen/deno-examples/mini-van-server/package.json
deleted file mode 100644
index 5e63b396..00000000
--- a/sitegen/deno-examples/mini-van-server/package.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name": "mini-van-deno-demo",
- "private": true,
- "version": "0.1.0",
- "type": "module",
- "scripts": {
- "dev": "deno run --allow-net mini-van-server.ts"
- },
- "devDependencies": {
- "deno-bin": "^1.36.0"
- }
-}
diff --git a/sitegen/deno-examples/van-plate-server/package-lock.json b/sitegen/deno-examples/van-plate-server/package-lock.json
deleted file mode 100644
index b5525ef1..00000000
--- a/sitegen/deno-examples/van-plate-server/package-lock.json
+++ /dev/null
@@ -1,59 +0,0 @@
-{
- "name": "van-plate-deno-demo",
- "version": "0.1.0",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "": {
- "name": "van-plate-deno-demo",
- "version": "0.1.0",
- "devDependencies": {
- "deno-bin": "^1.36.0"
- }
- },
- "node_modules/adm-zip": {
- "version": "0.5.10",
- "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz",
- "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==",
- "dev": true,
- "engines": {
- "node": ">=6.0"
- }
- },
- "node_modules/deno-bin": {
- "version": "1.36.3",
- "resolved": "https://registry.npmjs.org/deno-bin/-/deno-bin-1.36.3.tgz",
- "integrity": "sha512-ByxEARBe7r4Qar6kbSleLVj3m409nyLBgBvvbQ9RXhKqQnLzRo62+86GwXkbZtTQ0KfBd+6xkh41wZp6kD/5jQ==",
- "dev": true,
- "hasInstallScript": true,
- "dependencies": {
- "adm-zip": "^0.5.4",
- "follow-redirects": "^1.10.0"
- },
- "bin": {
- "deno": "bin/deno.js",
- "deno-bin": "bin/deno.js"
- }
- },
- "node_modules/follow-redirects": {
- "version": "1.15.2",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
- "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
- "dev": true,
- "funding": [
- {
- "type": "individual",
- "url": "https://github.com/sponsors/RubenVerborgh"
- }
- ],
- "engines": {
- "node": ">=4.0"
- },
- "peerDependenciesMeta": {
- "debug": {
- "optional": true
- }
- }
- }
- }
-}
diff --git a/sitegen/deno-examples/van-plate-server/package.json b/sitegen/deno-examples/van-plate-server/package.json
deleted file mode 100644
index f023fe04..00000000
--- a/sitegen/deno-examples/van-plate-server/package.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name": "van-plate-deno-demo",
- "private": true,
- "version": "0.1.0",
- "type": "module",
- "scripts": {
- "dev": "deno run --allow-net van-plate-server.ts"
- },
- "devDependencies": {
- "deno-bin": "^1.36.0"
- }
-}
diff --git a/sitegen/gen-fiddle-links.ts b/sitegen/gen-fiddle-links.ts
deleted file mode 100644
index 006c9986..00000000
--- a/sitegen/gen-fiddle-links.ts
+++ /dev/null
@@ -1,91 +0,0 @@
-import van from "./mini-van.js"
-import { DOMParser, Element } from "https://deno.land/x/deno_dom@v0.1.38/deno-dom-wasm.ts"
-import { emptyDirSync } from "https://deno.land/std@0.184.0/fs/mod.ts"
-import { join } from "https://deno.land/std@0.184.0/path/mod.ts"
-
-const jsFiddleRoot = "jsfiddle"
-const ghPath = "vanjs-org/vanjs-org.github.io/tree/master/jsfiddle"
-
-const mkdirIfNotExist = (dir: string) => {
- try {
- Deno.mkdirSync(dir, {recursive: true})
- } catch (e) {
- if (!(e instanceof Deno.errors.AlreadyExists)) throw e
- }
-}
-
-const findCode = (dom: Element) => {
- while (!dom.firstElementChild?.matches("code[class^=language-]"))
- dom = dom.previousElementSibling!
- return dom.querySelector("code")!.innerText
-}
-
-const extractCss = (htmlFile: string) => {
- const doc = new DOMParser().parseFromString(Deno.readTextFileSync(htmlFile), "text/html")!
- const cssLines = doc.querySelector("style")!.innerText.split("\n")
- const indent = cssLines[cssLines.length - 1].length + 2
- return cssLines.slice(1, -1).map(l => l.substring(indent) + "\n").join("")
-}
-
-const process = (file: string) => {
- const path = file === "index.html" ? "home" : file.slice(0, -5)
- console.log(`Generating jsfiddle links for ${file}...`)
- const doc = new DOMParser().parseFromString(Deno.readTextFileSync(file), "text/html")!
- const {add, tags} = van.vanWithDoc(doc)
- const {a} = tags
-
- const vanVersion = Deno.readTextFileSync("code/van.version")
- const miniVanVersion = Deno.readTextFileSync("code/mini-van.version")
- const vanXVersion = Deno.readTextFileSync("code/van-x.version")
-
- emptyDirSync(join(jsFiddleRoot, path))
-
- for (const node of doc.querySelectorAll("[id^=jsfiddle-]")) {
- const dom = node
- if (dom.querySelector("a")) continue
- let code = findCode(dom)
- const replaceCode = dom.getAttribute("data-replace-code")
- if (replaceCode) code = replaceCode.replace("$CODE", code)
- const prefix = dom.getAttribute("data-prefix")
- if (prefix) code = prefix + "\n\n" + code
- const suffix = dom.getAttribute("data-suffix")
- if (suffix) code += "\n" + suffix + "\n"
-
- const subdir = join(path ? path : "home", dom.id.substring(9))
- const dir = join(jsFiddleRoot, subdir)
- mkdirIfNotExist(dir)
- const detailFile = dom.getAttribute("data-details") ?? "demo.details"
- const detailStr = Deno.readTextFileSync("jsfiddle/" + detailFile)
- Deno.writeTextFileSync(join(dir, "demo.details"),
- detailStr
- .replace("van-latest.", `van-${detailFile.includes("mini-van") ? miniVanVersion : vanVersion}.`)
- .replace("@latest", "@" + vanXVersion)
- )
- Deno.writeTextFileSync(join(dir, "demo.js"), code)
- const css = dom.getAttribute("data-css")
- if (css) Deno.writeTextFileSync(join(dir, "demo.css"), css)
- const cssFile = dom.getAttribute("data-css-file")
- if (cssFile) {
- if (cssFile.endsWith(".css"))
- Deno.copyFileSync(cssFile, join(dir, "demo.css")); else
- Deno.writeTextFileSync(join(dir, "demo.css"), extractCss(cssFile))
- }
-
- add(dom,
- a({href: "https://jsfiddle.net/gh/get/library/pure/" + join(ghPath, subdir)},
- "Try on jsfiddle",
- ),
- )
- for (const name of dom.getAttributeNames())
- if (name.startsWith("data-") || name === "id") dom.removeAttribute(name)
- }
-
- Deno.writeTextFileSync(file, "\n" + doc.documentElement!.outerHTML
- .replaceAll('async=""', "async")
- .replaceAll('defer=""', "defer")
- .replaceAll('checked="true"', "checked")
- )
-}
-
-for await (const f of Deno.readDir("."))
- if (f.isFile && f.name.endsWith(".html") && f.name !== "template.html") process(f.name)
diff --git a/sitegen/mini-van.d.ts b/sitegen/mini-van.d.ts
deleted file mode 100644
index 3d8f9f3c..00000000
--- a/sitegen/mini-van.d.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-export interface State {
- val: T
- readonly oldVal: T
-}
-
-// Defining readonly view of State for covariance.
-// Basically we want StateView to implement StateView
-export type StateView = Readonly>
-
-export type Primitive = string | number | boolean | bigint
-
-export type PropValue = Primitive | ((e: any) => void) | null
-
-export type Props = Record | (() => PropValue)>
-
-interface HasFirstChild {firstChild?: unknown}
-
-type NodeType =
- Omit
-
-export type ValidChildDomValue =
- Primitive | ElementType | NodeType | TextNodeType | null | undefined
-
-export type BindingFunc =
- | ((dom?: ElementType | TextNodeType) => ValidChildDomValue)
- | ((dom?: ElementType) => ElementType)
-
-export type ChildDom =
- | ValidChildDomValue
- | StateView
- | BindingFunc
- | readonly ChildDom[]
-
-type AddFunc =
- (dom: ElementType, ...children: readonly ChildDom[]) => ElementType
-
-export type TagFunc =
- (first?: Props | ChildDom,
- ...rest: readonly ChildDom[]) => ResultType
-
-type Tags =
- Readonly>>
-
-// Tags type in browser context, which contains the signatures to tag functions that return
-// specialized DOM elements.
-type BrowserTags = Tags & {
- [K in keyof HTMLElementTagNameMap]: TagFunc
-}
-
-export interface VanObj {
- readonly state: (initVal: T) => State
- readonly val: (s: T | StateView) => T
- readonly oldVal: (s: T | StateView) => T
- readonly derive: (f: () => T) => State
- readonly add: AddFunc
- readonly _: (f: () => PropValue) => () => PropValue
- readonly tags: Tags
- readonly tagsNS: (namespaceURI: string) => Tags
-
- // Mini-Van specific API
- html: (first?: Props | ChildDom,
- ...rest: readonly ChildDom[]) => string
-}
-
-export interface Van extends VanObj {
- readonly vanWithDoc: (doc: {
- createElement(s: any): ElementType,
- createTextNode(s: any): TextNodeType,
- }) => VanObj
- readonly tags: BrowserTags
-}
-
-declare const van: Van
-
-export default van
diff --git a/sitegen/mini-van.js b/sitegen/mini-van.js
deleted file mode 100644
index f1397f8a..00000000
--- a/sitegen/mini-van.js
+++ /dev/null
@@ -1,49 +0,0 @@
-///
-
-// 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 }}, objProto = protoOf(stateProto)
-
-let state = initVal => ({__proto__: stateProto, val: initVal})
-
-let val = s => protoOf(s ?? 0) === stateProto ? s.val : s
-
-let plainValue = (k, v) => {
- let protoOfV = protoOf(v ?? 0)
- return protoOfV === stateProto ? v.val :
- protoOfV === funcProto && (!k?.startsWith("on") || v._isBindingFunc) ? 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 tagsNS = ns => new Proxy((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)
- }, {get: (tag, name) => tag.bind(null, name)})
-
- let tags = tagsNS()
-
- return {
- add, _: f => (f._isBindingFunc = 1, f), tags, tagsNS, state,
- val, oldVal: val, derive: f => state(f()),
- html: (...args) => "" + tags.html(...args).outerHTML,
- }
-}
-
-export default {"vanWithDoc": vanWithDoc,
- ...vanWithDoc(typeof window !== "undefined" ? window.document : null)}
diff --git a/sitegen/node-examples/mini-van-server/package-lock.json b/sitegen/node-examples/mini-van-server/package-lock.json
deleted file mode 100644
index 79addb47..00000000
--- a/sitegen/node-examples/mini-van-server/package-lock.json
+++ /dev/null
@@ -1,456 +0,0 @@
-{
- "name": "mini-van-node-demo",
- "version": "0.1.0",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "": {
- "name": "mini-van-node-demo",
- "version": "0.1.0",
- "dependencies": {
- "jsdom": "^22.1.0",
- "mini-van-plate": "^0.5.3"
- }
- },
- "node_modules/@tootallnate/once": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
- "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==",
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/abab": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
- "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA=="
- },
- "node_modules/agent-base": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
- "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
- "dependencies": {
- "debug": "4"
- },
- "engines": {
- "node": ">= 6.0.0"
- }
- },
- "node_modules/asynckit": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
- },
- "node_modules/combined-stream": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
- "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
- "dependencies": {
- "delayed-stream": "~1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/cssstyle": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz",
- "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==",
- "dependencies": {
- "rrweb-cssom": "^0.6.0"
- },
- "engines": {
- "node": ">=14"
- }
- },
- "node_modules/data-urls": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz",
- "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==",
- "dependencies": {
- "abab": "^2.0.6",
- "whatwg-mimetype": "^3.0.0",
- "whatwg-url": "^12.0.0"
- },
- "engines": {
- "node": ">=14"
- }
- },
- "node_modules/debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "dependencies": {
- "ms": "2.1.2"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/decimal.js": {
- "version": "10.4.3",
- "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz",
- "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA=="
- },
- "node_modules/delayed-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/domexception": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz",
- "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==",
- "dependencies": {
- "webidl-conversions": "^7.0.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/entities": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
- "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
- "engines": {
- "node": ">=0.12"
- },
- "funding": {
- "url": "https://github.com/fb55/entities?sponsor=1"
- }
- },
- "node_modules/form-data": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
- "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
- "dependencies": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.8",
- "mime-types": "^2.1.12"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/html-encoding-sniffer": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
- "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==",
- "dependencies": {
- "whatwg-encoding": "^2.0.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/http-proxy-agent": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
- "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==",
- "dependencies": {
- "@tootallnate/once": "2",
- "agent-base": "6",
- "debug": "4"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/https-proxy-agent": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
- "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
- "dependencies": {
- "agent-base": "6",
- "debug": "4"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/iconv-lite": {
- "version": "0.6.3",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
- "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
- "dependencies": {
- "safer-buffer": ">= 2.1.2 < 3.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-potential-custom-element-name": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
- "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ=="
- },
- "node_modules/jsdom": {
- "version": "22.1.0",
- "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz",
- "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==",
- "dependencies": {
- "abab": "^2.0.6",
- "cssstyle": "^3.0.0",
- "data-urls": "^4.0.0",
- "decimal.js": "^10.4.3",
- "domexception": "^4.0.0",
- "form-data": "^4.0.0",
- "html-encoding-sniffer": "^3.0.0",
- "http-proxy-agent": "^5.0.0",
- "https-proxy-agent": "^5.0.1",
- "is-potential-custom-element-name": "^1.0.1",
- "nwsapi": "^2.2.4",
- "parse5": "^7.1.2",
- "rrweb-cssom": "^0.6.0",
- "saxes": "^6.0.0",
- "symbol-tree": "^3.2.4",
- "tough-cookie": "^4.1.2",
- "w3c-xmlserializer": "^4.0.0",
- "webidl-conversions": "^7.0.0",
- "whatwg-encoding": "^2.0.0",
- "whatwg-mimetype": "^3.0.0",
- "whatwg-url": "^12.0.1",
- "ws": "^8.13.0",
- "xml-name-validator": "^4.0.0"
- },
- "engines": {
- "node": ">=16"
- },
- "peerDependencies": {
- "canvas": "^2.5.0"
- },
- "peerDependenciesMeta": {
- "canvas": {
- "optional": true
- }
- }
- },
- "node_modules/mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mime-types": {
- "version": "2.1.35",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "dependencies": {
- "mime-db": "1.52.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mini-van-plate": {
- "version": "0.5.3",
- "resolved": "https://registry.npmjs.org/mini-van-plate/-/mini-van-plate-0.5.3.tgz",
- "integrity": "sha512-l6iAE38kJZoLA7J4RecTU7g0g9hmepKaR2gAHqkSRrl8kRF+un+FQmsKDF/DboSGE1vi85msKGGEpNpCz+17uA=="
- },
- "node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- },
- "node_modules/nwsapi": {
- "version": "2.2.7",
- "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz",
- "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ=="
- },
- "node_modules/parse5": {
- "version": "7.1.2",
- "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
- "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
- "dependencies": {
- "entities": "^4.4.0"
- },
- "funding": {
- "url": "https://github.com/inikulin/parse5?sponsor=1"
- }
- },
- "node_modules/psl": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
- "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag=="
- },
- "node_modules/punycode": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
- "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/querystringify": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
- "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
- },
- "node_modules/requires-port": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
- "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="
- },
- "node_modules/rrweb-cssom": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz",
- "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw=="
- },
- "node_modules/safer-buffer": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
- },
- "node_modules/saxes": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
- "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
- "dependencies": {
- "xmlchars": "^2.2.0"
- },
- "engines": {
- "node": ">=v12.22.7"
- }
- },
- "node_modules/symbol-tree": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
- "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
- },
- "node_modules/tough-cookie": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
- "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
- "dependencies": {
- "psl": "^1.1.33",
- "punycode": "^2.1.1",
- "universalify": "^0.2.0",
- "url-parse": "^1.5.3"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/tr46": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz",
- "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==",
- "dependencies": {
- "punycode": "^2.3.0"
- },
- "engines": {
- "node": ">=14"
- }
- },
- "node_modules/universalify": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
- "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
- "engines": {
- "node": ">= 4.0.0"
- }
- },
- "node_modules/url-parse": {
- "version": "1.5.10",
- "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
- "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
- "dependencies": {
- "querystringify": "^2.1.1",
- "requires-port": "^1.0.0"
- }
- },
- "node_modules/w3c-xmlserializer": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
- "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==",
- "dependencies": {
- "xml-name-validator": "^4.0.0"
- },
- "engines": {
- "node": ">=14"
- }
- },
- "node_modules/webidl-conversions": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
- "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/whatwg-encoding": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
- "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==",
- "dependencies": {
- "iconv-lite": "0.6.3"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/whatwg-mimetype": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz",
- "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==",
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/whatwg-url": {
- "version": "12.0.1",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz",
- "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==",
- "dependencies": {
- "tr46": "^4.1.1",
- "webidl-conversions": "^7.0.0"
- },
- "engines": {
- "node": ">=14"
- }
- },
- "node_modules/ws": {
- "version": "8.13.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
- "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
- "engines": {
- "node": ">=10.0.0"
- },
- "peerDependencies": {
- "bufferutil": "^4.0.1",
- "utf-8-validate": ">=5.0.2"
- },
- "peerDependenciesMeta": {
- "bufferutil": {
- "optional": true
- },
- "utf-8-validate": {
- "optional": true
- }
- }
- },
- "node_modules/xml-name-validator": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
- "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==",
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/xmlchars": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
- "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
- }
- }
-}
diff --git a/sitegen/node-examples/mini-van-server/package.json b/sitegen/node-examples/mini-van-server/package.json
deleted file mode 100644
index 47e5c820..00000000
--- a/sitegen/node-examples/mini-van-server/package.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "name": "mini-van-node-demo",
- "private": true,
- "version": "0.1.0",
- "type": "module",
- "scripts": {
- "dev": "node mini-van-server.mjs"
- },
- "dependencies": {
- "jsdom": "^22.1.0",
- "mini-van-plate": "^0.5.3"
- }
-}
diff --git a/sitegen/node-examples/van-plate-server/package-lock.json b/sitegen/node-examples/van-plate-server/package-lock.json
deleted file mode 100644
index 193acdbd..00000000
--- a/sitegen/node-examples/van-plate-server/package-lock.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "name": "van-plate-node-demo",
- "version": "0.1.0",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "": {
- "name": "van-plate-node-demo",
- "version": "0.1.0",
- "dependencies": {
- "mini-van-plate": "^0.5.3"
- }
- },
- "node_modules/mini-van-plate": {
- "version": "0.5.3",
- "resolved": "https://registry.npmjs.org/mini-van-plate/-/mini-van-plate-0.5.3.tgz",
- "integrity": "sha512-l6iAE38kJZoLA7J4RecTU7g0g9hmepKaR2gAHqkSRrl8kRF+un+FQmsKDF/DboSGE1vi85msKGGEpNpCz+17uA=="
- }
- }
-}
diff --git a/sitegen/node-examples/van-plate-server/package.json b/sitegen/node-examples/van-plate-server/package.json
deleted file mode 100644
index 84b52705..00000000
--- a/sitegen/node-examples/van-plate-server/package.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name": "van-plate-node-demo",
- "private": true,
- "version": "0.1.0",
- "type": "module",
- "scripts": {
- "dev": "node van-plate-server.mjs"
- },
- "dependencies": {
- "mini-van-plate": "^0.5.3"
- }
-}
diff --git a/sitegen/render.ts b/sitegen/render.ts
deleted file mode 100644
index b8f9d303..00000000
--- a/sitegen/render.ts
+++ /dev/null
@@ -1,147 +0,0 @@
-import van from "./mini-van.js"
-import { DOMParser, HTMLDocument, Element } from "https://deno.land/x/deno_dom@v0.1.38/deno-dom-wasm.ts"
-
-import common from "./common.ts"
-import home from "./home.ts"
-import start from "./start.ts"
-import tutorial from "./tutorial.ts"
-import demo from "./demo.ts"
-import convert from "./convert.ts"
-import vanui from "./vanui.ts"
-import minivan from "./minivan.ts"
-import ssr from "./ssr.ts"
-import x from "./x.ts"
-import advanced from "./advanced.ts"
-import media from "./media.ts"
-import about from "./about.ts"
-
-import converterLib from "./convert-lib.ts"
-
-const scripts = {
- prism: "/prism.js",
- chart: "https://www.gstatic.com/charts/loader.js",
- diff: "/code/diff.min.js",
- van: "/code/van-latest.nomodule.min.js",
- vanX: "/code/van-x.nomodule.min.js",
-}
-
-const pageToScripts = {
- "": [scripts.prism, scripts.chart, scripts.van],
- start: [scripts.prism, scripts.van],
- tutorial: [scripts.prism, scripts.van],
- demo: [scripts.prism, scripts.van, scripts.diff, scripts.chart, scripts.vanX],
- convert: [scripts.prism, scripts.van],
- vanui: [scripts.prism],
- minivan: [scripts.prism],
- ssr: [scripts.prism],
- x: [scripts.prism, scripts.van, scripts.vanX],
- advanced: [scripts.prism, scripts.van],
- media: [],
- about: [scripts.prism],
- "converter-lib": [scripts.prism],
-}
-
-type Path = keyof typeof pageToScripts
-
-const templateStr = Deno.readTextFileSync("template.html")
-
-const renderPage = (page: (doc: HTMLDocument) => Element, path: Path, file: string,
- title: string) => {
- const doc = new DOMParser().parseFromString(templateStr, "text/html")!
- const {tags: {a, aside, div, li, link, script, ul}} = van.vanWithDoc(doc)
- const {Link} = common(doc)
-
- const shortTitleToPath = [
- ["Home", ""],
- ["Getting Started", "start"],
- ["Tutorial", "tutorial"],
- ["VanJS by Example", "demo"],
- ["HTML/MD to VanJS", "convert"],
- ["VanUI", "vanui"],
- ["Mini-Van", "minivan"],
- ["SSR & Hydration", "ssr"],
- ["X", "x"],
- ["Advanced Topics", "advanced"],
- ["Media Coverage", "media"],
- ["About", "about"],
- ]
-
- const Nav = ({page}: {page: string}) => div({id: "nav", class: "w3-bar-block"},
- shortTitleToPath.map(([title, path]) => {
- const className = "w3-bar-item w3-button w3-hover-white" + (path === page ? " current" : "")
- return a({href: path.startsWith("https://") ? path : `/${path}`, onclick: "w3_close()", class: className}, title)
- }),
- )
-
- const Toc = (pageDom: Element) => {
- const headers = [...pageDom.querySelectorAll("h2,h3")]
- const List = (headers: readonly Element[], level: number): Element | [] => {
- if (headers.length === 0) return []
- const tagName = "H" + level
- const indexes = headers.flatMap((dom, i) => dom.tagName === tagName ? i : [])
- return ul(indexes.map((index, i) => li(
- Link(headers[index].innerText, "#" + headers[index].id),
- List(headers.slice(index + 1, indexes[i + 1]), level + 1),
- )))
- }
-
- return aside({id: "toc"},
- headers.length > 0 ? [
- List(headers, 2),
- ] : [],
- )
- }
-
- console.log(`Rendering ${file}...`)
-
- let docTitle = title
- if (title === "Home") docTitle = "A 0.9kB No-JSX Framework Based on Vanilla JavaScript"
- if (title === "Mini-Van")
- doc.querySelector("title")!.innerText = "Mini-Van - A Minimalist Template Engine for Client/Server-side Rendering"
- else if (title === "VanUI")
- doc.querySelector("title")!.innerText = "VanUI - A Collection of Grab 'n Go Reusable UI Components for VanJS"
- else if (title === "VanX")
- doc.querySelector("title")!.innerText = "VanX - The 1.0 kB Official VanJS Extension"
- else
- doc.querySelector("title")!.innerText += " - " + docTitle
- let shortTitle = shortTitleToPath?.find(([_, p]) => p === path)?.[0] ?? ""
- if (shortTitle === "Home") shortTitle = "VanJS"
- else if (shortTitle === "Tutorial") shortTitle = "VanJS Tutorial"
- doc.getElementById("title-bar")!.innerText = shortTitle
- doc.getElementById("nav")!.replaceWith(Nav({page: path}))
- const pageDom = page(doc)
- doc.getElementById("content")!.replaceWith(pageDom)
- doc.getElementById("toc")!.replaceWith(Toc(pageDom))
-
- const placeholderDom = doc.getElementById("script-placeholder")!
- for (const src of pageToScripts[path])
- doc.body.insertBefore(script({type: "text/javascript", src, defer: ""}), placeholderDom)
- try {
- const src = `${path === "" ? "home" : path}.js`
- Deno.lstatSync(src)
- doc.body.insertBefore(script({type: "text/javascript", src, defer: ""}), placeholderDom)
- } catch (e) {
- if (!(e instanceof Deno.errors.NotFound)) throw e
- }
- placeholderDom.remove()
-
- for (const href of Object.values(scripts))
- doc.body.appendChild(link({rel: "prefetch", href, as: "script"}))
-
- Deno.writeTextFileSync(file, "\n" + doc.documentElement!.outerHTML)
-}
-
-renderPage(home, "", "index.html", "Home")
-renderPage(start, "start", "start.html", "Getting Started")
-renderPage(tutorial, "tutorial", "tutorial.html", "Tutorial and API Reference")
-renderPage(demo, "demo", "demo.html", "Learning by Example")
-renderPage(convert, "convert", "convert.html", "HTML/MD Snippet to 🍦VanJS Code")
-renderPage(vanui, "vanui", "vanui.html", "VanUI")
-renderPage(minivan, "minivan", "minivan.html", "Mini-Van")
-renderPage(ssr, "ssr", "ssr.html", "Fullstack Rendering (SSR, CSR and Hydration)")
-renderPage(x, "x", "x.html", "VanX")
-renderPage(advanced, "advanced", "advanced.html", "Advanced Topics")
-renderPage(media, "media", "media.html", "Media Coverage")
-renderPage(about, "about", "about.html", "About")
-
-renderPage(converterLib, "converter-lib", "converter-lib.html", "MD and HTML to VanJS Code Converter")
diff --git a/sitegen/van-plate.d.ts b/sitegen/van-plate.d.ts
deleted file mode 100644
index a5443791..00000000
--- a/sitegen/van-plate.d.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-export interface State {
- val: T
- readonly oldVal: T
-}
-
-// Defining readonly view of State for covariance.
-// Basically we want StateView to implement StateView
-export type StateView = Readonly>
-
-export type Primitive = string | number | boolean | bigint
-
-export type PropValue = Primitive | ((e: any) => void) | null
-
-export type Props = Record | (() => PropValue)>
-
-export interface Element { render(): string }
-
-export type ValidChildDomValue = Primitive | Element | null | undefined
-
-export type BindingFunc = (dom: any) => ValidChildDomValue
-
-export type ChildDom = ValidChildDomValue | StateView | BindingFunc | readonly ChildDom[]
-
-export type TagFunc = (first?: Props | ChildDom, ...rest: readonly ChildDom[]) => Element
-
-export interface Van {
- readonly state: (initVal: T) => State
- readonly val: (s: T | StateView) => T
- readonly oldVal: (s: T | StateView) => T
- readonly derive: (f: () => T) => State
- readonly add: (dom: Element, ...children: readonly ChildDom[]) => Element
- readonly _: (f: () => PropValue) => () => PropValue
- readonly tags: Readonly>
- readonly tagsNS: (namespaceURI: string) => Readonly>
- readonly html: (first?: Props | ChildDom, ...rest: readonly ChildDom[]) => string
-}
-
-declare const van: Van
-
-export default van
diff --git a/sitegen/van-plate.js b/sitegen/van-plate.js
deleted file mode 100644
index 35fe5443..00000000
--- a/sitegen/van-plate.js
+++ /dev/null
@@ -1,90 +0,0 @@
-///
-
-const noChild = {
- input: 1,
- meta: 1,
- br: 1,
- link: 1,
- img: 1,
- hr: 1,
- area: 1,
- base: 1,
- col: 1,
- param: 1,
- wbr: 1,
- track: 1,
- source: 1,
- embed: 1,
- command: 1,
- keygen: 1,
-}
-
-const escapeMap = {
- '&': '&',
- '<': '<',
- '>': '>',
-}
-
-const escape = s => s.replace(/[&<>]/g, tag => escapeMap[tag] || tag)
-
-const escapeAttr = v => v.replace(/"/g, """)
-
-const protoOf = Object.getPrototypeOf, funcProto = protoOf(protoOf), objProto = protoOf(noChild)
-
-const stateProto = {get oldVal() { return this.val }}
-
-const state = initVal => ({__proto__: stateProto, val: initVal})
-
-const val = s => protoOf(s ?? 0) === stateProto ? s.val : s
-
-const plainValue = (v, k) => {
- let protoOfV = protoOf(v ?? 0)
- return protoOfV === stateProto ? v.val :
- protoOfV === funcProto && (!k?.startsWith("on") || v._isBindingFunc) ? v() : v
-}
-
-const elementProto = {
- renderToBuf(buf) {
- buf.push(`<${this.name}${this.propsStr}>`)
- if (noChild[this.name]) return
- for (const c of this.children) {
- const plainC = plainValue(c)
- protoOf(plainC) === elementProto ? plainC.renderToBuf(buf) : buf.push(escape(plainC.toString()))
- }
- buf.push(`${this.name}>`)
- },
-
- render() {
- const buf = []
- this.renderToBuf(buf)
- return buf.join("")
- },
-}
-
-const tags = new Proxy((name, ...args) => {
- const [props, ...children] = protoOf(args[0] ?? 0) === objProto ? args : [{}, ...args]
- const propsStr = Object.entries(props).map(([k, v]) => {
- const plainV = plainValue(v, k), lowerK = k.toLowerCase()
- return typeof plainV === "boolean" ? (plainV ? " " + lowerK : "") :
- // Disable setting attribute for function-valued properties (mostly event handlers),
- // as they're usually not useful for SSR (server-side rendering).
- protoOf(plainV) !== funcProto ? ` ${lowerK}=${JSON.stringify(escapeAttr(plainV.toString()))}` : ""
- }).join("")
- return {__proto__: elementProto, name, propsStr,
- children: children.flat(Infinity).filter(c => c != null)}
-}, { get: (tag, name) => tag.bind(null, name) })
-
-const add = (dom, ...children) => {
- dom.children.push(...children.flat(Infinity).filter(c => c != null))
- return dom
-}
-
-export default {
- add, _: f => (f._isBindingFunc = 1, f), tags, tagsNS: () => tags, state,
- val, oldVal: val, derive: f => state(f()),
- html: (...args) => {
- const buf = [""]
- tags.html(...args).renderToBuf(buf)
- return buf.join("")
- }
-}
diff --git a/src/build-client.ts b/src/build-client.ts
new file mode 100644
index 00000000..5fc95137
--- /dev/null
+++ b/src/build-client.ts
@@ -0,0 +1,29 @@
+import type { Van } from 'vanjs-core'
+import { Nav } from './build-nav.js'
+import { render } from './render.macros.js'
+declare global {
+ const van: Van
+}
+
+const state = van.state(location.pathname.slice(1))
+
+function click(path: string) {
+ const d = (render as Awaited>).find(e => e.path === path)
+ const { script } = van.tags
+ if (!d) return
+ return (e: MouseEvent) => {
+ e.preventDefault()
+ document.getElementById('content').outerHTML = d.body
+ document.getElementById('toc').outerHTML = d.toc
+ const placeholderDom = document.getElementById("script-placeholder")!
+ placeholderDom.innerHTML = ""
+ for (const src of d.scripts) {
+ placeholderDom.appendChild(script({ type: "text/javascript", src, defer: true }))
+ }
+ history.pushState({}, d.title, path || '/')
+ state.val = path
+ }
+}
+van.hydrate(document.getElementById('nav'), (el) => {
+ return Nav(van, (render as Awaited>).map(e => [e.name, e.path]), state, click)
+})
diff --git a/src/build-nav.ts b/src/build-nav.ts
new file mode 100644
index 00000000..c10d1a17
--- /dev/null
+++ b/src/build-nav.ts
@@ -0,0 +1,9 @@
+import type { VanObj } from "./type";
+export function Nav(van: VanObj, titlePath: [title: string, path: string][], current: {val: string}, click?: (path: string) => void) {
+ const { div, a } = van.tags
+ return div(
+ {id: "nav", class: "w3-bar-block"},
+ titlePath.map(([title, path]) => {
+ return a({href: path.startsWith("https://") ? path : `/${path}`, ...(click ? { onclick: click(path) } : {}), class: () => "w3-bar-item w3-button w3-hover-white" + (path === current.val ? " current" : "")}, title)
+ }));
+}
\ No newline at end of file
diff --git a/src/build-static.js b/src/build-static.js
new file mode 100644
index 00000000..f513fe0b
--- /dev/null
+++ b/src/build-static.js
@@ -0,0 +1,65 @@
+import { transform, build } from 'esbuild'
+import { mkdirSync } from 'fs'
+import { readFile, writeFile, cp } from 'fs/promises'
+
+const minifyOptions = {
+ css: async (body) => {
+ const { code: esb } = await transform(body, {
+ loader: 'css',
+ minify: true,
+ });
+ return esb
+ },
+}
+
+async function buildJs(filename) {
+ await build({
+ entryPoints: ["./assert/" + filename],
+ bundle: true,
+ minify: true,
+ sourcemap: false,
+ outfile: './dist/' + filename,
+ });
+}
+
+async function buildStatic(filename, type) {
+ const css = await readFile(`./assert/${filename}`, 'utf8')
+ const result = await minifyOptions[type](css);
+ console.log(filename, css.length, '->', result.length, "bytes")
+ return writeFile(`./dist/${filename}`, result)
+}
+
+function copyStatic(filename) {
+ return cp(`./assert/${filename}`, `./dist/${filename}`, {
+ recursive: true,
+ })
+}
+
+mkdirSync("./dist", { recursive: true });
+
+const tree = {
+ static: {
+ css: ['w3.css', 'prism.css', 'vanjs.css'],
+ js: ['prism.js', 'home.js', 'start.js', 'tutorial.js', 'demo.js', 'convert.js', 'x.js', 'advanced.js'],
+ },
+ copy: ['logo.svg', 'vs-code-16x16.png', 'tao.jpeg'],
+ copyFolder: ['code'],
+}
+
+async function main() {
+ try {
+ await Promise.all([
+ ...tree.static?.css?.map(filename => buildStatic(filename, 'css')),
+ ...tree.static?.js?.map(filename => buildJs(filename)),
+ ...tree.copy?.map(filename => copyStatic(filename)),
+ ...tree.copyFolder?.map(filename => copyStatic(filename)),
+ ]).then(() => {
+ console.log("Done!")
+ });
+ } catch (e) {
+ console.error(e)
+ process.exit(1)
+ }
+}
+
+main()
diff --git a/src/build-template.ts b/src/build-template.ts
new file mode 100644
index 00000000..4dfefbfe
--- /dev/null
+++ b/src/build-template.ts
@@ -0,0 +1,107 @@
+import { minify } from '@swc/html'
+import { build } from 'esbuild'
+import { mkdirSync } from 'fs'
+import {readFile, writeFile} from 'fs/promises'
+import van from "mini-van-plate"
+import jsdom from 'jsdom'
+import common from './common'
+import { scripts, shortTitleToPath } from './router'
+import { type Toc, render, Render } from './render.macros'
+import { Nav } from './build-nav'
+
+
+const templatePromise = readFile('./template.html', 'utf8')
+
+const minifyOptions = {
+ html: async (body) => {
+ const { code } = await minify(Buffer.from(body), {
+ collapseWhitespaces: "all",
+ });
+ return code;
+ }
+}
+
+async function renderPage(render: Render) {
+ const dom = new jsdom.JSDOM(await templatePromise)
+ const doc = dom.window.document;
+ const vanObj = van.vanWithDoc(doc)
+ const { aside, script, link } = vanObj.tags
+
+ console.log(`Rendering ${render.name}...`)
+
+ const titleElement = doc.querySelector("title")
+ titleElement.innerHTML = render.title || (titleElement.innerHTML + " - " + render.name)
+ let shortTitle = shortTitleToPath?.find(([_, p]) => p === render.path)?.[0] ?? ""
+ if (shortTitle === "Home") shortTitle = "VanJS"
+ else if (shortTitle === "Tutorial") shortTitle = "VanJS Tutorial"
+ doc.getElementById("title-bar")!.innerHTML = shortTitle
+ doc.getElementById("nav")!.replaceWith(Nav(vanObj, shortTitleToPath.map(e => [e[0], e[1]]), {val: render.path}))
+ doc.getElementById("content")!.outerHTML = render.body
+ doc.getElementById("toc")!.outerHTML = render.toc
+
+ const placeholderDom = doc.getElementById("script-placeholder")!
+ for (const src of render.scripts) {
+ placeholderDom.appendChild(script({type: "text/javascript", src, defer: ""}))
+ }
+
+ for (const href of Object.values(scripts)) {
+ doc.body.appendChild(link({rel: "prefetch", href, as: "script"}))
+ }
+
+ const result = dom.serialize()
+
+ const compressed = await minifyOptions.html(result)
+ // console.log(file, result.length, '->', compressed.length, "bytes")
+ await writeFile(`./dist/${render.path || 'index'}.html`, compressed)
+}
+
+mkdirSync("./dist", { recursive: true });
+
+async function renderClient() {
+ console.log("Building client...")
+ await build({
+ entryPoints: ["./src/build-client.ts"],
+ bundle: true,
+ minify: true,
+ sourcemap: false,
+ outfile: './dist/client.js',
+ plugins: [{
+ name: "esbuild-plugin-macros",
+ setup(ctx) {
+ ctx.onLoad({ filter: /\.macros\.[^\.]+$/ }, async args => {
+ const exports = await import(args.path);
+ const newExports = {}
+ for (const key in exports) {
+ if (exports[key] instanceof Promise) {
+ newExports[key] = await exports[key];
+ } else if (typeof exports[key] === "function") {
+ newExports[key] = await exports[key]();
+ } else {
+ newExports[key] = exports[key];
+ }
+ }
+ return { loader: "json", contents: JSON.stringify(newExports) };
+ });
+ }
+ }]
+ });
+}
+
+async function main() {
+ try {
+ const buildTemplate = await render();
+ await Promise.all([
+ ...Object.values(buildTemplate).map(async (render) => {
+ return await renderPage(render);
+ }),
+ renderClient(),
+ ]).then(() => {
+ console.log("Done!")
+ });
+ } catch (e) {
+ console.error(e)
+ process.exit(1)
+ }
+}
+
+main()
diff --git a/sitegen/common.ts b/src/common.ts
similarity index 68%
rename from sitegen/common.ts
rename to src/common.ts
index 788a4d48..5823684a 100644
--- a/sitegen/common.ts
+++ b/src/common.ts
@@ -1,10 +1,25 @@
-import van, { ChildDom as TypedChildDom } from "./mini-van.js"
-import { HTMLDocument, Element, Text } from "https://deno.land/x/deno_dom@v0.1.38/deno-dom-wasm.ts"
-
-type ChildDom = TypedChildDom
+import type { VanParam, VanObj, VanReturn, JsFiddle } from "./type"
+import fs from "fs"
+import { join } from "path"
+
+const ctx = new Map()
+export function addContext(obj: VanObj, list: {obj: JsFiddle, el: VanReturn}[]) {
+ ctx.set(obj, list)
+ return () => {
+ ctx.delete(obj)
+ }
+}
+function pushToContext(v: VanObj, obj: unknown) {
+ const c = ctx.get(v)
+ if (c) {
+ c.push(obj)
+ } else {
+ throw new Error("No context")
+ }
+}
-export default (doc: HTMLDocument) => {
- const {add, tags: {a, b, blockquote, br, code, h1, h2, h3, h4, hr, i, li, pre, span, table, tbody, td, tr, ul}} = van.vanWithDoc(doc)
+export default (van: VanObj) => {
+ const {add, tags: {a, b, blockquote, br, code, h1, h2, h3, h4, hr, i, li, pre, span, table, tbody, td, tr, ul}} = van
const idMap: Record = {}
@@ -15,10 +30,10 @@ export default (doc: HTMLDocument) => {
return seq ? `${r}-${seq}` : r
}
- const addToHeading = (id: string | undefined, dom: Element, children: readonly ChildDom[]) => {
+ const addToHeading = (id: string | undefined, dom: Element, children: readonly VanParam[]) => {
const link = a({class: "self-link"}, children)
add(dom, link)
- id = genId(link.innerText, id)
+ id = genId(link.innerHTML, id)
dom.id = id
link.setAttribute("href", "#" + id)
return dom
@@ -27,11 +42,11 @@ export default (doc: HTMLDocument) => {
interface HeadingProps { readonly id?: string }
const Link = (...args: readonly unknown[]) => {
- const children = args.slice(0, -1), href = args[args.length - 1]
+ const children = args.slice(0, -1), href = args[args.length - 1]
return a({href, class: "w3-hover-opacity"}, children)
}
- const Symbol = (...children: ChildDom[]) => code({class: "symbol"}, children)
+ const Symbol = (...children: VanParam[]) => code({class: "symbol"}, children)
const CopyButton = () => a({class: "copy", onclick: "copy(this)", onmouseout: "resetTooltip(this)"},
span({class: "tooltip"}, "Copy import line"),
@@ -48,7 +63,7 @@ export default (doc: HTMLDocument) => {
readonly prefix?: string
readonly suffix: string
readonly hasDts?: true
- readonly description: string | readonly ChildDom[]
+ readonly description: string | readonly VanParam[]
}
const DownloadRow = ({version, prefix = "", suffix, hasDts, description}: DownloadRowProps) => tr(
td(pre({style: "margin: 0;"}, Download(`${prefix}van-${version}${suffix}.js`, true)),
@@ -61,9 +76,9 @@ export default (doc: HTMLDocument) => {
interface ApiTableProps {
readonly signature: string
- readonly description: string | readonly ChildDom[]
- readonly parameters: {[key: string]: string | readonly ChildDom[] | Element}
- readonly returns: string | readonly ChildDom[] | Element
+ readonly description: string | readonly VanParam[]
+ readonly parameters: {[key: string]: string | readonly VanParam[] | Element}
+ readonly returns: string | readonly VanParam[] | Element
}
const ApiTable = ({signature, description, parameters, returns}: ApiTableProps) =>
table(
@@ -71,8 +86,9 @@ export default (doc: HTMLDocument) => {
tr(td(b("Signature")), td(InlineJs(signature))),
tr(td(b("Description")), td(description)),
tr(td(b("Parameters")), td(
- ul(Object.entries(parameters).map(([k, v]) => v instanceof Element ?
- v : li(b(Symbol(k)), " - ", v))),
+ // ul(Object.entries(parameters).map(([k, v]) => v instanceof HTMLElement ?
+ // v : li(b(Symbol(k)), " - ", v))),
+ ul(Object.entries(parameters).map(([k, v]) => li(b(Symbol(k)), " - ", v))),
)),
tr(td(b("Returns")), td(returns)),
),
@@ -80,7 +96,7 @@ export default (doc: HTMLDocument) => {
interface FileOptions {trim?: boolean}
const File = (lang: string, file: string, {trim = false}: FileOptions) => {
- let text = Deno.readTextFileSync(file)
+ let text = fs.readFileSync(join('.', 'assert', file), "utf8")
if (trim) {
const lines = text.split("\n")
const tagImportingLine = lines.findIndex(l => l.includes("= van.tags"))
@@ -102,32 +118,32 @@ export default (doc: HTMLDocument) => {
Demo: () => b("Demo:"),
Caveat: () => ["⚠️ ", b("Caveat"), ": "],
- H1: (...children: readonly ChildDom[]) => h1({class: "w3-xxlarge"}, ...children),
+ H1: (...children: readonly VanParam[]) => h1({class: "w3-xxlarge"}, ...children),
- H2: (first: HeadingProps | ChildDom, ...rest: readonly ChildDom[]) => {
+ H2: (first: HeadingProps | VanParam, ...rest: readonly VanParam[]) => {
const [props, children] =
first?.constructor === Object ?
- [first, rest] :
- [{}, [first, ...rest]]
+ [first, rest] :
+ [{}, [first, ...rest]]
return [
addToHeading(props.id, h2({class: "w3-xxlarge w3-text-red"}), children),
hr({style: "width:50px;border:5px solid red", class: "w3-round"}),
]
},
- H3: (first: HeadingProps | ChildDom, ...rest: readonly ChildDom[]) => {
+ H3: (first: HeadingProps | VanParam, ...rest: readonly VanParam[]) => {
const [props, children] =
first?.constructor === Object ?
- [first, rest] :
- [{}, [first, ...rest]]
+ [first, rest] :
+ [{}, [first, ...rest]]
return addToHeading(props.id, h3({class: "w3-large w3-text-red"}), children)
},
- H4: (first: HeadingProps | ChildDom, ...rest: readonly ChildDom[]) => {
+ H4: (first: HeadingProps | VanParam, ...rest: readonly VanParam[]) => {
const [props, children] =
first?.constructor === Object ?
- [first, rest] :
- [{}, [first, ...rest]]
+ [first, rest] :
+ [{}, [first, ...rest]]
return addToHeading(props.id, h4({class: "w3-medium w3-text-red"}), children)
},
@@ -167,9 +183,16 @@ export default (doc: HTMLDocument) => {
User: (id: string) => Link("@" + id, "https://github.com/" + id),
- Quote: ({text, source}: {text: string | readonly ChildDom[], source: string}) =>
+ Quote: ({text, source}: {text: string | readonly VanParam[], source: string}) =>
blockquote(i(text, br(), br(), "-- " + source)),
Url: (url: string) => Link(url, url),
+
+ jsFiddle: (obj: JsFiddle) => {
+ const {p} = van.tags
+ const el = p()
+ pushToContext(van, {obj, el})
+ return el
+ }
}
}
diff --git a/src/gen-fiddle-links.ts b/src/gen-fiddle-links.ts
new file mode 100644
index 00000000..60399cf0
--- /dev/null
+++ b/src/gen-fiddle-links.ts
@@ -0,0 +1,76 @@
+import fs from "fs"
+import fsp from "fs/promises"
+import { join } from "path"
+import type { JsFiddle, VanObj, VanReturn } from "./type"
+
+const jsFiddleRoot = "jsfiddle"
+const ghPath = `vanjs-org/vanjs-org.github.io/tree/master/`
+
+const mkdirIfNotExist = async (dir: string) => {
+ try {
+ fsp.mkdir(dir, {recursive: true})
+ } catch (e) {
+ }
+}
+
+const findCode = (dom: Element) => {
+ // while (!dom.firstElementChild?.matches("code[class^=language-]"))
+ // dom = dom.previousElementSibling!
+ // return dom.querySelector("code")!.innerText
+
+}
+
+const extractCss = (htmlFile: string) => {
+ const doc = new DOMParser().parseFromString(fs.readFileSync(htmlFile, 'utf-8'), "text/html")!
+ const cssLines = doc.querySelector("style")!.innerText.split("\n")
+ const indent = cssLines[cssLines.length - 1].length + 2
+ return cssLines.slice(1, -1).map(l => l.substring(indent) + "\n").join("")
+}
+
+const vanVersion = fs.readFileSync("assert/code/van.version", "utf8")
+const miniVanVersion = fs.readFileSync("assert/code/mini-van.version", "utf8")
+const vanXVersion = fs.readFileSync("assert/code/van-x.version", "utf8")
+
+export const processFiddle = async (path: string, van: VanObj, dom: {obj: JsFiddle, el: VanReturn}[]) => {
+ const {add, tags} = van
+ const {a} = tags
+
+ for (const node of dom) {
+ let code = node.obj.code
+ const replaceCode = node.obj["data-replace-code"]
+ if (replaceCode) code = replaceCode.replace("$CODE", code)
+ const prefix = node.obj["data-prefix"]
+ if (prefix) code = prefix + "\n\n" + code
+ const suffix = node.obj["data-suffix"]
+ if (suffix) code += "\n" + suffix + "\n"
+
+ const subdir = join(path ? path : "home", node.obj.id)
+ const dir = join(jsFiddleRoot, subdir)
+
+ await mkdirIfNotExist(dir)
+
+ const detailFile = node.obj["data-details"] ?? "demo.details"
+ const detailStr = await fsp.readFile("jsfiddle/" + detailFile, 'utf8')
+ await fsp.writeFile(join(dir, "demo.details"), detailStr
+ .replace("van-latest.", `van-${detailFile.includes("mini-van") ? miniVanVersion : vanVersion}.`)
+ .replace("@latest", "@" + vanXVersion)
+ )
+ await fsp.writeFile(join(dir, "demo.js"), code)
+ const css = node.obj["data-css"]
+ if (css) await fsp.writeFile(join(dir, "demo.css"), css)
+ const cssFile = node.obj["data-css-file"]
+ if (cssFile) {
+ if (cssFile.endsWith(".css")) {
+ await fsp.copyFile(cssFile, join(dir, "demo.css"))
+ } else {
+ await fsp.writeFile(join(dir, "demo.css"), extractCss(cssFile))
+ }
+ }
+
+ add(node.el,
+ a({href: "https://jsfiddle.net/gh/get/library/pure/" + join(ghPath, dir)},
+ "Try on jsfiddle",
+ ),
+ )
+ }
+}
diff --git a/src/hydrate.js b/src/hydrate.js
new file mode 100644
index 00000000..6c93d891
--- /dev/null
+++ b/src/hydrate.js
@@ -0,0 +1,3 @@
+export function hydrate(obj) {
+ console.log('hydrate', obj);
+}
\ No newline at end of file
diff --git a/src/render.macros.ts b/src/render.macros.ts
new file mode 100644
index 00000000..58f8a859
--- /dev/null
+++ b/src/render.macros.ts
@@ -0,0 +1,92 @@
+import van from "mini-van-plate"
+import jsdom from 'jsdom'
+import type { JsFiddle, VanObj, VanReturn } from "./type"
+import { shortTitleToPath } from "./router"
+import { processFiddle } from "./gen-fiddle-links"
+import common, { addContext } from "./common"
+
+async function getElement(name: string, render?: (van: VanObj) => (VanReturn | Promise)) {
+ const dom = new jsdom.JSDOM()
+ const vanObj = van.vanWithDoc(dom.window.document)
+ if (render) {
+ const list: {obj: JsFiddle, el: VanReturn}[] = [];
+ const remove = addContext(vanObj, list)
+ const result = await render(vanObj)
+ remove();
+ await processFiddle(name, vanObj, list);
+ return result
+ }
+ const {div} = vanObj.tags
+ return div({id: "content"});
+}
+
+async function renderTemplate(name: string, render?: (van: VanObj) => (VanReturn | Promise)): Promise {
+ const page = await getElement(name, render)
+ return page
+}
+
+export type Toc = {
+ title: string,
+ path: string,
+ level: number,
+ children: Toc[]
+}
+
+export type Render = {
+ title: string,
+ path: string,
+ body: string,
+ scripts: string[],
+ name: string,
+ toc: string
+}
+
+function List(headers: readonly HTMLHeadingElement[], level: number): Toc[] {
+ const tagName = "H" + level
+ const indexes = headers.flatMap((dom, i) => dom.tagName === tagName ? i : [])
+ if (indexes.length === 0) return undefined
+ return indexes.map((index, i) => ({
+ title: headers[index].textContent ?? "",
+ path: "#" + headers[index].id,
+ level,
+ children: List(headers.slice(index + 1, indexes[i + 1]), level + 1),
+ }))
+}
+
+function buildToc(dom: VanReturn): Toc[] {
+ const headers: HTMLHeadingElement[] = [...dom.querySelectorAll("h2,h3")]
+ const r = headers.length > 0 ? List(headers, 2) : []
+ return r
+}
+
+export async function render(): Promise {
+ const dom = new jsdom.JSDOM()
+ const vanObj = van.vanWithDoc(dom.window.document)
+ const { ul, li, aside } = vanObj.tags
+ const { Link } = common(vanObj)
+ const Toc = (toc: Toc[]) => {
+ return toc?.length > 0 ? [ul(
+ toc.map(({title, path, children}) => li(
+ Link(title, path),
+ Toc(children),
+ ))
+ )] : []
+ }
+
+ function returnToc(dom: Toc[]): string {
+ const d = aside({id: "toc"}, Toc(dom))
+ return d.outerHTML
+ }
+
+ return await Promise.all(shortTitleToPath.map(async ([name, path, page, scripts, title]) => {
+ const body = await renderTemplate(path, page)
+ return {
+ title,
+ name,
+ path,
+ scripts,
+ body: body.outerHTML,
+ toc: returnToc(buildToc(body))
+ }
+ }));
+}
diff --git a/src/router.ts b/src/router.ts
new file mode 100644
index 00000000..900d4129
--- /dev/null
+++ b/src/router.ts
@@ -0,0 +1,35 @@
+import about from "./template/about";
+import advanced from "./template/advanced";
+import convert from "./template/convert";
+import demo from "./template/demo";
+import home from "./template/home";
+import media from "./template/media";
+import minivan from "./template/minivan";
+import ssr from "./template/ssr";
+import start from "./template/start";
+import tutorial from "./template/tutorial";
+import vanui from "./template/vanui";
+import x from "./template/x";
+import type { VanObj, VanReturn } from "./type";
+
+export const scripts = {
+ prism: "/prism.js",
+ chart: "https://www.gstatic.com/charts/loader.js",
+ diff: "/code/diff.min.js",
+ vanX: "/code/van-x.nomodule.min.js",
+}
+
+export const shortTitleToPath: [name: string, link: string, render: (van: VanObj) => VanReturn | Promise, scripts: string[], title?: string][] = [
+ ["Home", "", home, [scripts.prism, scripts.chart, `home.js`], 'VanJS - A 0.9kB No-JSX Framework Based on Vanilla JavaScript'],
+ ["Getting Started", "start", start, [scripts.prism, `start.js`]],
+ ["Tutorial", "tutorial", tutorial, [scripts.prism, `tutorial.js`], "VanJS - Tutorial and API Reference"],
+ ["VanJS by Example", "demo", demo, [scripts.prism, scripts.diff, scripts.chart, scripts.vanX, `demo.js`], "VanJS - Learning by Example"],
+ ["HTML/MD to VanJS", "convert", convert, [scripts.prism, `convert.js`], "VanJS - HTML/MD Snippet to 🍦VanJS Code"],
+ ["VanUI", "vanui", vanui, [scripts.prism], "VanUI - A Collection of Grab 'n Go Reusable UI Components for VanJS"],
+ ["Mini-Van", "minivan", minivan, [scripts.prism], "Mini-Van - A Minimalist Template Engine for Client/Server-side Rendering"],
+ ["SSR & Hydration", "ssr", ssr, [scripts.prism], 'VanJS - Fullstack Rendering (SSR, CSR and Hydration)'],
+ ["X", "x", x, [scripts.prism, scripts.vanX, `x.js`], 'VanX - The 1.0 kB Official VanJS Extension'],
+ ["Advanced Topics", "advanced", advanced, [scripts.prism, `advanced.js`]],
+ ["Media Coverage", "media", media, []],
+ ["About", "about", about, [scripts.prism]],
+]
\ No newline at end of file
diff --git a/sitegen/about.ts b/src/template/about.ts
similarity index 98%
rename from sitegen/about.ts
rename to src/template/about.ts
index 798b6ef1..adeeb9d6 100644
--- a/sitegen/about.ts
+++ b/src/template/about.ts
@@ -1,10 +1,9 @@
-import van from "./mini-van.js"
-import common from "./common.ts"
-import { HTMLDocument } from "https://deno.land/x/deno_dom@v0.1.38/deno-dom-wasm.ts"
+import common from "../common"
+import type { VanObj } from "../type"
-export default (doc: HTMLDocument) => {
- const {tags: {b, blockquote, br, div, i, img, li, p, ul}} = van.vanWithDoc(doc)
- const {H1, H2, InlineHtml, InlineJs, Js, Link, MiniVan, Quote, SymLink, Symbol, VanJS, VanX} = common(doc)
+export default async (van: VanObj) => {
+ const {tags: {b, blockquote, br, div, i, img, li, p, ul}} = van
+ const {H1, H2, InlineHtml, InlineJs, Js, Link, MiniVan, Quote, SymLink, Symbol, VanJS, VanX} = common(van)
return div({id: "content"},
H1(VanJS(), ": About"),
diff --git a/sitegen/advanced.ts b/src/template/advanced.ts
similarity index 88%
rename from sitegen/advanced.ts
rename to src/template/advanced.ts
index 55d2726d..0c39c5ec 100644
--- a/sitegen/advanced.ts
+++ b/src/template/advanced.ts
@@ -1,10 +1,18 @@
-import van from "./mini-van.js"
-import common from "./common.ts"
-import { HTMLDocument } from "https://deno.land/x/deno_dom@v0.1.38/deno-dom-wasm.ts"
+import common from "../common"
+import fsp from "fs/promises"
+import type { VanObj } from "../type"
-export default (doc: HTMLDocument) => {
- const {tags: {b, br, div, li, ol, p, span}} = van.vanWithDoc(doc)
- const {Demo, H1, H2, H3, InlineHtml, InlineJs, Js, JsFile, Link, MiniVan, Quote, SymLink, Symbol, VanJS} = common(doc)
+export default async (van: VanObj) => {
+ const {tags: {b, br, div, li, ol, p, span}} = van
+ const {Demo, H1, H2, H3, InlineHtml, InlineJs, Js, Link, MiniVan, Quote, SymLink, Symbol, VanJS, jsFiddle} = common(van)
+
+ const codes = {
+ datalist: await fsp.readFile("src/template/advanced/datalist.code.js", "utf-8"),
+ domValuedState: await fsp.readFile("src/template/advanced/dom-valued-state.code.js", "utf-8"),
+ advancedStateDerivation: await fsp.readFile("src/template/advanced/advanced-state-derivation.code.js", "utf-8"),
+ conditionalBinding: await fsp.readFile("src/template/advanced/conditional-binding.code.js", "utf-8"),
+ conditionalDerive: await fsp.readFile("src/template/advanced/conditional-derive.code.js", "utf-8"),
+ }
return div({id: "content"},
H1(VanJS(), ": Advanced Topics"),
@@ -13,19 +21,20 @@ export default (doc: HTMLDocument) => {
p("In ", SymLink("tag functions", "/tutorial#api-tags"), ", while assigning values from ", Symbol("props"), " parameter to the created HTML element, there are 2 ways of doing it: via ", SymLink("HTML attributes", "https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes"), " (", InlineJs("dom.setAttribute(, )"), "), or via the properties of the created HTML element (", InlineJs("dom[] = "), "). ", VanJS(), " follows a consistent rule that makes sense for most use cases regarding which option to choose: when a settable property exists in a given ", Symbol(""), " for the specific element type, we will assign the value via property, otherwise we will assign the value via attribute."),
p("For instance, ", InlineJs('input({type: "text", value: "Hello 🍦VanJS"})'), " will create an ", Link("input box", "https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/text"), " with ", Symbol("Hello 🍦VanJS"), " as the value of the ", Symbol("value"), " property, while ", InlineJs('div({"data-index": 1})'), " will create the tag: ", InlineHtml(''), "."),
p("Note that, for readonly properties of HTML elements, we will still assign ", Symbol("props"), " values via ", Symbol("setAttribute"), ". For instance, in the code snippet below, the ", Symbol("list"), " of the ", InlineHtml(""), " element is set via ", Symbol("setAttribute"), ":"),
- JsFile("datalist.code.js"),
- p({
- id: "jsfiddle-readonly-prop",
+ Js(codes.datalist),
+ jsFiddle({
+ id: "readonly-prop",
"data-prefix": "const {div, input, option, datalist, label} = van.tags",
"data-suffix": 'van.add(document.body, Datalist())',
+ code: codes.datalist,
}),
p(b("NOTE:"), " for ", MiniVan(), ", since ", Symbol("0.4.0"), ", we consistently assign the ", Symbol("props"), " values via ", Symbol("setAttribute"), " for all property keys in tag functions. This is because for SSR (server-side rendering), which is ", MiniVan(), "'s primary use case, setting the properties of a DOM node won't be visible in the rendered HTML string unless the action of setting the property itself will also set the corresponding HTML attribute (e.g.: setting the ", Symbol("id"), " property of a DOM node will also set the ", Symbol("id"), " attribute). This is helpful as ", InlineJs(`input({type: "text", value: "value"})`), " can be rendered as ", InlineHtml(``), " in ", MiniVan(), " but would be rendered as ", InlineHtml(``), " if we set the property value via DOM property."),
H2("State and State Binding"),
H3({id: "why-not-dom-valued-states"}, "Why can't states have DOM node as values?"),
p("We might be prompted to assign a DOM node to a ", Symbol("State"), " object, especially when the ", Symbol("State"), " object is used as a ", Symbol("State"), "-typed child node. However, this is problematic when the state is bound in multiple places, like the example below:"),
- JsFile("dom-valued-state.code.js"),
+ Js(codes.domValuedState),
p(Demo(), " ", span({id: "demo-dom-valued-state"})),
- p({id: "jsfiddle-dom-valued-state"}),
+ jsFiddle({id: "dom-valued-state", code: codes.domValuedState}),
p("In this example, if we click the \"Turn Bold\" button, the first \"", VanJS(), "\" text will disappear, which is unexpected. This is because the same DOM node ", InlineJs('b("VanJS")'), " is used twice in the DOM tree. For this reason, an error will be thrown in ", Symbol("van-{version}.debug.js"), " whenever we assign a DOM node to a ", Symbol("State"), " object."),
H3("State granularity"),
p("Whenever possible, it's encouraged to define states at a more granular level. That is, it's recommended to define states like this:"),
@@ -44,10 +53,11 @@ export default (doc: HTMLDocument) => {
H3("Advanced state derivation"),
Quote({text: ["道生一,一生二,二生三,三生万物", br(), "(Tao derives one, one derives two, two derive three, and three derive everything)"], source: "老子,道德经"}),
p("A broad set of advanced state derivation (derived states and side effects) can indeed be defined with ", SymLink("van.derive", "/tutorial#api-derive"), ", as illustrated in the following piece of code:"),
- JsFile("advanced-state-derivation.code.js"),
- p({
- id: "jsfiddle-advanced-state-derivation",
+ Js(codes.advancedStateDerivation),
+ jsFiddle({
+ id: "advanced-state-derivation",
"data-prefix": "const {div, input, span} = van.tags",
+ code: codes.advancedStateDerivation,
"data-suffix": `van.add(document.body,
div(
span({class: "label"}, "fullName:"),
@@ -59,25 +69,31 @@ export default (doc: HTMLDocument) => {
div(span({class: "label"}, "delayed:"), () => delayed.val.toFixed(2)),
div(span({class: "label"}, "throttled:"), () => throttled.val.toFixed(2)),
)`,
- "data-css-file": "code/advanced-state-derivation.html",
+ "data-css": `.label {
+ font-weight: bold;
+ display: inline-block;
+ width: 100px;
+ }`
}),
H3("Conditional state binding"),
p("In ", Link(Symbol("State"), "-derived properties", "/tutorial#state-derived-prop"), " and ", Link(Symbol("State"), "-derived child nodes", "/tutorial#state-derived-child"), ", it is guaranteed that the binding function will (only) be triggered when the dependency states change. This is true even for complex binding functions, who have different dependency states under different conditions."),
p("For instance, the binding function ", InlineJs("() => cond.val ? a.val + b.val : c.val + d.val"), " will (only) be triggered by updates of state ", Symbol("a"), ", ", Symbol("b"), " and ", Symbol("cond"), " if ", Symbol("cond.val"), " is true, and will (only) be triggered by updates of state ", Symbol("c"), ", ", Symbol("d"), " and ", Symbol("cond"), " if ", Symbol("cond.val"), " is false. This can be illustrated with the code below:"),
- JsFile("conditional-binding.code.js"),
+ Js(codes.conditionalBinding),
p(Demo()),
p({id: "demo-conditional-binding"}),
- p({
- id: "jsfiddle-conditional-binding",
+ jsFiddle({
+ id: "conditional-binding",
+ code: codes.conditionalBinding,
"data-prefix": "const {div, input, option, select} = van.tags",
"data-suffix": "van.add(document.body, ConditionalBinding())",
}),
p("Conditional state binding works for ", Link("derived states", "/tutorial#derived-state"), " and ", Link("side effects", "/tutorial#side-effect"), " registered via ", Symbol("van.derive"), " as well:"),
- JsFile("conditional-derive.code.js"),
+ Js(codes.conditionalDerive),
p(Demo()),
p({id: "demo-conditional-derive"}),
- p({
- id: "jsfiddle-conditional-derive",
+ jsFiddle({
+ id: "conditional-derive",
+ code: codes.conditionalDerive,
"data-prefix": "const {div, input, option, select} = van.tags",
"data-suffix": "van.add(document.body, ConditionalDerive())",
}),
diff --git a/advanced-state-derivation.code.js b/src/template/advanced/advanced-state-derivation.code.js
similarity index 100%
rename from advanced-state-derivation.code.js
rename to src/template/advanced/advanced-state-derivation.code.js
diff --git a/conditional-binding.code.js b/src/template/advanced/conditional-binding.code.js
similarity index 100%
rename from conditional-binding.code.js
rename to src/template/advanced/conditional-binding.code.js
diff --git a/conditional-derive.code.js b/src/template/advanced/conditional-derive.code.js
similarity index 100%
rename from conditional-derive.code.js
rename to src/template/advanced/conditional-derive.code.js
diff --git a/datalist.code.js b/src/template/advanced/datalist.code.js
similarity index 100%
rename from datalist.code.js
rename to src/template/advanced/datalist.code.js
diff --git a/dom-valued-state.code.js b/src/template/advanced/dom-valued-state.code.js
similarity index 100%
rename from dom-valued-state.code.js
rename to src/template/advanced/dom-valued-state.code.js
diff --git a/src/template/convert.ts b/src/template/convert.ts
new file mode 100644
index 00000000..a6c4a340
--- /dev/null
+++ b/src/template/convert.ts
@@ -0,0 +1,13 @@
+import common from "../common"
+import type { VanObj } from "../type"
+
+export default async (van: VanObj) => {
+ const {tags: {div, i, p}} = van
+ const {H1, Link, VanJS} = common(van)
+
+ return div({id: "content"},
+ H1("HTML/MD Snippet to 🍦VanJS Code"),
+ p(i("The library version of the converter with the support of custom ", VanJS(), " components is ", Link("here", "https://github.com/vanjs-org/converter"), ".")),
+ p({id: "converter"}),
+ )
+}
diff --git a/sitegen/demo.ts b/src/template/demo.ts
similarity index 81%
rename from sitegen/demo.ts
rename to src/template/demo.ts
index 18cfd955..d21e13a2 100644
--- a/sitegen/demo.ts
+++ b/src/template/demo.ts
@@ -1,46 +1,40 @@
-import van from "./mini-van.js"
-import common from "./common.ts"
-import { HTMLDocument } from "https://deno.land/x/deno_dom@v0.1.38/deno-dom-wasm.ts"
+import common from "../common"
+import fsp from "fs/promises"
+import type { VanObj } from "../type"
-export default (doc: HTMLDocument) => {
- const {tags: {a, b, br, button, div, i, iframe, li, p, span, table, tbody, td, th, thead, tr, ul}} = van.vanWithDoc(doc)
- const {Demo, H1, H2, InlineHtml, Js, JsFile, Link, Quote, SymLink, Symbol, TsFile, User, VanJS, VanX} = common(doc)
+export default async (van: VanObj) => {
+ const {tags: {a, b, br, button, div, i, iframe, li, p, span, table, tbody, td, th, thead, tr, ul}} = van
+ const {Demo, H1, H2, InlineHtml, Js, Link, Quote, SymLink, Symbol, Ts, User, VanJS, VanX, jsFiddle} = common(van)
- return div({id: "content"},
- H1(VanJS(), ": Learning by Example"),
- Quote({text: "Simplicity is the ultimate sophistication.", source: "Steve Jobs"}),
- p("Despite being an ", b("ultra-lightweight"), " UI framework, ", VanJS(), " allows you to write incredibly elegant and expressive code for comprehensive application logic. This page is a curated list of cool things you can do with just a few lines of JavaScript code, including several handy utilities built with ", VanJS(), "."),
- p("See also ", Link("Community Examples", "#community-examples"), "."),
- p(button({id: "random-demo"}, span({id: "dice"}, "🎲 "), "Show Me a Random Demo")),
- H2("Hello World!"),
- p("This is the ", Symbol("Hello World"), " program shown in the ", Link("Home", "/"), " page:"),
- Js(`const Hello = () => div(
+ const codes = {
+ helloFun: await fsp.readFile("src/template/demo/hello-fun.code.js", "utf-8"),
+ state: await fsp.readFile("src/template/tutorial/state.code.js", "utf-8"),
+ todoFunctional: await fsp.readFile("src/template/demo/todo-functional.code.js", "utf-8"),
+ todoApp: await fsp.readFile("src/template/demo/todo-app.code.js", "utf-8"),
+ game: await fsp.readFile("src/template/demo/game.code.js", "utf-8"),
+ stars: await fsp.readFile("src/template/demo/stars.code.js", "utf-8"),
+ epochConverter: await fsp.readFile("src/template/demo/epoch-converter.code.js", "utf-8"),
+ keyInspector: await fsp.readFile("src/template/demo/key-inspector.code.js", "utf-8"),
+ diffSimple: await fsp.readFile("src/template/demo/diff-simple.code.js", "utf-8"),
+ diff: await fsp.readFile("src/template/demo/diff.code.js", "utf-8"),
+ packageLockInspector: await fsp.readFile("src/template/demo/package-lock-inspector.code.js", "utf-8"),
+ jsonInspector: await fsp.readFile("src/template/demo/json-inspector.code.js", "utf-8"),
+ tableViewer: await fsp.readFile("src/template/demo/table-viewer.code.js", "utf-8"),
+ calculator: await fsp.readFile("src/template/demo/calculator.code.js", "utf-8"),
+ console: await fsp.readFile("src/template/demo/console.code.js", "utf-8"),
+ todoAppTs: await fsp.readFile("src/template/demo/todoApp.ts", "utf-8"),
+ codeBrowser: await fsp.readFile("src/template/demo/code-browser.js", "utf-8"),
+ autoCompleteStatefulDomFunc: await fsp.readFile("src/template/demo/auto-complete-stateful-dom-func.code.ts", "utf-8"),
+ autoCompleteDerivedProps: await fsp.readFile("src/template/demo/auto-complete-derived-props.code.ts", "utf-8"),
+
+ hello: `const Hello = () => div(
p("👋Hello"),
ul(
li("🗺️World"),
li(a({href: "https://vanjs.org/"}, "🍦VanJS")),
),
-)
-`),
- p(Demo()),
- p({id: "demo-hello"}),
- p({
- id: "jsfiddle-hello",
- "data-prefix": "const {a, div, li, p, ul} = van.tags",
- "data-suffix": "van.add(document.body, Hello())",
- }),
- p("This is the funnier ", Symbol("Hello"), " program shown in ", Link("Getting Started", "/start"), " page:"),
- JsFile("hello-fun.code.js"),
- p(Demo()),
- p({id: "demo-hello-fun"}),
- p({
- id: "jsfiddle-hello-fun",
- "data-prefix": "const {button, div, pre} = van.tags",
- "data-suffix": "van.add(document.body, Hello())",
- }),
- H2("DOM Composition and Manipulation"),
- p("Even without state and state binding, you can build interactive web pages thanks to ", VanJS(), "'s flexible API for DOM composition and manipulation: ", SymLink("tag functions", "/tutorial#api-tags"), " and ", SymLink("van.add", "/tutorial#api-add"), ". Check out the example below:"),
- Js(`const StaticDom = () => {
+)`,
+ static: `const StaticDom = () => {
const dom = div(
div(
button("Dummy Button"),
@@ -56,34 +50,16 @@ export default (doc: HTMLDocument) => {
),
)
return dom
-}
-`),
- p(Demo()),
- p({id: "demo-static"}),
- p({
- id: "jsfiddle-static",
- "data-prefix": "const {a, button, div, h1} = van.tags",
- "data-suffix": "van.add(document.body, StaticDom())",
- }),
- H2("Counter"),
- p("The ", Symbol("Counter App"), " is a good illustration on how to leverage ", Link("States", "/tutorial#states"), " to make your application reactive. This is the program shown in the ", Link("Home", "/"), " page:"),
- Js(`const Counter = () => {
+}`,
+ counterSimple: `const Counter = () => {
const counter = van.state(0)
return span(
"❤️ ", counter, " ",
button({onclick: () => ++counter.val}, "👍"),
button({onclick: () => --counter.val}, "👎"),
)
-}
-`),
- p(Demo(), " ", span({id: "demo-counter-simple"})),
- p({
- id: "jsfiddle-counter-simple",
- "data-prefix": "const {button, span} = van.tags",
- "data-suffix": "van.add(document.body, Counter())",
- }),
- p("This is a slightly advanced version of ", Symbol("Counter App"), ":"),
- Js(`const buttonStyleList = [
+}`,
+ counterAdvanced: `const buttonStyleList = [
["👆", "👇"],
["👍", "👎"],
["🔼", "🔽"],
@@ -112,18 +88,8 @@ const CounterSet = () => {
"➕",
),
)
-}
-`),
- p(Demo()),
- p({id: "demo-counter-advanced"}),
- p({
- id: "jsfiddle-counter-advanced",
- "data-prefix": "const {button, div} = van.tags",
- "data-suffix": "van.add(document.body, CounterSet())",
- }),
- H2("Stopwatch"),
- p("This is a ", Symbol("Stopwatch App"), ", similar to the ", SymLink("Timer App", "/tutorial#state-typed-child"), " shown in the tutorial:"),
- Js(`const Stopwatch = () => {
+}`,
+ stopwatch: `const Stopwatch = () => {
const elapsed = van.state(0)
let id
const start = () => id = id || setInterval(() => elapsed.val += .01, 10)
@@ -133,17 +99,8 @@ const CounterSet = () => {
button({onclick: () => (clearInterval(id), id = 0)}, "Stop"),
button({onclick: () => (clearInterval(id), id = 0, elapsed.val = 0)}, "Reset"),
)
-}
-`),
- p(Demo(), " ", span({id: "demo-stopwatch"})),
- p({
- id: "jsfiddle-stopwatch",
- "data-prefix": "const {button, pre, span} = van.tags",
- "data-suffix": "van.add(document.body, Stopwatch())",
- }),
- H2("Blog"),
- p(VanJS(), " doesn't have an equivalent to React's ", SymLink("", "https://react.dev/reference/react/Fragment"), ". For most of the cases, returning an array of HTML elements from your custom component would serve the similar purpose. Here is the sample code equivalent to the ", Symbol("Blog"), " example in React's official website:"),
- Js(`const Blog = () => [
+}`,
+ blog: `const Blog = () => [
Post({title: "An update", body: "It's been a while since I posted..."}),
Post({title: "My new blog", body: "I am starting a new blog!"}),
]
@@ -154,20 +111,8 @@ const Post = ({title, body}) => [
]
const PostTitle = ({title}) => h1(title)
-const PostBody = ({body}) => article(p(body))
-`
-),
- p({
- id: "jsfiddle-blog",
- "data-prefix": "const {article, h1, p} = van.tags",
- "data-suffix": "van.add(document.body, Blog())",
- }),
- p("The sample code in React is 29 lines. Thus ", VanJS(), "'s equivalent code is ~3 times shorter by eliminating unnecessary boilerplate."),
- p("Note that: The result of the binding function of a ", Link("state-derived child node", "/tutorial#state-derived-child"), " can't be an array of elements. You can wrap the result into a pass-through container (", InlineHtml(""), " for inline elements and ", InlineHtml("
"), " for block elements) if multiple elements need to be returned."),
- H2("List"),
- p("As an ", b("unopinionated"), " framework, ", VanJS(), " supports multiple programming paradigms. You can construct the DOM tree in an imperative way (modifying the DOM tree via ", SymLink("van.add", "/tutorial#api-add"), "), or in a functional/declarative way."),
- p("Below is an example of building a list even numbers in ", Symbol("1..N"), ", using an imperative way:"),
- Js(`const EvenNumbers = ({N}) => {
+const PostBody = ({body}) => article(p(body))`,
+ listImperative: `const EvenNumbers = ({N}) => {
const listDom = ul()
for (let i = 1; i <= N; ++i)
if (i % 2 === 0)
@@ -177,32 +122,16 @@ const PostBody = ({body}) => article(p(body))
p("List of even numbers in 1.." + N + ":"),
listDom,
)
-}`),
- p({
- id: "jsfiddle-list-imperative",
- "data-prefix": "const {div, li, p, ul} = van.tags",
- "data-suffix": "van.add(document.body, EvenNumbers({N: 20}))",
- }),
- p("Alternatively, you can build a list of even numbers in ", Symbol("1..N"), ", using a functional/declarative way:"),
- Js(`const EvenNumbers = ({N}) => div(
+}`,
+ listDeclarative: `const EvenNumbers = ({N}) => div(
p("List of even numbers in 1.." + N + ":"),
ul(
Array.from({length: N}, (_, i) => i + 1)
.filter(i => i % 2 === 0)
.map(i => li(i)),
),
-)
-`),
- p({
- id: "jsfiddle-list-declarative",
- "data-prefix": "const {div, li, p, ul} = van.tags",
- "data-suffix": "van.add(document.body, EvenNumbers({N: 20}))",
- }),
- H2("TODO List"),
- p("Similarly, to build reactive applications, you can build in a procedural way, which updates UI via the integration with native DOM API (it's easy to do with ", VanJS(), " as it doesn't introduce an ad-hoc virtual-DOM layer), or in a functional/reactive way, which delegates UI changes to ", Link("State Binding", "/tutorial#state-binding"), ". You can also choose a hybrid approach between the 2 paradigms, depending on which approach fits well for a specific problem."),
- Quote({text: ["道可道,非常道", br(), "(A rule that can be told by words, is not the rule that should universally apply)"], source: "老子,道德经"}),
- p("Below is an example of building a ", Symbol("TODO List"), " in a completely procedural way:"),
- Js(`const TodoItem = ({text}) => div(
+)`,
+ todoProcedural: `const TodoItem = ({text}) => div(
input({type: "checkbox", onchange: e =>
e.target.closest("div").querySelector("span").style["text-decoration"] =
e.target.checked ? "line-through" : ""
@@ -218,51 +147,157 @@ const TodoList = () => {
button({onclick: () => van.add(dom, TodoItem({text: inputDom.value}))}, "Add"),
)
return dom
-}
-`),
+}`,
+ }
+
+ return div({id: "content"},
+ H1(VanJS(), ": Learning by Example"),
+ Quote({text: "Simplicity is the ultimate sophistication.", source: "Steve Jobs"}),
+ p("Despite being an ", b("ultra-lightweight"), " UI framework, ", VanJS(), " allows you to write incredibly elegant and expressive code for comprehensive application logic. This page is a curated list of cool things you can do with just a few lines of JavaScript code, including several handy utilities built with ", VanJS(), "."),
+ p("See also ", Link("Community Examples", "#community-examples"), "."),
+ p(button({id: "random-demo"}, span({id: "dice"}, "🎲 "), "Show Me a Random Demo")),
+ H2("Hello World!"),
+ p("This is the ", Symbol("Hello World"), " program shown in the ", Link("Home", "/"), " page:"),
+ Js(codes.hello),
+ p(Demo()),
+ p({id: "demo-hello"}),
+ jsFiddle({
+ id: "hello",
+ "data-prefix": "const {a, div, li, p, ul} = van.tags",
+ "data-suffix": "van.add(document.body, Hello())",
+ code: codes.hello,
+ }),
+ p("This is the funnier ", Symbol("Hello"), " program shown in ", Link("Getting Started", "/start"), " page:"),
+ Js(codes.helloFun),
+ p(Demo()),
+ p({id: "demo-hello-fun"}),
+ jsFiddle({
+ id: "hello-fun",
+ "data-prefix": "const {button, div, pre} = van.tags",
+ "data-suffix": "van.add(document.body, Hello())",
+ code: codes.helloFun,
+ }),
+ H2("DOM Composition and Manipulation"),
+ p("Even without state and state binding, you can build interactive web pages thanks to ", VanJS(), "'s flexible API for DOM composition and manipulation: ", SymLink("tag functions", "/tutorial#api-tags"), " and ", SymLink("van.add", "/tutorial#api-add"), ". Check out the example below:"),
+ Js(codes.static),
+ p(Demo()),
+ p({id: "demo-static"}),
+ jsFiddle({
+ id: "static",
+ "data-prefix": "const {a, button, div, h1} = van.tags",
+ "data-suffix": "van.add(document.body, StaticDom())",
+ code: codes.static,
+ }),
+ H2("Counter"),
+ p("The ", Symbol("Counter App"), " is a good illustration on how to leverage ", Link("States", "/tutorial#states"), " to make your application reactive. This is the program shown in the ", Link("Home", "/"), " page:"),
+ Js(codes.counterSimple),
+ p(Demo(), " ", span({id: "demo-counter-simple"})),
+ jsFiddle({
+ id: "counter-simple",
+ "data-prefix": "const {button, span} = van.tags",
+ "data-suffix": "van.add(document.body, Counter())",
+ code: codes.counterSimple,
+ }),
+ p("This is a slightly advanced version of ", Symbol("Counter App"), ":"),
+ Js(codes.counterAdvanced),
+ p(Demo()),
+ p({id: "demo-counter-advanced"}),
+ jsFiddle({
+ id: "counter-advanced",
+ "data-prefix": "const {button, div} = van.tags",
+ "data-suffix": "van.add(document.body, CounterSet())",
+ code: codes.counterAdvanced,
+ }),
+ H2("Stopwatch"),
+ p("This is a ", Symbol("Stopwatch App"), ", similar to the ", SymLink("Timer App", "/tutorial#state-typed-child"), " shown in the tutorial:"),
+ Js(codes.stopwatch),
+ p(Demo(), " ", span({id: "demo-stopwatch"})),
+ jsFiddle({
+ id: "stopwatch",
+ "data-prefix": "const {button, pre, span} = van.tags",
+ "data-suffix": "van.add(document.body, Stopwatch())",
+ code: codes.stopwatch,
+ }),
+ H2("Blog"),
+ p(VanJS(), " doesn't have an equivalent to React's ", SymLink("", "https://react.dev/reference/react/Fragment"), ". For most of the cases, returning an array of HTML elements from your custom component would serve the similar purpose. Here is the sample code equivalent to the ", Symbol("Blog"), " example in React's official website:"),
+ Js(codes.blog),
+ jsFiddle({
+ id: "blog",
+ "data-prefix": "const {article, h1, p} = van.tags",
+ "data-suffix": "van.add(document.body, Blog())",
+ code: codes.blog,
+ }),
+ p("The sample code in React is 29 lines. Thus ", VanJS(), "'s equivalent code is ~3 times shorter by eliminating unnecessary boilerplate."),
+ p("Note that: The result of the binding function of a ", Link("state-derived child node", "/tutorial#state-derived-child"), " can't be an array of elements. You can wrap the result into a pass-through container (", InlineHtml(""), " for inline elements and ", InlineHtml("
"), " for block elements) if multiple elements need to be returned."),
+ H2("List"),
+ p("As an ", b("unopinionated"), " framework, ", VanJS(), " supports multiple programming paradigms. You can construct the DOM tree in an imperative way (modifying the DOM tree via ", SymLink("van.add", "/tutorial#api-add"), "), or in a functional/declarative way."),
+ p("Below is an example of building a list even numbers in ", Symbol("1..N"), ", using an imperative way:"),
+ Js(codes.listImperative),
+ jsFiddle({
+ id: "list-imperative",
+ "data-prefix": "const {div, li, p, ul} = van.tags",
+ "data-suffix": "van.add(document.body, EvenNumbers({N: 20}))",
+ code: codes.listImperative,
+ }),
+ p("Alternatively, you can build a list of even numbers in ", Symbol("1..N"), ", using a functional/declarative way:"),
+ Js(codes.listDeclarative),
+ jsFiddle({
+ id: "list-declarative",
+ "data-prefix": "const {div, li, p, ul} = van.tags",
+ "data-suffix": "van.add(document.body, EvenNumbers({N: 20}))",
+ code: codes.listDeclarative,
+ }),
+ H2("TODO List"),
+ p("Similarly, to build reactive applications, you can build in a procedural way, which updates UI via the integration with native DOM API (it's easy to do with ", VanJS(), " as it doesn't introduce an ad-hoc virtual-DOM layer), or in a functional/reactive way, which delegates UI changes to ", Link("State Binding", "/tutorial#state-binding"), ". You can also choose a hybrid approach between the 2 paradigms, depending on which approach fits well for a specific problem."),
+ Quote({text: ["道可道,非常道", br(), "(A rule that can be told by words, is not the rule that should universally apply)"], source: "老子,道德经"}),
+ p("Below is an example of building a ", Symbol("TODO List"), " in a completely procedural way:"),
+ Js(codes.todoProcedural),
p(Demo()),
p({id: "demo-todo-procedural"}),
- p({
- id: "jsfiddle-todo-procedural",
+ jsFiddle({
+ id: "todo-procedural",
"data-prefix": "const {a, button, div, input, span} = van.tags",
"data-suffix": "van.add(document.body, TodoList())",
"data-css": "a { cursor: pointer; }\n",
+ code: codes.todoProcedural,
}),
p("Alternatively, you can use a functional/reactive way to build ", Symbol("TODO Items"), ":"),
- JsFile("todo-functional.code.js"),
+ Js(codes.todoFunctional),
p(Demo()),
p({id: "demo-todo-functional"}),
- p({
- id: "jsfiddle-todo-functional",
+ jsFiddle({
+ id: "todo-functional",
"data-prefix": "const {a, button, div, input, span, strike} = van.tags",
"data-suffix": "van.add(document.body, TodoList())",
"data-css": "a { cursor: pointer; }\n",
+ code: codes.todoFunctional,
}),
H2({id: "todo-app"}, "A Fully Reactive TODO App"),
p("You can also go fully reactive for the ", Symbol("TODO App"), ". That is, the entire state of the app is captured by a global ", Symbol("appState"), ". With the full reactivity it's easier to persist the ", Symbol("appState"), " into ", SymLink("localStorage", "https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage"), " so that the state is kept across page reloads."),
p("Note that even if the app is fully reactive, we don't need to re-render the whole DOM tree for state updates, thanks to the optimization with ", Link("stateful binding", "/tutorial#stateful-binding"), "."),
p(i("The code was implemented in TypeScript.")),
- TsFile("code/todo-app/src/main.ts", {trim: true}),
+ Ts(codes.todoAppTs),
p(Demo()),
p({id: "demo-todo-fully-reactive"}),
p(Link("Try on CodeSandbox", "https://codesandbox.io/p/sandbox/github/vanjs-org/vanjs-org.github.io/tree/master/code/todo-app?file=/src/main.ts:1,1")),
p("With the help of ", Link(VanX(), "/x"), ", the code above can be simplified to just 10+ lines:"),
- JsFile("todo-app.code.js"),
+ Js(codes.todoApp),
p(Demo()),
p({id: "demo-todo-fully-reactive-vanx"}),
- p({
- id: "jsfiddle-todo-fully-reactive-vanx",
+ jsFiddle({
+ id: "todo-fully-reactive-vanx",
"data-details": "demo-van-x.details",
"data-prefix": "const {a, button, div, input, span, strike} = van.tags",
"data-suffix": "van.add(document.body, TodoList())",
+ code: codes.todoApp,
}),
p("You can refer to ", SymLink("vanX.list", "/x#reactive-list"), " for more details."),
H2({id: "game"}, "Fun Game: Emojis Pops"),
p("We're able to implement a mini game engine with ", VanJS(), " in just a few lines. Here is a fun game implemented under 60 lines with the help of ", VanJS(), " and ", Link(VanX(), "x"), ":"),
- JsFile("game.code.js"),
+ Js(codes.game),
p(Link("🎮 Let's play!", "/code/game"), " (you can share your score here: ", Link("#174", "https://github.com/vanjs-org/van/discussions/174"), ")"),
- p({
- id: "jsfiddle-game",
+ jsFiddle({
+ id: "game",
"data-details": "demo-van-x.details",
"data-prefix": "const {a, b, button, div, h1, li, p, span, ul} = van.tags",
"data-suffix": `van.add(document.body,
@@ -278,74 +313,81 @@ const TodoList = () => {
Game(),
div({class: "footer"}, "Powered by ", a({href: "https://vanjs.org/"}, b("VanJS")), " and ", a({href: "https://vanjs.org/x"}, b("VanX"))),
)`,
+ code: codes.game,
}),
H2({id: "code-browser"}, "SPA w/ Client-Side Routing: Code Browser"),
p("With ", VanJS(), ", you can built a single-page application with client-side routing support, thanks to ", VanJS(), "'s powerful builtin state management and state derivation:"),
- TsFile("code/code-browser/src/main.js", {trim: true}),
+ Js(codes.codeBrowser),
p(Link("Try on CodeSandbox", "https://codesandbox.io/p/sandbox/github/vanjs-org/vanjs-org.github.io/tree/master/code/code-browser?file=/src/main.js:1,1")),
H2("Stargazers"),
p("The following code can show the number of stars for a Github repo, and a list of most recent stargazers:"),
- JsFile("stars.code.js"),
+ Js(codes.stars),
p(Link("Try it out here", "code/stars")),
- p({
- id: "jsfiddle-starts",
+ jsFiddle({
+ id: "starts",
"data-prefix": "const {a, div, li, p, ul} = van.tags",
"data-suffix": '(async () => van.add(document.body, await Stars("vanjs-org/van")))()',
+ code: codes.stars,
}),
H2("Epoch Timestamp Converter"),
p("Below is an application which converts a Unix epoch timestamp into a human-readable datetime string:"),
- JsFile("epoch-converter.code.js"),
+ Js(codes.epochConverter),
p(Demo()),
p({id: "demo-epoch-converter"}),
- p({
- id: "jsfiddle-epoch-converter",
+ jsFiddle({
+ id: "epoch-converter",
"data-prefix": "const {b, button, div, i, input, p} = van.tags",
"data-suffix": "van.add(document.body, Converter())",
+ code: codes.epochConverter,
}),
H2("Keyboard Event Inspector"),
p("Below is an application to inspect all relevant key codes in keyboard ", SymLink("keydown", "https://developer.mozilla.org/en-US/docs/Web/API/Element/keydown_event"), " events:"),
- JsFile("key-inspector.code.js"),
+ Js(codes.keyInspector),
p(Demo()),
p({id: "demo-key-inspector"}),
- p({
- id: "jsfiddle-key-inspector",
+ jsFiddle({
+ id: "key-inspector",
"data-prefix": "const {div, input, span} = van.tags",
"data-suffix": "van.add(document.body, Inspector())",
- "data-css-file": "code/key-inspector.html",
+ "data-css-file": "src/template/demo/key-inspector.css",
+ code: codes.keyInspector,
}),
H2("Diff"),
p("Here is a ", Symbol("Diff App"), " with the integration of ", SymLink("jsdiff", "https://github.com/kpdecker/jsdiff"), ". The app can compare 2 pieces of text (very handy tool to check how your text is revised by ", Symbol("ChatGPT"), " 🙂):"),
- JsFile("diff-simple.code.js"),
+ Js(codes.diffSimple),
p(Demo()),
p({id: "demo-diff-simple"}),
- p({
- id: "jsfiddle-diff-simple",
+ jsFiddle({
+ id: "diff-simple",
"data-details": "demo-diff.details",
"data-prefix": "const {button, div, span, textarea} = van.tags",
"data-suffix": "document.body.appendChild(DiffApp())",
- "data-css-file": "code/diff-simple.html",
+ "data-css-file": "src/template/demo/diff-simple.css",
+ code: codes.diffSimple,
}),
p("Here is a more advanced ", Symbol("Diff App"), " that supports side-by-side and line-by-line comparison:"),
- JsFile("diff.code.js"),
+ Js(codes.diff),
p(Demo()),
p({id: "demo-diff"}),
- p({
- id: "jsfiddle-diff",
+ jsFiddle({
+ id: "diff",
"data-details": "demo-diff.details",
"data-prefix": "const {button, div, input, span, textarea} = van.tags",
"data-suffix": "document.body.appendChild(DiffApp())",
- "data-css-file": "code/diff.html",
+ "data-css-file": "src/template/demo/diff.css",
+ code: codes.diff,
}),
H2("Calculator"),
p("The code below implements a ", Symbol("Calculator App"), " similar to the one that you are using on your smartphones:"),
- JsFile("calculator.code.js"),
+ Js(codes.calculator),
p(Demo()),
iframe({id: "demo-calculator", src: "/code/calculator.html"}),
- p({
- id: "jsfiddle-calculator",
+ jsFiddle({
+ id: "calculator",
"data-prefix": "const {button, div} = van.tags",
"data-suffix": "van.add(document.body, Calculator())",
- "data-css-file": "code/calculator.css",
+ "data-css-file": "src/template/demo/calculator.css",
+ code: codes.calculator,
}),
p("Notably, this ", Symbol("Calculator App"), " is equivalent to the React-based implementation here: ", Link("github.com/ahfarmer/calculator", "https://github.com/ahfarmer/calculator"), ". Here is the size comparison of the total package between the 2 apps:"),
table({style: "text-align: right;"},
@@ -358,42 +400,45 @@ const TodoList = () => {
p("As you can see, not only ", VanJS(), " is ", b("~50 times"), " smaller than React, apps built with ", VanJS(), " also tends to be much slimmer."),
H2({id: "table-viewer"}, "Table-View Example: JSON/CSV Table Viewer"),
p("The following code implements a ", Symbol("Table Viewer"), " for JSON/CSV-based data by leveraging ", Link("functional-style DOM tree building", "/tutorial#fun-dom"), ":"),
- JsFile("table-viewer.code.js"),
+ Js(codes.tableViewer),
p(Demo()),
p({id: "demo-table-viewer"}),
- p({
- id: "jsfiddle-table-viewer",
+ jsFiddle({
+ id: "table-viewer",
"data-prefix": "const {button, input, div, label, p, pre, table, tbody, td, textarea, th, thead, tr} = van.tags",
"data-suffix": `van.add(document.body, TableViewer({
inputText: \`[{"id":1,"name":"John Doe","email":"john.doe@example.com","age":35,"country":"USA"},{"id":2,"name":"Jane Smith","email":"jane.smith@example.com","age":28,"country":"Canada"},{"id":3,"name":"Bob Johnson","email":"bob.johnson@example.com","age":42,"country":"Australia"}]\`,
inputType: "json",
}))`,
- "data-css-file": "code/json-csv-table-viewer.html",
+ "data-css-file": "src/template/demo/json-csv-table-viewer.css",
+ code: codes.tableViewer,
}),
H2({id: "package-lock-inspector"}, Symbol("package-lock.json"), " Inspector"),
p("Below is an example which can extract and display all dependency packages and their versions from ", Symbol("package-lock.json"), " file:"),
- JsFile("package-lock-inspector.code.js"),
+ Js(codes.packageLockInspector),
p(Link("Try it out here", "code/package-lock-inspector")),
- p({
- id: "jsfiddle-package-lock-inspector",
+ jsFiddle({
+ id: "package-lock-inspector",
"data-prefix": "const {a, div, h4, pre, table, tbody, td, textarea, th, thead, tr} = van.tags",
"data-suffix": "van.add(document.body, PackageLockInspector())",
+ code: codes.packageLockInspector,
}),
H2({id: "json-inspector"}, "Tree-View Example: JSON Inspector"),
p("This is another example of leveraging ", Link("functional-style DOM tree building", "/tutorial#fun-dom"), " - to build a tree view for inspecting JSON data:"),
- JsFile("json-inspector.code.js"),
+ Js(codes.jsonInspector),
p(Demo()),
p({id: "demo-json-inspector"}),
- p({
- id: "jsfiddle-json-inspector",
+ jsFiddle({
+ id: "json-inspector",
"data-prefix": "const {a, b, button, div, pre, span, textarea} = van.tags",
"data-suffix": 'van.add(document.body, JsonInspector({initInput: `{"name":"John Doe","age":30,"email":"johndoe@example.com","address":{"street":"123 Main St","city":"Anytown","state":"CA","zip":"12345"},"phone_numbers":[{"type":"home","number":"555-1234"},{"type":"work","number":"555-5678"}]}`}))',
- "data-css-file": "code/json-inspector.html",
+ "data-css-file": "src/template/demo/json-inspector.css",
+ code: codes.jsonInspector,
}),
H2({id: "auto-complete"}, "Textarea with Autocomplete"),
p("The code below implements a ", SymLink("textarea", "https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea"), " with autocomplete support. This implementation leverages ", Link("Stateful DOM binding", "/tutorial#stateful-binding"), " to optimize the performance of DOM tree rendering:"),
p(i("The code was implemented in TypeScript to validate ", VanJS(), "'s TypeScript support.")),
- TsFile("auto-complete-stateful-dom-func.code.ts"),
+ Ts(codes.autoCompleteStatefulDomFunc),
p(Demo()),
p({id: "demo-auto-complete-stateful-binding"}),
p({id: "jsfiddle-auto-complete-stateful-binding"},
@@ -401,7 +446,7 @@ const TodoList = () => {
),
p("Alternatively, we can implement the same app with ", Link("State-derived properties", "/tutorial#state-derived-prop"), ":"),
p(i("The code was implemented in TypeScript to validate ", VanJS(), "'s TypeScript support.")),
- TsFile("auto-complete-derived-props.code.ts"),
+ Ts(codes.autoCompleteDerivedProps),
p(Demo()),
p({id: "demo-auto-complete-derived-props"}),
p({id: "jsfiddle-auto-complete-derived-props"},
@@ -413,11 +458,12 @@ const TodoList = () => {
H2("Jupyter-like JavaScript Console"),
p("Next up, we're going to demonstrate a simplified Jupyter-like JavaScript console implemented in ", b("~100 lines"), " of code with ", VanJS(), ". The JavaScript console supports drawing tables (with the technique similar to ", Link("Table Viewer", "#table-viewer"), "), inspecting objects in a tree view (with the technique similar to ", Link("Json Inspector", "#json-inspector") , ") and plotting (with the integration of ", Link("Google Charts", "https://developers.google.com/chart"), ")."),
p("Here is the implementation:"),
- JsFile("console.code.js"),
+ Js(codes.console),
p(Demo()),
p({id: "demo-js-console"}),
- p({
- id: "jsfiddle-js-console",
+ jsFiddle({
+ id: "js-console",
+ code: codes.console,
"data-prefix": "const {button, code, div, li, p, pre, span, tbody, td, textarea, th, thead, tr, ul} = van.tags",
"data-suffix": `const Snippet = str => str.includes("\\n") ? pre(str) : code(str)
@@ -451,7 +497,7 @@ google.charts.setOnLoadCallback(() =>
).querySelector("textarea").focus()
)`,
"data-details": "demo-js-console.details",
- "data-css-file": "code/console.html",
+ "data-css-file": "src/template/demo/console.css",
}),
p("You can also try out the JavaScript console in ", Link("this standalone page", "/code/console.html"), "."),
H2("An Improved Unix Terminal"),
diff --git a/auto-complete-derived-props.code.ts b/src/template/demo/auto-complete-derived-props.code.ts
similarity index 100%
rename from auto-complete-derived-props.code.ts
rename to src/template/demo/auto-complete-derived-props.code.ts
diff --git a/auto-complete-stateful-dom-func.code.ts b/src/template/demo/auto-complete-stateful-dom-func.code.ts
similarity index 100%
rename from auto-complete-stateful-dom-func.code.ts
rename to src/template/demo/auto-complete-stateful-dom-func.code.ts
diff --git a/calculator.code.js b/src/template/demo/calculator.code.js
similarity index 100%
rename from calculator.code.js
rename to src/template/demo/calculator.code.js
diff --git a/src/template/demo/calculator.css b/src/template/demo/calculator.css
new file mode 100644
index 00000000..1fc151ca
--- /dev/null
+++ b/src/template/demo/calculator.css
@@ -0,0 +1,86 @@
+html { height: 100%; }
+
+body {
+ background-color: black;
+ margin: 0;
+ padding: 0;
+ font-size: 10px;
+ font-family: sans-serif;
+ height: 100%;
+}
+
+@media (min-width: 400px) and (min-height: 400px) {
+ html { font-size: 20px; }
+}
+
+@media (min-width: 500px) and (min-height: 500px) {
+ html { font-size: 30px; }
+}
+
+@media (min-width: 600px) and (min-height: 600px) {
+ html { font-size: 40px; }
+}
+
+@media (min-width: 800px) and (min-height: 800px) {
+ html { font-size: 50px; }
+}
+
+#root {
+ display: flex;
+ flex-direction: column;
+ flex-wrap: wrap;
+ height: 100%;
+}
+
+#display {
+ background-color: #858694;
+ color: white;
+ text-align: right;
+ font-weight: 200;
+ flex: 0 0 auto;
+ width: 100%;
+}
+
+#display > div {
+ font-size: 2.5rem;
+ padding: 0.2rem 0.7rem 0.1rem 0.5rem;
+}
+
+#panel {
+ background-color: #858694;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ flex: 1 0 auto;
+}
+
+#panel > div {
+ width: 100%;
+ margin-bottom: 1px;
+ flex: 1 0 auto;
+ display: -ms-flexbox;
+ display: flex;
+}
+
+.button {
+ display: inline-flex;
+ width: 25%;
+ flex: 1 0 auto;
+}
+
+.button.wide { width: 50%; }
+
+.button button {
+ background-color: #e0e0e0;
+ border: 0;
+ font-size: 1.5rem;
+ margin: 0 1px 0 0;
+ flex: 1 0 auto;
+ padding: 0;
+}
+
+.button:last-child button {
+ margin-right: 0;
+ background-color: #f5923e;
+ color: white;
+}
diff --git a/src/template/demo/code-browser.js b/src/template/demo/code-browser.js
new file mode 100644
index 00000000..012a59bb
--- /dev/null
+++ b/src/template/demo/code-browser.js
@@ -0,0 +1,45 @@
+import van from "vanjs-core"
+
+const {a, button, code, div, li, pre, ul} = van.tags
+
+const Browser = () => {
+ const file = van.state(location.hash.slice(1))
+ window.addEventListener("hashchange", () => file.val = location.hash.slice(1))
+
+ const text = van.derive(() => file.val ? (
+ fetch("https://api.github.com/repos/vanjs-org/van/contents/src/" + file.val)
+ .then(r => r.json())
+ .then(json => text.val = {lang: file.val.split(".").at(-1), str: atob(json.content)})
+ .catch(e => text.val = {str: e.toString()}),
+ {str: "Loading"}
+ ) : {str: "Select a file to browse"})
+
+ const files = van.state([])
+ fetch("https://api.github.com/repos/vanjs-org/van/contents/src")
+ .then(r => r.json())
+ .then(json => files.val = json.map(f => f.name).filter(n => /\.(ts|js)$/.test(n)))
+ .catch(e => text.val = {str: e.toString()})
+
+ const browseFile = e => {
+ e.preventDefault()
+ history.pushState({}, "", new URL(e.target.href).hash)
+ dispatchEvent(new Event("hashchange"))
+ }
+
+ return div({class: "row"},
+ div({class: "left"}, ul(li({class: "folder"}, "src", () => ul(
+ files.val.map(f => li({class: "file"},
+ a({href: "#" + f, class: () => f === file.val ? "selected" : "", onclick: browseFile}, f),
+ )),
+ )))),
+ (dom = div({class: "right"}, pre(code()))) => {
+ const codeDom = dom.querySelector("code")
+ codeDom.textContent = text.val.str
+ codeDom.className = text.val.lang ? "language-" + text.val.lang : ""
+ if (text.val.lang) setTimeout(() => Prism.highlightAll(), 5)
+ return dom
+ },
+ )
+}
+
+van.add(document.body, Browser())
diff --git a/console.code.js b/src/template/demo/console.code.js
similarity index 100%
rename from console.code.js
rename to src/template/demo/console.code.js
diff --git a/src/template/demo/console.css b/src/template/demo/console.css
new file mode 100644
index 00000000..9fb8e0c2
--- /dev/null
+++ b/src/template/demo/console.css
@@ -0,0 +1,41 @@
+body { max-width: 960px; }
+
+ .row {
+ display: flex;
+ flex-flow: wrap;
+ }
+
+ .left {
+ width: 60px;
+ text-align: right;
+ }
+
+ .run {
+ display: none;
+ margin: 9px;
+ }
+
+ @media (max-width: 450px), (pointer:none), (pointer:coarse) {
+ .break { width: 100%; }
+ .run { display: unset; }
+ }
+
+ .right { flex-grow: 1; }
+
+ .right textarea, .right table {
+ margin: 11px;
+ border-width: 1px;
+ box-sizing: border-box;
+ font: 15px monospace;
+ width: 100%;
+ }
+
+ .right pre, .right .chart { margin: 12px; }
+
+ a { cursor: pointer ;}
+
+ table { border-collapse: collapse; }
+
+ th, td { border: 1px solid black; }
+
+ .err { color: red; }
\ No newline at end of file
diff --git a/diff-simple.code.js b/src/template/demo/diff-simple.code.js
similarity index 100%
rename from diff-simple.code.js
rename to src/template/demo/diff-simple.code.js
diff --git a/src/template/demo/diff-simple.css b/src/template/demo/diff-simple.css
new file mode 100644
index 00000000..0e1affb2
--- /dev/null
+++ b/src/template/demo/diff-simple.css
@@ -0,0 +1,18 @@
+.row { display: flex; }
+
+ .column {
+ width: 500px;
+ margin: 2px;
+ }
+
+ .column textarea {
+ box-sizing: border-box;
+ width: 100%;
+ }
+
+ .add { background-color: #B5EFDB; }
+
+ .remove {
+ background-color: #FFC4C1;
+ text-decoration: line-through;
+ }
\ No newline at end of file
diff --git a/diff.code.js b/src/template/demo/diff.code.js
similarity index 100%
rename from diff.code.js
rename to src/template/demo/diff.code.js
diff --git a/src/template/demo/diff.css b/src/template/demo/diff.css
new file mode 100644
index 00000000..a004382f
--- /dev/null
+++ b/src/template/demo/diff.css
@@ -0,0 +1,15 @@
+.row { display: flex; }
+
+ .column {
+ width: 500px;
+ margin: 2px;
+ }
+
+ .column textarea {
+ box-sizing: border-box;
+ width: 100%;
+ }
+
+ .add { background-color: #B5EFDB; }
+ .remove { background-color: #FFC4C1; }
+ .merged .remove { text-decoration: line-through; }
\ No newline at end of file
diff --git a/epoch-converter.code.js b/src/template/demo/epoch-converter.code.js
similarity index 100%
rename from epoch-converter.code.js
rename to src/template/demo/epoch-converter.code.js
diff --git a/game.code.js b/src/template/demo/game.code.js
similarity index 100%
rename from game.code.js
rename to src/template/demo/game.code.js
diff --git a/hello-fun.code.js b/src/template/demo/hello-fun.code.js
similarity index 91%
rename from hello-fun.code.js
rename to src/template/demo/hello-fun.code.js
index 1570917b..fb87a907 100644
--- a/hello-fun.code.js
+++ b/src/template/demo/hello-fun.code.js
@@ -1,3 +1,5 @@
+const {button, div, pre} = van.tags
+
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
const Run = ({sleepMs}) => {
@@ -17,3 +19,5 @@ const Hello = () => {
button({onclick: () => van.add(dom, Run({sleepMs: 2}))}, "Hello 🚀"),
)
}
+
+van.add(document.body, Hello())
\ No newline at end of file
diff --git a/src/template/demo/json-csv-table-viewer.css b/src/template/demo/json-csv-table-viewer.css
new file mode 100644
index 00000000..13788e09
--- /dev/null
+++ b/src/template/demo/json-csv-table-viewer.css
@@ -0,0 +1,10 @@
+.err { color: red; }
+
+ table { border-collapse: collapse; }
+
+ table, th, td { border: 1px solid black; }
+
+ textarea {
+ width: 100%;
+ max-width: 700px;
+ }
\ No newline at end of file
diff --git a/json-inspector.code.js b/src/template/demo/json-inspector.code.js
similarity index 100%
rename from json-inspector.code.js
rename to src/template/demo/json-inspector.code.js
diff --git a/src/template/demo/json-inspector.css b/src/template/demo/json-inspector.css
new file mode 100644
index 00000000..92a2abb4
--- /dev/null
+++ b/src/template/demo/json-inspector.css
@@ -0,0 +1,4 @@
+textarea {
+ width: 100%;
+ max-width: 700px;
+}
\ No newline at end of file
diff --git a/key-inspector.code.js b/src/template/demo/key-inspector.code.js
similarity index 100%
rename from key-inspector.code.js
rename to src/template/demo/key-inspector.code.js
diff --git a/src/template/demo/key-inspector.css b/src/template/demo/key-inspector.css
new file mode 100644
index 00000000..95fad3e5
--- /dev/null
+++ b/src/template/demo/key-inspector.css
@@ -0,0 +1,11 @@
+.label {
+ width: 80px;
+ font-weight: bold;
+}
+
+.value { width: 80px; }
+
+.label, .value {
+ font: monospace;
+ display: inline-block;
+}
\ No newline at end of file
diff --git a/package-lock-inspector.code.js b/src/template/demo/package-lock-inspector.code.js
similarity index 100%
rename from package-lock-inspector.code.js
rename to src/template/demo/package-lock-inspector.code.js
diff --git a/stars.code.js b/src/template/demo/stars.code.js
similarity index 100%
rename from stars.code.js
rename to src/template/demo/stars.code.js
diff --git a/table-viewer.code.js b/src/template/demo/table-viewer.code.js
similarity index 100%
rename from table-viewer.code.js
rename to src/template/demo/table-viewer.code.js
diff --git a/todo-app.code.js b/src/template/demo/todo-app.code.js
similarity index 100%
rename from todo-app.code.js
rename to src/template/demo/todo-app.code.js
diff --git a/todo-functional.code.js b/src/template/demo/todo-functional.code.js
similarity index 100%
rename from todo-functional.code.js
rename to src/template/demo/todo-functional.code.js
diff --git a/src/template/demo/todoApp.ts b/src/template/demo/todoApp.ts
new file mode 100644
index 00000000..725840ad
--- /dev/null
+++ b/src/template/demo/todoApp.ts
@@ -0,0 +1,41 @@
+class TodoItemState {
+ constructor(public text: string, public done: State, public deleted: State) {}
+ serialize() { return {text: this.text, done: this.done.val} }
+}
+
+const TodoItem = ({text, done, deleted}: TodoItemState) => () => deleted.val ? null : div(
+ input({type: "checkbox", checked: done, onclick: e => done.val = e.target.checked}),
+ () => (done.val ? strike : span)(text),
+ a({onclick: () => deleted.val = true}, "❌"),
+)
+
+class TodoListState {
+ private constructor(public todos: TodoItemState[]) {}
+
+ save() {
+ localStorage.setItem("appState", JSON.stringify(
+ (this.todos = this.todos.filter(t => !t.deleted.val)).map(t => t.serialize())))
+ }
+
+ static readonly load = () => new TodoListState(
+ JSON.parse(localStorage.getItem("appState") ?? "[]")
+ .map((t: any) => new TodoItemState(t.text, van.state(t.done), van.state(false)))
+ )
+
+ add(text: string) {
+ this.todos.push(new TodoItemState(text, van.state(false), van.state(false)))
+ return new TodoListState(this.todos)
+ }
+}
+
+const TodoList = () => {
+ const appState = van.state(TodoListState.load())
+ van.derive(() => appState.val.save())
+ const inputDom = input({type: "text"})
+ return div(
+ inputDom, button({onclick: () => appState.val = appState.val.add(inputDom.value)}, "Add"),
+ (dom?: Element) => dom ?
+ van.add(dom, TodoItem(appState.val.todos.at(-1)!)) :
+ div(appState.val.todos.map(TodoItem)),
+ )
+}
diff --git a/sitegen/home.ts b/src/template/home.ts
similarity index 96%
rename from sitegen/home.ts
rename to src/template/home.ts
index 708d53db..69106509 100644
--- a/sitegen/home.ts
+++ b/src/template/home.ts
@@ -1,10 +1,9 @@
-import van from "./mini-van.js"
-import common from "./common.ts"
-import { HTMLDocument } from "https://deno.land/x/deno_dom@v0.1.38/deno-dom-wasm.ts"
+import common from "../common"
+import type { VanObj } from "../type"
-export default (doc: HTMLDocument) => {
- const {tags: {a, b, blockquote, div, g, i, img, input, label, li, p, path, span, svg, title, ul}} = van.vanWithDoc(doc)
- const {BI, Demo, H1, H2, H3, Js, Link, MiniVan, Quote, Symbol, VanJS, VanUI, VanX} = common(doc)
+export default (van: VanObj) => {
+ const {a, b, blockquote, div, g, i, img, input, label, li, p, path, span, svg, title, ul} = van.tags
+ const {BI, Demo, H1, H2, H3, Js, Link, MiniVan, Quote, Symbol, VanJS, VanUI, VanX, jsFiddle} = common(van)
const mailIcon = svg({viewBox: "0 0 16 16", version: "1.1", width: 16, height: 16, "aria-hidden": true},
path({"d": "M1.75 2h12.5c.966 0 1.75.784 1.75 1.75v8.5A1.75 1.75 0 0 1 14.25 14H1.75A1.75 1.75 0 0 1 0 12.25v-8.5C0 2.784.784 2 1.75 2ZM1.5 12.251c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25V5.809L8.38 9.397a.75.75 0 0 1-.76 0L1.5 5.809v6.442Zm13-8.181v-.32a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25v.32L8 7.88Z"}),
@@ -54,10 +53,7 @@ van.add(document.body, Hello())
// Alternatively, you can write:
// document.body.appendChild(Hello())
`),
- p({
- id: "jsfiddle-hello",
- "data-prefix": "const {a, div, li, p, ul} = van.tags",
- }),
+ jsFiddle({id: "hello", 'data-prefix': "const {a, div, li, p, ul} = van.tags"}),
p("You can convert any HTML or MD snippet into ", VanJS(), " code with our online ", Link("converter", "/convert"), "."),
p({id: "code-counter"}, VanJS(), " helps you manage states and UI bindings as well, with a more natural API:"),
Js(`const Counter = () => {
@@ -72,10 +68,7 @@ van.add(document.body, Hello())
van.add(document.body, Counter())
`),
p(Demo(), " ", span({id: "demo-counter"})),
- p({
- id: "jsfiddle-counter",
- "data-prefix": "const {button, span} = van.tags",
- }),
+ jsFiddle({id: "counter", 'data-prefix': "const {button, span} = van.tags"}),
H2("Why VanJS?"),
H3("Reactive Programming without React/JSX"),
p("Declarative DOM tree composition, reusable components, reactive state binding - ", VanJS(), " offers every good aspect that React does, but without the need of React, JSX, transpiling, virtual DOM, or any hidden logic. Everything is built with simple JavaScript functions and DOM."),
diff --git a/sitegen/media.ts b/src/template/media.ts
similarity index 96%
rename from sitegen/media.ts
rename to src/template/media.ts
index ff3e2e07..9143d46e 100644
--- a/sitegen/media.ts
+++ b/src/template/media.ts
@@ -1,10 +1,9 @@
-import van from "./mini-van.js"
-import common from "./common.ts"
-import { HTMLDocument } from "https://deno.land/x/deno_dom@v0.1.38/deno-dom-wasm.ts"
+import common from "../common"
+import type { VanObj } from "../type"
-export default (doc: HTMLDocument) => {
- const {tags: {div, i, iframe, li, ol, p}} = van.vanWithDoc(doc)
- const {H1, H2, Url, VanJS} = common(doc)
+export default async (van: VanObj) => {
+ const {tags: {div, i, iframe, li, ol, p}} = van
+ const {H1, H2, Url, VanJS} = common(van)
const Video = (src: string) => p({class: "video-wrapper"},
iframe({src, frameborder: "0", allow: "accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture", allowfullscreen: ""}),
diff --git a/sitegen/minivan.ts b/src/template/minivan.ts
similarity index 90%
rename from sitegen/minivan.ts
rename to src/template/minivan.ts
index acd78fde..74436dfc 100644
--- a/sitegen/minivan.ts
+++ b/src/template/minivan.ts
@@ -1,12 +1,33 @@
-import van from "./mini-van.js"
-import common from "./common.ts"
-import { HTMLDocument } from "https://deno.land/x/deno_dom@v0.1.38/deno-dom-wasm.ts"
+import common from "../common"
+import fsp from "fs/promises"
+import type { VanObj } from "../type"
-export default (doc: HTMLDocument) => {
- const {tags: {a, div, i, p, path, svg, table, tbody, th, thead, tr}} = van.vanWithDoc(doc)
- const {BI, Download, DownloadRow, H1, H2, H3, Html, Js, JsFile, Link, MiniVan, Shell, Symbol, SymLink, TsFile, VanJS} = common(doc)
+export default async (van: VanObj) => {
+ const {tags: {a, div, i, p, path, svg, table, tbody, th, thead, tr}} = van
+ const {BI, Download, DownloadRow, H1, H2, H3, Html, Js, Link, MiniVan, Shell, Symbol, SymLink, Ts, VanJS, jsFiddle} = common(van)
- const version = Deno.readTextFileSync("code/mini-van.version")
+ const version = await fsp.readFile('assert/code/mini-van.version', 'utf8')
+
+ const codes = {
+ vanPlateServer: await fsp.readFile('src/template/minivan/van-plate-server.mjs', 'utf8'),
+ miniVanServer: await fsp.readFile('src/template/minivan/mini-van-server.mjs', 'utf8'),
+ denoVanPlateServer: await fsp.readFile('src/template/minivan/van-plate-server.ts', 'utf8'),
+ denoMiniVanServer: await fsp.readFile('src/template/minivan/mini-van-server.ts', 'utf8'),
+ }
+
+ const codeHello = `// Reusable components can be just pure vanilla JavaScript functions.
+// Here we capitalize the first letter to follow React conventions.
+const Hello = () => div(
+ p("👋Hello"),
+ ul(
+ li("🗺️World"),
+ li(a({href: "https://vanjs.org/"}, "🍦VanJS")),
+ ),
+)
+
+van.add(document.body, Hello())
+// Alternatively, you can write:
+// document.body.appendChild(Hello())`
const DownloadTable = ({version}: {version: string}) => table({class: "download-table"},
thead(tr(th("Files"), th("Description"))),
@@ -41,24 +62,12 @@ export default (doc: HTMLDocument) => {
return div({id: "content"},
H1(MiniVan(), ": A Minimalist Template Engine for Client/Server-side Rendering without JSX"),
p(MiniVan(), " is an ", BI("ultra-lightweight"), " template engine for DOM composition and manipulation. With only 0.7kB in the minified bundle size (0.5kB gzipped), ", MiniVan(), " enables you to build comprehensive UI with elegant and expressive vanilla JavaScript code:"),
- Js(`// Reusable components can be just pure vanilla JavaScript functions.
-// Here we capitalize the first letter to follow React conventions.
-const Hello = () => div(
- p("👋Hello"),
- ul(
- li("🗺️World"),
- li(a({href: "https://vanjs.org/"}, "🍦VanJS")),
- ),
-)
-
-van.add(document.body, Hello())
-// Alternatively, you can write:
-// document.body.appendChild(Hello())
-`),
- p({
- id: "jsfiddle-hello",
+ Js(codeHello),
+ jsFiddle({
+ id: "hello",
"data-prefix": "const {a, div, li, p, ul} = van.tags",
"data-details": "demo-mini-van.details",
+ code: codeHello,
}),
p("You can convert any HTML snippet into ", MiniVan(), " code with our online ", Link("converter", "/convert"), "."),
p(MiniVan(), " is the slimmed-down version of ", Link(VanJS(), "/"), ", which aims to provide an ", BI("ultra-lightweight"), ", ", BI("zero-dependency"), ", and ", BI("unopinionated"), " Reactive UI framework based on pure vanilla JavaScript and DOM. Compared to ", VanJS(), ", ", MiniVan(), " further reduces the gzipped minified bundle size to 0.5kB and (", i("more importantly"), ") can be used on the server-side as a ", Link("template engine", "https://en.wikipedia.org/wiki/Web_template_system"), "."),
@@ -69,7 +78,7 @@ van.add(document.body, Hello())
Shell("npm install mini-van-plate"),
H3({id: "npm-van-plate"}, Symbol("van-plate"), " mode"),
p("In ", Symbol("van-plate"), " mode, HTML content is generated purely through text templating. It can be easily integrated with your HTTP server to render dynamic web content. See the sample code below:"),
- JsFile("sitegen/node-examples/van-plate-server/van-plate-server.mjs"),
+ Js(codes.vanPlateServer),
p("Preview via ", Link("CodeSandbox", "https://codesandbox.io/p/sandbox/github/vanjs-org/vanjs-org.github.io/tree/master/sitegen/node-examples/van-plate-server?file=%2Fvan-plate-server.mjs%3A1%2C1"), "."),
p("As illustrated in the example, ", Symbol("render"), " method can be called on the object returned from the ", SymLink("tag function", "/tutorial#api-tags"), " to generate a ", Symbol("string"), " that can be used for serving."),
p(Symbol("van.html"), " is a helper function defined in ", Symbol("van-plate.js"), " that is equivalent to:",
@@ -81,7 +90,7 @@ van.add(document.body, Hello())
p("First, install ", Symbol("jsdom"), ":"),
Shell("npm install jsdom"),
p("Sample code:"),
- JsFile("sitegen/node-examples/mini-van-server/mini-van-server.mjs"),
+ Js(codes.miniVanServer),
p("Preview via ", Link("CodeSandbox", "https://codesandbox.io/p/sandbox/github/vanjs-org/vanjs-org.github.io/tree/master/sitegen/node-examples/mini-van-server?file=%2Fmini-van-server.mjs%3A1%2C1"), "."),
p("Similar to ", Symbol("van-plate"), " mode, we have a helper function ", Symbol("html"), " defined in ", Symbol("mini-van.js"), " which is equivalent to:"),
Js(`(...args) => "" + tags.html(...args).outerHTML`),
@@ -90,12 +99,12 @@ van.add(document.body, Hello())
H3({id: "deno-van-plate"}, Symbol("van-plate"), " mode"),
p("Sample code:"),
div({style: "font-size: 0.9em;"}, i("Requires Deno ", Symbol("1.35"), " or later.")),
- TsFile("sitegen/deno-examples/van-plate-server/van-plate-server.ts"),
+ Ts(codes.denoVanPlateServer),
p("Preview via ", Link("CodeSandbox", "https://codesandbox.io/p/sandbox/github/vanjs-org/vanjs-org.github.io/tree/master/sitegen/deno-examples/van-plate-server?file=%2Fvan-plate-server.ts%3A1%2C1"), "."),
H3({id: "deno-mini-van"}, Symbol("mini-van"), " mode"),
p("Likewise, ", MiniVan(), " mode needs a 3rd-party DOM library to provide the ", Symbol("Document"), " object. We will show an example with the integration of ", SymLink("deno-dom", "https://deno.com/manual@v1.28.1/advanced/jsx_dom/deno_dom"), "."),
div({style: "font-size: 0.9em;"}, i("Requires Deno ", Symbol("1.35"), " or later.")),
- TsFile("sitegen/deno-examples/mini-van-server/mini-van-server.ts"),
+ Ts(codes.denoMiniVanServer),
p("Preview via ", Link("CodeSandbox", "https://codesandbox.io/p/sandbox/github/vanjs-org/vanjs-org.github.io/tree/master/sitegen/deno-examples/mini-van-server?file=%2Fmini-van-server.ts%3A1%2C1"), "."),
H2("Client-Side: Getting Started"),
p("To get started on the client side, add the line below to your script:"),
diff --git a/sitegen/node-examples/mini-van-server/mini-van-server.mjs b/src/template/minivan/mini-van-server.mjs
similarity index 100%
rename from sitegen/node-examples/mini-van-server/mini-van-server.mjs
rename to src/template/minivan/mini-van-server.mjs
diff --git a/sitegen/deno-examples/mini-van-server/mini-van-server.ts b/src/template/minivan/mini-van-server.ts
similarity index 100%
rename from sitegen/deno-examples/mini-van-server/mini-van-server.ts
rename to src/template/minivan/mini-van-server.ts
diff --git a/sitegen/node-examples/van-plate-server/van-plate-server.mjs b/src/template/minivan/van-plate-server.mjs
similarity index 100%
rename from sitegen/node-examples/van-plate-server/van-plate-server.mjs
rename to src/template/minivan/van-plate-server.mjs
diff --git a/sitegen/deno-examples/van-plate-server/van-plate-server.ts b/src/template/minivan/van-plate-server.ts
similarity index 100%
rename from sitegen/deno-examples/van-plate-server/van-plate-server.ts
rename to src/template/minivan/van-plate-server.ts
diff --git a/sitegen/ssr.ts b/src/template/ssr.ts
similarity index 95%
rename from sitegen/ssr.ts
rename to src/template/ssr.ts
index 98ca942b..02a1513d 100644
--- a/sitegen/ssr.ts
+++ b/src/template/ssr.ts
@@ -1,19 +1,24 @@
-import van, { ChildDom as TypedChildDom } from "./mini-van.js"
-import common from "./common.ts"
-import { HTMLDocument, Element, Text } from "https://deno.land/x/deno_dom@v0.1.38/deno-dom-wasm.ts"
+import common from "../common"
+import fsp from "fs/promises"
+import type { VanObj, VanParam } from "../type"
-type ChildDom = TypedChildDom
-
-export default (doc: HTMLDocument) => {
- const {tags: {b, div, i, img, li, ol, p, ul}} = van.vanWithDoc(doc)
- const {ApiTable, Code, H1, H2, H3, InlineHtml, InlineJs, InlineTs, Json, Link, MiniVan, Shell, SymLink, Symbol, Ts, TsFile, VanJS} = common(doc)
+export default async (van: VanObj) => {
+ const {tags: {b, div, i, img, li, ol, p, ul}} = van
+ const {ApiTable, Code, H1, H2, H3, InlineHtml, InlineJs, InlineTs, Json, Link, MiniVan, Shell, SymLink, Symbol, Ts, VanJS} = common(van)
const codeUrlBase = "https://github.com/vanjs-org/vanjs-org.github.io/tree/master/hydration-example"
const previewUrl = "https://codesandbox.io/p/sandbox/github/vanjs-org/vanjs-org.github.io/tree/master/hydration-example?file=%2Fsrc%2Fserver.ts%3A1%2C1"
- const Folder = (name: string, ...rest: ChildDom[]) =>
+ const codes = {
+ hello: await fsp.readFile("assert/code/hydration-example/src/components/hello.ts", "utf-8"),
+ counter: await fsp.readFile("assert/code/hydration-example/src/components/counter.ts", "utf-8"),
+ server: await fsp.readFile("assert/code/hydration-example/src/server.ts", "utf-8"),
+ optimizedCounter: await fsp.readFile("assert/code/hydration-example/src/components/optimized-counter.ts", "utf-8"),
+ }
+
+ const Folder = (name: string, ...rest: VanParam[]) =>
li({class: "folder"}, Symbol(name), ...rest)
- const File = (name: string, path: string, ...rest: ChildDom[]) =>
+ const File = (name: string, path: string, ...rest: VanParam[]) =>
li({class: "file"}, SymLink(name, codeUrlBase + path + name), ...rest)
const NpmLink = (name: string) => Link(name, "https://www.npmjs.com/package/" + name)
@@ -68,7 +73,7 @@ export default (doc: HTMLDocument) => {
p("Now, let's build some shared UI components that can run on both server-side and client-side."),
H3("Static Component"),
p("First, let's take a look at a static (non-reactive) component - ", Symbol("Hello"), ":"),
- TsFile("hydration-example/src/components/hello.ts"),
+ Ts(codes.hello),
p("Compared to the ", SymLink("Hello", "/demo#hello-world"), " component in the \"VanJS by Example\" page, there are following notable differences:"),
ul(
li("The shared ", Symbol("Hello"), " component takes a ", Symbol("van"), " object as its input property. This is crucial to make ", Symbol("Hello"), " component cross-platform. Callers are responsible for providing the ", Symbol("van"), " object based on what's available in their specific environment so that the component can be agnostic to the execution environment. On the server-side, the ", Symbol("van"), " object from ", MiniVan(), " will be used (we can choose the ", Symbol("van"), " object from ", Symbol("van-plate"), " mode or from ", Symbol("mini-van"), " mode), whereas on the client-side, the ", Symbol("van"), " object from ", VanJS(), " will be used."),
@@ -78,7 +83,7 @@ export default (doc: HTMLDocument) => {
p(b("Limitations: "), i("The typechecking for tag functions and ", Symbol("van.add"), " is quite limited. This is because it's hard to unify the type system across the common types between server-side and client-side.")),
H3("Reactive Component"),
p("Next, let's take a look at a reactive component - ", Symbol("Counter"), ":"),
- TsFile("hydration-example/src/components/counter.ts"),
+ Ts(codes.counter),
p("Notable differences from the ", SymLink("Counter", "/demo#counter"), " component in the \"VanJS by Example\" page:"),
ul(
li("Similar to the ", Symbol("Hello"), " component, it takes a ", Symbol("van"), " object as its input property to make the component environment-agnostic."),
@@ -90,7 +95,7 @@ export default (doc: HTMLDocument) => {
),
H2("Server-Side Script: HTML Template"),
p("Now, let's build the server-side script that enables SSR:"),
- TsFile("hydration-example/src/server.ts"),
+ Ts(codes.server),
p("The script implements a basic HTTP server with the built-in ", Symbol("node:http"), " module (no web framework needed). You will probably first notice this line:"),
Ts('if (req.url?.endsWith(".js")) return serveFile(req, res, finalhandler(req, res))'),
p("This is to tell the HTTP server to serve the file statically if any ", Symbol(".js"), " file is requested."),
@@ -131,7 +136,7 @@ styleSelectDom.oninput = e => buttonStyle.val = (e.target).va
`),
p("Since ", Symbol("buttonStyle"), " is passed into the ", Symbol("Counter"), " component where its ", Symbol("val"), " property is referenced, the hydrated ", Symbol("Counter"), " component will be reactive to the change of ", Symbol("buttonStyle"), " state."),
p("Note that, this is an illustrative example to show how to make the entire hydrated component reactive to external states. In practice, the implementation of ", Symbol("Counter"), " component can be optimized to only make the ", InlineHtml("