diff --git a/.gitignore b/.gitignore index e229009..c034237 100644 --- a/.gitignore +++ b/.gitignore @@ -56,4 +56,3 @@ typings/ # distribution folder lib/ - diff --git a/.nvmrc b/.nvmrc index 8351c19..209e3ef 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -14 +20 diff --git a/Makefile b/Makefile index 9658d2d..c38f1b2 100644 --- a/Makefile +++ b/Makefile @@ -4,29 +4,41 @@ help: ## Show this help message @echo 'Targets:' @egrep '^(.+)\:\ ##\ (.+)' ${MAKEFILE_LIST} | column -t -c 2 -s ':#' -bundle : ## Create production bundle +bundle: ## Create production bundle rm -rf dist || exit $? ; \ node ./esbuild.js || exit $? ; \ -format : ## Enforces a consistent style by parsing your code and re-printing it - pnpx prettier --write "./src/**/*.js" "./tests/**/*.js" "./examples/**/*.js" ;\ +cp: ## Copy files + cp -r index.js examples/h.js || exit $? ; \ + cp -r document.js examples/document.js || exit $? ; \ + +format: ## Enforces a consistent style by parsing your code and re-printing it + npx prettier --write "./**/*.js" "./tests/**/*.js" "./examples/**/*.js" ;\ jsx: ## Build JSX example - node -r esm examples/jsx/esbuild-jsx.js || exit $? ;\ + node examples/jsx/esbuild-jsx.js || exit $? ;\ + +ssr: ## Run a static page + node examples/ssr/counter.js || exit $? ;\ -static : ## Run a static page - node -r esm examples/ssr/counter.js || exit $? ;\ +server: ## Run a dev server + make cp || exit $? ; \ + make ssr || exit $? ; \ + make jsx || exit $? ; \ + pnpm --package=github:gc-victor/d-d dlx d-d || exit $? ; \ -server : ## Run a dev static server - pnpm --package=github:gc-victor/d-d dlx d-d +test: ## Execute tests + make test-browser || exit $? ; \ + make test-ssr || exit $? ; \ -test : ## Execute tests - TEST=true node -r esm tests/index.js || exit $? ;\ +test-browser: ## Execute tests + node tests/tests-browser.js || exit $? ;\ -test-ssr : ## Execute SSR tests - node -r esm tests/index.js || exit $? ;\ +test-ssr: ## Execute SSR tests + node tests/tests-ssr.js || exit $? ;\ -test-watch : test ## Execute tests on watch mode +test-watch: ## Execute tests on watch mode + make test-ssr || exit $? ; \ npx chokidar-cli "**/*.js" -c "make test" || exit $? ;\ # catch anything and do nothing diff --git a/README.md b/README.md index ed3f16a..42d942a 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,13 @@ # H -H is a micro-library (800 B) to create DOM Trees using HyperScript template. +H is a micro-library (~1 KB) to create DOM Trees using HyperScript template. ## Key Features -- Micro-library 800 B -- No compilation needed - Real DOM Tree - SSR out of the box -- Only one dependency for SSR +- JSX compatible +- Zero dependencies - Small API, not much to learn ## Let's Play @@ -136,16 +135,12 @@ const App = () => ; ``` -### Dependencies +### SSR -The only dependency is [html-element](https://github.com/1N50MN14/html-element) for Server Side Rendering or Static Site Generation. - -```console -npm install html-element -``` +To use it in SSR, you only need to import the `h/document` module into the main file. ```javascript -import 'html-element/global-shim'; +import 'h/document'; // Your code ... ``` diff --git a/dist/cjs/index.js b/dist/cjs/index.js index 5ac08c6..be72b32 100644 --- a/dist/cjs/index.js +++ b/dist/cjs/index.js @@ -1 +1 @@ -var i=Object.defineProperty;var m=o=>i(o,"__esModule",{value:!0});var k=(o,t)=>{m(o);for(var s in t)i(o,s,{get:t[s],enumerable:!0})};k(exports,{default:()=>y});var a=typeof global!="undefined"&&{}.toString.call(global)==="[object global]";a||(window.process={env:{TEST:!1}});var d=process.env.TEST?!1:a;var p=/^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|fill|flood|font|glyph(?!R)|horiz|marker(?!H|W|U)|overline|paint|stop|strikethrough|stroke|text(?!L)|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[A-Z]/,f={};function v(o,t={},s=[]){let n=o==="svg"&&!d?document.createElementNS("http://www.w3.org/2000/svg","svg"):document.createElement(o),c=Object.keys(t||{}),h=c.length,_=s.length;for(let r=0;r<_;r++){let e=s[r];e&&o==="svg"?n.innerHTML=`${n.innerHTML}${e.outerHTML}`:e&&n.appendChild(typeof e=="string"?document.createTextNode(e):e)}for(let r=0;r{let t=o.target,s=o.type;for(;t!==null;){let n=t.__handler__&&t.__handler__[s];if(n){n(o);return}t=t.parentNode}},y=v; +var d=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var w=Object.getOwnPropertyNames;var y=Object.prototype.hasOwnProperty;var p=(n,t)=>{for(var r in t)d(n,r,{get:t[r],enumerable:!0})},L=(n,t,r,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of w(t))!y.call(n,o)&&o!==r&&d(n,o,{get:()=>t[o],enumerable:!(s=m(t,o))||s.enumerable});return n};var k=n=>L(d({},"__esModule",{value:!0}),n);var $={};p($,{Fragment:()=>H,default:()=>M,h:()=>u});module.exports=k($);var v=/^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|fill|flood|font|glyph(?!R)|horiz|marker(?!H|W|U)|overline|paint|stop|strikethrough|stroke|text(?!L)|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[A-Z]/,f={};function T(n,t={},r=[]){let s=typeof window<"u",o=n==="svg"?document.createElementNS("http://www.w3.org/2000/svg","svg"):document.createElement(n),i=Object.keys(t||{}),a=i.length,h=r.length;for(let c=0;c{let t=n.target,r=n.type;for(;t!==null;){let s=t.__handler__&&t.__handler__[r];if(s){s(n);return}t=t.parentNode}};function H(n){return n.children}function u(n,t,...r){let s=typeof window<"u";if(typeof n=="function")return n({...t||{},children:s?r:[r.map(i=>Object.prototype.toString.call(i)==="[object Array]"?i.map(a=>typeof a=="string"?a:a.outerHTML).join(""):i.outerHTML||i).join("")]});let o=T(n,t||{},[].concat.apply([],r));return s?o:o.outerHTML}var M=u; diff --git a/dist/esm/index.js b/dist/esm/index.js index 740011d..ccdb236 100644 --- a/dist/esm/index.js +++ b/dist/esm/index.js @@ -1 +1 @@ -var i=typeof global!="undefined"&&{}.toString.call(global)==="[object global]";i||(window.process={env:{TEST:!1}});var a=process.env.TEST?!1:i;var u=/^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|fill|flood|font|glyph(?!R)|horiz|marker(?!H|W|U)|overline|paint|stop|strikethrough|stroke|text(?!L)|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[A-Z]/,d={};function m(o,n={},l=[]){let t=o==="svg"&&!a?document.createElementNS("http://www.w3.org/2000/svg","svg"):document.createElement(o),c=Object.keys(n||{}),f=c.length,h=l.length;for(let s=0;s{let n=o.target,l=o.type;for(;n!==null;){let t=n.__handler__&&n.__handler__[l];if(t){t(o);return}n=n.parentNode}},w=m;export{w as default}; +var _=/^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|fill|flood|font|glyph(?!R)|horiz|marker(?!H|W|U)|overline|paint|stop|strikethrough|stroke|text(?!L)|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[A-Z]/,d={};function g(n,t={},r=[]){let s=typeof window<"u",o=n==="svg"?document.createElementNS("http://www.w3.org/2000/svg","svg"):document.createElement(n),i=Object.keys(t||{}),a=i.length,f=r.length;for(let c=0;c{let t=n.target,r=n.type;for(;t!==null;){let s=t.__handler__&&t.__handler__[r];if(s){s(n);return}t=t.parentNode}};function y(n){return n.children}function w(n,t,...r){let s=typeof window<"u";if(typeof n=="function")return n({...t||{},children:s?r:[r.map(i=>Object.prototype.toString.call(i)==="[object Array]"?i.map(a=>typeof a=="string"?a:a.outerHTML).join(""):i.outerHTML||i).join("")]});let o=g(n,t||{},[].concat.apply([],r));return s?o:o.outerHTML}var p=w;export{y as Fragment,p as default,w as h}; diff --git a/dist/iife/index.js b/dist/iife/index.js index 76d92c4..8b5d2b9 100644 --- a/dist/iife/index.js +++ b/dist/iife/index.js @@ -1 +1 @@ -(()=>{var m=Object.defineProperty;var c=(o,t)=>m(o,"name",{value:t,configurable:!0});var a=typeof global!="undefined"&&{}.toString.call(global)==="[object global]";a||(window.process={env:{TEST:!1}});var d=process.env.TEST?!1:a;var k=/^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|fill|flood|font|glyph(?!R)|horiz|marker(?!H|W|U)|overline|paint|stop|strikethrough|stroke|text(?!L)|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[A-Z]/,f={};function p(o,t={},l=[]){let n=o==="svg"&&!d?document.createElementNS("http://www.w3.org/2000/svg","svg"):document.createElement(o),i=Object.keys(t||{}),h=i.length,_=l.length;for(let s=0;s<_;s++){let e=l[s];e&&o==="svg"?n.innerHTML=`${n.innerHTML}${e.outerHTML}`:e&&n.appendChild(typeof e=="string"?document.createTextNode(e):e)}for(let s=0;s{let t=o.target,l=o.type;for(;t!==null;){let n=t.__handler__&&t.__handler__[l];if(n){n(o);return}t=t.parentNode}},"handler"),L=p;})(); +(()=>{var g=Object.defineProperty;var d=(n,t)=>g(n,"name",{value:t,configurable:!0});var m=/^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|fill|flood|font|glyph(?!R)|horiz|marker(?!H|W|U)|overline|paint|stop|strikethrough|stroke|text(?!L)|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[A-Z]/,f={};function w(n,t={},r=[]){let s=typeof window<"u",o=n==="svg"?document.createElementNS("http://www.w3.org/2000/svg","svg"):document.createElement(n),i=Object.keys(t||{}),a=i.length,u=r.length;for(let c=0;c{let t=n.target,r=n.type;for(;t!==null;){let s=t.__handler__&&t.__handler__[r];if(s){s(n);return}t=t.parentNode}},"handler");function k(n){return n.children}d(k,"Fragment");function p(n,t,...r){let s=typeof window<"u";if(typeof n=="function")return n({...t||{},children:s?r:[r.map(i=>Object.prototype.toString.call(i)==="[object Array]"?i.map(a=>typeof a=="string"?a:a.outerHTML).join(""):i.outerHTML||i).join("")]});let o=w(n,t||{},[].concat.apply([],r));return s?o:o.outerHTML}d(p,"h");var v=p;})(); diff --git a/document.js b/document.js new file mode 100644 index 0000000..e6af4d7 --- /dev/null +++ b/document.js @@ -0,0 +1,53 @@ +globalThis.document = { + createElement(tagName) { + return { + tagName, + attributes: {}, + children: [], + setAttribute(name, value) { + this.attributes[name] = value; + }, + appendChild(child) { + this.children.push(child); + }, + get innerHTML() { + return this.children.reduce((prev, child) => prev + child.textContent, ''); + }, + get outerHTML() { + const shelfClosingTags = [ + 'area', + 'base', + 'br', + 'col', + 'embed', + 'hr', + 'img', + 'input', + 'link', + 'meta', + 'param', + 'source', + 'track', + 'wbr', + ]; + const attributes = Object.keys(this.attributes) + .map((name) => `${name}="${this.attributes[name]}"`) + .join(' '); + + const tagName2 = this.tagName?.toLowerCase() || 'div'; + const innerHTML = this.innerHTML; + return `<${tagName2}${attributes ? ` ${attributes}` : ''}>${innerHTML}${ + shelfClosingTags.includes(tagName2) ? '' : `` + }`; + }, + }; + }, + createTextNode(text) { + return { + textContent: text, + }; + }, + createElementNS(namespaceURI, tagName) { + return this.createElement(tagName); + }, +}; diff --git a/esbuild.js b/esbuild.js index 25ee73e..c9849fe 100644 --- a/esbuild.js +++ b/esbuild.js @@ -1,5 +1,5 @@ -const { buildSync } = require('esbuild'); -const gzipSize = require('gzip-size'); +import * as esbuild from 'esbuild'; +import { gzipSizeFromFileSync } from 'gzip-size'; [ { @@ -17,10 +17,10 @@ const gzipSize = require('gzip-size'); outdir: 'dist/iife', }, ].forEach((config) => { - const result = buildSync({ + const result = esbuild.buildSync({ bundle: true, entryNames: '[dir]/[name]', - entryPoints: ['src/index.js'], + entryPoints: ['index.js'], metafile: true, minify: true, ...config, @@ -31,12 +31,13 @@ const gzipSize = require('gzip-size'); Object.keys(result.metafile.outputs).forEach((key) => { total = total + result.metafile.outputs[key].bytes; - totalGzip = totalGzip + gzipSize.fileSync(key); + totalGzip = totalGzip + gzipSizeFromFileSync(key); + console.log( key, formatBytes(result.metafile.outputs[key].bytes), '- gzip:', - formatBytes(gzipSize.fileSync(key)) + formatBytes(gzipSizeFromFileSync(key)) ); }); diff --git a/examples/.gitignore b/examples/.gitignore new file mode 100644 index 0000000..988fd61 --- /dev/null +++ b/examples/.gitignore @@ -0,0 +1,4 @@ +h.js +document.js +index-jsx.js +index.html diff --git a/examples/app-jsx.js b/examples/app-jsx.js deleted file mode 100644 index fb315e0..0000000 --- a/examples/app-jsx.js +++ /dev/null @@ -1,108 +0,0 @@ -(() => { - // src/is-nodejs.js - var is = typeof global !== "undefined" && {}.toString.call(global) === "[object global]"; - if (!is) { - window.process = { env: { TEST: false } }; - } - var isNodejs = process.env.TEST ? false : is; - - // src/index.js - var CAMEL_PROPS = /^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|fill|flood|font|glyph(?!R)|horiz|marker(?!H|W|U)|overline|paint|stop|strikethrough|stroke|text(?!L)|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[A-Z]/; - var events = {}; - function h2(type, props = {}, children = []) { - const element = type === "svg" && !isNodejs ? document.createElementNS("http://www.w3.org/2000/svg", "svg") : document.createElement(type); - const keys = Object.keys(props || {}); - const length = keys.length; - const childrenLength = children.length; - for (let i = 0; i < childrenLength; i++) { - const c = children[i]; - if (c && type === "svg") { - element.innerHTML = `${element.innerHTML}${c.outerHTML}`; - } else { - c && element.appendChild(typeof c === "string" ? document.createTextNode(c) : c); - } - } - for (let i = 0; i < length; i++) { - const key = keys[i]; - if (key && !/^key$|^on|^ref$|^$/.test(key)) { - if (key !== "checked" || key === "checked" && props[key]) { - element.setAttribute(key === "htmlFor" ? "for" : key === "className" ? "class" : CAMEL_PROPS.test(key) && key.replace(/[A-Z0-9]/, "-$&").toLowerCase() || key, props[key]); - } - } - if (key && /^on/.test(key)) { - const eventType = key.toLowerCase().substring(2); - element.__handler__ = element.__handler__ || {}; - element.__handler__[eventType] = props[key]; - !events[eventType] && document.addEventListener(eventType, handler); - events[eventType] = 1; - } - if (key && /^key$/.test(key)) { - element.__key__ = props[key]; - } - if (key && /^ref$/.test(key)) { - props[key](element); - } - } - return element; - } - var handler = (ev) => { - let el = ev.target; - const type = ev.type; - while (el !== null) { - const handler2 = el.__handler__ && el.__handler__[type]; - if (handler2) { - handler2(ev); - return; - } - el = el.parentNode; - } - }; - var src_default = h2; - - // examples/jsx/h-shim.js - function h(type, props, ...children) { - if (typeof type === "function") { - return type({ - ...props || {}, - children: [].concat.apply([], children) - }); - } - return src_default(type, props || {}, [].concat.apply([], children)); - } - function Fragment(props) { - return props.children; - } - - // examples/jsx/app.jsx - var count = 0; - var input; - var increment = () => { - count = count + 1; - input.value = count; - }; - var decrement = () => { - count = count - 1; - input.value = count; - }; - var add = (ev) => { - count = Number(ev.target.value); - }; - var content = () => /* @__PURE__ */ h(Fragment, null, /* @__PURE__ */ h("h1", null, "Counter"), /* @__PURE__ */ h("button", { - onClick: increment - }, "+"), /* @__PURE__ */ h("input", { - ref: (el) => input = el, - onInput: add, - name: "input", - type: "number", - value: count - }), /* @__PURE__ */ h("button", { - onClick: decrement - }, "-"), /* @__PURE__ */ h("ul", null, ["0", "1"].map((i) => /* @__PURE__ */ h("li", null, i)))); - var counter = () => { - return /* @__PURE__ */ h("div", { - id: "app" - }, content()); - }; - var app = document.getElementById("app"); - app.parentNode.replaceChild(counter(), app); -})(); diff --git a/examples/counter.html b/examples/counter.html deleted file mode 100644 index dea28dd..0000000 --- a/examples/counter.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - H - SSR - - - -

Counter

- - - - - - diff --git a/examples/index-jsx.html b/examples/index-jsx.html index 4efc0d3..6ceb124 100644 --- a/examples/index-jsx.html +++ b/examples/index-jsx.html @@ -1,36 +1,29 @@ - - - - - H - JSX - - - -
-

Counter

- -
- - - - - - + + + + \ No newline at end of file diff --git a/examples/index.html b/examples/index.html deleted file mode 100644 index c7dc9f2..0000000 --- a/examples/index.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - H - - - -
-

Counter

- -
- - - - - - diff --git a/examples/index.js b/examples/index.js index 45755d9..0fd84aa 100644 --- a/examples/index.js +++ b/examples/index.js @@ -1,4 +1,4 @@ -import h from './src/index.js'; +import h from './h.js'; let count = 0; let input; @@ -9,18 +9,15 @@ const increment = () => { }; const decrement = () => { count = count - 1; - // input.value = count; - const app = document.getElementById('app'); - app.parentNode.replaceChild(counter(), app); + input.value = count; }; const add = (ev) => { count = Number(ev.target.value); }; const counter = () => { - return h('div', { id: 'app' }, [ - h('h1', null, ['Counter']), - h('button', { onClick: increment }, ['+']), + return h('form', { onSubmit: (ev) => ev.preventDefault() }, [ + h('button', { type: 'button', onClick: increment }, ['+']), h('input', { ref: (el) => (input = el), onInput: add, @@ -28,10 +25,9 @@ const counter = () => { type: 'number', value: count, }), - ...['0', '1'].map((i) => h('span', {}, i)), - h('button', { onClick: decrement }, [h('span', {}, ['-'])]), + h('button', { type: 'button', onClick: decrement }, [h('span', {}, ['-'])]), ]); }; -const app = document.getElementById('app'); -app.parentNode.replaceChild(counter(), app); +const form = document.querySelector('form'); +form.parentNode.replaceChild(counter(), form); diff --git a/examples/jsx/esbuild-jsx.js b/examples/jsx/esbuild-jsx.js index 068e7c2..8cfbf1b 100644 --- a/examples/jsx/esbuild-jsx.js +++ b/examples/jsx/esbuild-jsx.js @@ -1,8 +1,10 @@ -require('esbuild').buildSync({ - entryPoints: ['examples/jsx/app.jsx'], +import * as esbuild from 'esbuild'; + +await esbuild.buildSync({ + entryPoints: ['examples/jsx/index.jsx'], inject: ['examples/jsx/h-shim.js'], jsxFactory: 'h', jsxFragment: 'Fragment', bundle: true, - outfile: 'examples/app-jsx.js', + outfile: 'examples/index-jsx.js', }); diff --git a/examples/jsx/h-shim.js b/examples/jsx/h-shim.js index 8516d13..e51a93d 100644 --- a/examples/jsx/h-shim.js +++ b/examples/jsx/h-shim.js @@ -1,18 +1,4 @@ -import hh from '../src/index.js'; +import { Fragment, h } from '../h.js'; -export default function h(type, props, ...children) { - if (typeof type === 'function') { - return type({ - ...(props || {}), - children: [].concat.apply([], children), - }); - } - - return hh(type, props || {}, [].concat.apply([], children)); -} - -function Fragment(props) { - return props.children; -} - -export { Fragment, h }; +window.h = h; +window.Fragment = Fragment; diff --git a/examples/jsx/app.jsx b/examples/jsx/index.jsx similarity index 74% rename from examples/jsx/app.jsx rename to examples/jsx/index.jsx index 8f58933..ecbf2e9 100644 --- a/examples/jsx/app.jsx +++ b/examples/jsx/index.jsx @@ -1,5 +1,3 @@ -import h from './h-shim'; - let count = 0; let input; @@ -15,20 +13,21 @@ const add = (ev) => { count = Number(ev.target.value); }; -const content = () => ( +const Title = ({ children }) => ( +

{children}

+); + +const Content = () => ( <> -

Counter

+ Counter JSX (input = el)} onInput={add} name="input" type="number" value={count} /> -
    - {['0', '1'].map((i) =>
  • {i}
  • )} -
); const counter = () => { - return
{content()}
; + return
; }; const app = document.getElementById('app'); diff --git a/examples/src b/examples/src deleted file mode 120000 index 5cd551c..0000000 --- a/examples/src +++ /dev/null @@ -1 +0,0 @@ -../src \ No newline at end of file diff --git a/examples/ssr/build-page.js b/examples/ssr/build-page.js deleted file mode 100644 index 700fd43..0000000 --- a/examples/ssr/build-page.js +++ /dev/null @@ -1,27 +0,0 @@ -import 'html-element/global-shim'; -import { promises as fsp, readFileSync } from 'fs'; -import { join as joinPath } from 'path'; - -// @see: https://github.com/jakearchibald/jakearchibald.com/blob/master/static-build/utils.tsx#L27 -export async function buildPage({ content, output }) { - const pathParts = ['./', output]; - const fullPath = joinPath(...pathParts); - const templ = readFileSync(`${joinPath('./examples/templ.html')}`).toString(); - - try { - await fsp - .writeFile( - fullPath, - '' + templ.replace('__CONTENT__', content), - { - encoding: 'utf8', - } - ) - .catch(); - - return fullPath; - } catch (err) { - console.error('Failed to write ' + fullPath); - throw err; - } -} diff --git a/examples/ssr/counter.js b/examples/ssr/counter.js index 3b6a30e..26005dc 100644 --- a/examples/ssr/counter.js +++ b/examples/ssr/counter.js @@ -1,20 +1,22 @@ -import { buildPage } from './build-page'; -import h from '../src'; +import { writeFile, readFileSync } from 'fs'; +import { join as joinPath } from 'path'; -const counter = h('div', { id: 'app' }, [ - h('h1', {}, ['Counter']), - h('button', { onClick: () => {} }, ['+']), - h('input', { onInput: () => {}, name: 'input', type: 'number', value: 0 }), - h('button', { onClick: () => {} }, ['-']), +import '../document.js'; +import h, { Fragment } from '../h.js'; + +const content = h(Fragment, {}, [ + h('h1', {}, ['Counter SSR']), + h('form', {}, [ + h('button', { type: 'button', onClick: () => {} }, ['+']), + h('input', { onInput: () => {}, name: 'input', type: 'number', value: 0 }), + h('button', { type: 'button', onClick: () => {} }, ['-']), + ]), ]); -buildPage({ - content: counter.outerHTML, - output: 'examples/counter.html', -}) - .then((fullPath) => console.log('Success: ' + fullPath + '\n')) - .then(() => process.exit()) - .catch((e) => { - console.error(e); - process.exit(1); - }); +const counter = h('div', { id: 'app' }, content); + +const template = readFileSync(`${joinPath('./examples/ssr/template.html')}`).toString(); +writeFile('examples/index.html', template.replace('__CONTENT__', counter), (err) => { + if (err) throw err; + console.log('The file has been saved!'); +}); diff --git a/examples/templ.html b/examples/ssr/template.html similarity index 69% rename from examples/templ.html rename to examples/ssr/template.html index 1a3ebce..4038016 100644 --- a/examples/templ.html +++ b/examples/ssr/template.html @@ -4,7 +4,7 @@ - H + Counter SSR __CONTENT__ - -