move from nano-jsx to Preact, benefits: 1. Smaller bundle size, 2. Quicker rendering, 3. Full vDom with proper states, 4. Proper pure functions
All checks were successful
/ test (push) Successful in 14s
All checks were successful
/ test (push) Successful in 14s
This commit is contained in:
parent
b598ebd306
commit
7255080d31
|
@ -18,6 +18,6 @@
|
||||||
"esbuild": "^0.23.0",
|
"esbuild": "^0.23.0",
|
||||||
"marked": "^13.0.2",
|
"marked": "^13.0.2",
|
||||||
"mime-types": "^2.1.35",
|
"mime-types": "^2.1.35",
|
||||||
"nano-jsx": "^0.1.0"
|
"preact": "^10.23.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -29,8 +29,8 @@ export default class TSCompiler extends Plugin {
|
||||||
| "jsx",
|
| "jsx",
|
||||||
},
|
},
|
||||||
jsxFragment: "Fragment",
|
jsxFragment: "Fragment",
|
||||||
jsxFactory: "Nano.h",
|
jsxFactory: "h",
|
||||||
jsxImportSource: "nano-jsx",
|
jsxImportSource: "preact",
|
||||||
jsx: "transform",
|
jsx: "transform",
|
||||||
write: false,
|
write: false,
|
||||||
bundle: true,
|
bundle: true,
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"moduleDetection": "force",
|
"moduleDetection": "force",
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"jsxImportSource": "nano-jsx/esm",
|
"jsxImportSource": "preact",
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
|
|
||||||
// Bundler mode
|
// Bundler mode
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import Nano, { Component, Fragment } from "nano-jsx"
|
import { h, Component, Fragment, render } from 'preact';
|
||||||
import { BlogPage } from "./blog_page";
|
import { useEffect, useState } from 'preact/hooks';
|
||||||
import { Giscus } from "./giscus";
|
import { Giscus } from './giscus';
|
||||||
import { useState } from "nano-jsx/esm/hooks/useState.js";
|
import { BlogPost } from './blog_post';
|
||||||
|
|
||||||
export interface Metadata {
|
export interface Metadata {
|
||||||
title: string;
|
title: string;
|
||||||
|
@ -12,74 +12,58 @@ export interface Metadata {
|
||||||
|
|
||||||
const blog_posts = __BLOG_POSTS__ as string[];
|
const blog_posts = __BLOG_POSTS__ as string[];
|
||||||
|
|
||||||
const fetchBlogPosts = async () => {
|
const Blog = () => {
|
||||||
const metadatas: Metadata[] = [];
|
const pageOpen = useState<Metadata | undefined>()
|
||||||
|
const blogPosts = useState<Metadata[] | undefined>(undefined)
|
||||||
|
const md = new URLSearchParams(location.search).get("md");
|
||||||
|
|
||||||
for await (const blog of blog_posts) {
|
useEffect(() => {
|
||||||
const req = await fetch("/blogs/" + blog + ".json");
|
(async () => {
|
||||||
const json = await req.json()
|
const metadatas: Metadata[] = [];
|
||||||
json.filename = blog;
|
|
||||||
metadatas.push(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
return metadatas
|
for await (const blog of blog_posts) {
|
||||||
}
|
const req = await fetch("/blogs/" + blog + ".json");
|
||||||
|
const json = await req.json()
|
||||||
class Main extends Component {
|
json.filename = blog;
|
||||||
async didMount() {
|
metadatas.push(json);
|
||||||
const blogPosts = await fetchBlogPosts()
|
|
||||||
this.update(blogPosts)
|
|
||||||
}
|
|
||||||
|
|
||||||
list(metadatas: Metadata[]) {
|
|
||||||
const pageOpen = useState<Metadata | undefined>(undefined, "pageOpen");
|
|
||||||
|
|
||||||
return <ul>
|
|
||||||
{metadatas.map((n) => {
|
|
||||||
return <li>
|
|
||||||
<a onClick={
|
|
||||||
() => {
|
|
||||||
pageOpen[1](n);
|
|
||||||
this.update();
|
|
||||||
}
|
|
||||||
}>{n.title} (created {new Date(n.time * 1000).toLocaleString()})</a>
|
|
||||||
</li>
|
|
||||||
})}
|
|
||||||
</ul>
|
|
||||||
}
|
|
||||||
|
|
||||||
async handleSelfUpdate() {
|
|
||||||
const blogPosts = await fetchBlogPosts()
|
|
||||||
this.update(blogPosts)
|
|
||||||
}
|
|
||||||
|
|
||||||
render(blogPosts: Metadata[]) {
|
|
||||||
|
|
||||||
const pageOpen = useState<Metadata | undefined>(undefined, "pageOpen");
|
|
||||||
const md = new URLSearchParams(location.search).get("md");
|
|
||||||
let pageOpenValueRender = pageOpen[0];
|
|
||||||
|
|
||||||
if (blogPosts) {
|
|
||||||
const found = blogPosts.find(z => z.filename == md);
|
|
||||||
if (found) {
|
|
||||||
pageOpen[1](found);
|
|
||||||
pageOpenValueRender = found;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
blogPosts[1](metadatas);
|
||||||
|
})();
|
||||||
|
}, [])
|
||||||
|
|
||||||
if (pageOpenValueRender) {
|
if (blogPosts[0]) {
|
||||||
return <div><BlogPage metadata={pageOpenValueRender} updateParent={this.handleSelfUpdate.bind(this)}></BlogPage></div>
|
const found = blogPosts[0].find(z => z.filename == md);
|
||||||
|
if (found) {
|
||||||
|
pageOpen[1](found);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <>
|
|
||||||
<h1>blog & comments</h1>
|
|
||||||
{() => {
|
|
||||||
if (blogPosts) return this.list(blogPosts)
|
|
||||||
else return <h3>Loading...</h3>
|
|
||||||
}}
|
|
||||||
<Giscus searchTerm="main"></Giscus>
|
|
||||||
</>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pageOpen[0]) {
|
||||||
|
return <BlogPost pageOpen={pageOpen}></BlogPost>
|
||||||
|
}
|
||||||
|
|
||||||
|
return <>
|
||||||
|
<h1>blog & comments</h1>
|
||||||
|
{(() => {
|
||||||
|
if (blogPosts[0]) {
|
||||||
|
return <ul>
|
||||||
|
{blogPosts[0].map((n) => {
|
||||||
|
return <li>
|
||||||
|
<a onClick={
|
||||||
|
() => {
|
||||||
|
pageOpen[1](n);
|
||||||
|
}
|
||||||
|
}>{n.title} (created {new Date(n.time * 1000).toLocaleString()})</a>
|
||||||
|
</li>
|
||||||
|
})}
|
||||||
|
</ul>;
|
||||||
|
}
|
||||||
|
else { return <h3>Loading...</h3> }
|
||||||
|
})()}
|
||||||
|
<Giscus searchTerm='main'></Giscus>
|
||||||
|
</>;
|
||||||
}
|
}
|
||||||
|
|
||||||
Nano.render(<Main></Main>, document.getElementById("root"))
|
|
||||||
|
render(<Blog></Blog>, document.getElementById("root")!);
|
|
@ -1,48 +0,0 @@
|
||||||
import { Component } from "nano-jsx"
|
|
||||||
import { Giscus } from "./giscus";
|
|
||||||
import { useState } from "nano-jsx/esm/hooks/useState.js";
|
|
||||||
import type { Metadata } from "./blog";
|
|
||||||
|
|
||||||
const fetchBlogPost = async (metadata: Metadata) => {
|
|
||||||
return (await fetch("/blogs/" + metadata.filename + ".html")).text();
|
|
||||||
}
|
|
||||||
|
|
||||||
export class BlogPage extends Component {
|
|
||||||
metadata: Metadata;
|
|
||||||
updateParent: () => void;
|
|
||||||
|
|
||||||
constructor(props: { metadata: Metadata, updateParent: () => void }) {
|
|
||||||
super(props);
|
|
||||||
this.metadata = props.metadata;
|
|
||||||
this.updateParent = props.updateParent;
|
|
||||||
}
|
|
||||||
|
|
||||||
async didMount() {
|
|
||||||
const blogPost = await fetchBlogPost(this.metadata)
|
|
||||||
this.update(blogPost)
|
|
||||||
}
|
|
||||||
|
|
||||||
render(blogPost: string) {
|
|
||||||
const pageOpen = useState<string | undefined>(undefined, "pageOpen");
|
|
||||||
history.replaceState({}, "", location.pathname + "?md=" + this.metadata.filename);
|
|
||||||
|
|
||||||
return <>
|
|
||||||
<h1>blog & comments</h1>
|
|
||||||
<a style="font-size:xx-large;" onClick={() => {
|
|
||||||
pageOpen[1](undefined);
|
|
||||||
history.replaceState({}, "", location.pathname + "?md=");
|
|
||||||
|
|
||||||
this.updateParent();
|
|
||||||
}}>return back?</a>
|
|
||||||
<div>Scroll to bottom for comments ↓</div>
|
|
||||||
|
|
||||||
{
|
|
||||||
() => {
|
|
||||||
if (!blogPost) return <h1>Loading...</h1>
|
|
||||||
else return <div dangerouslySetInnerHTML={{ __html: blogPost }}></div>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<Giscus searchTerm={this.metadata.filename}></Giscus>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
}
|
|
36
website/scripts/blog_post.tsx
Normal file
36
website/scripts/blog_post.tsx
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import { useEffect, useState } from "preact/hooks";
|
||||||
|
import type { Metadata } from "./blog";
|
||||||
|
import { Giscus } from "./giscus";
|
||||||
|
|
||||||
|
|
||||||
|
export function BlogPost({ pageOpen }: { pageOpen: [Metadata | undefined, (z: Metadata | undefined) => void] }) {
|
||||||
|
if(!pageOpen[0]) return <h1>How did you get to here..?</h1>;
|
||||||
|
|
||||||
|
const blogPost = useState<string | undefined>();
|
||||||
|
|
||||||
|
history.replaceState({}, "", location.pathname + "?md=" + pageOpen[0].filename);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
const blogpost = await (await fetch("/blogs/" + pageOpen[0]!.filename + ".html")).text();;
|
||||||
|
blogPost[1](blogpost);
|
||||||
|
})();
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return <>
|
||||||
|
<h1>blog & comments</h1>
|
||||||
|
<a style="font-size:xx-large;" onClick={() => {
|
||||||
|
history.replaceState({}, "", location.pathname + "?md=");
|
||||||
|
pageOpen[1](undefined);
|
||||||
|
}}>return back?</a>
|
||||||
|
<div>Scroll to bottom for comments ↓</div>
|
||||||
|
|
||||||
|
{
|
||||||
|
(() => {
|
||||||
|
if (!blogPost[0]) return <h1>Loading...</h1>
|
||||||
|
else return <div dangerouslySetInnerHTML={{ __html: blogPost[0] }}></div>
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
<Giscus searchTerm={pageOpen[0].filename}></Giscus>
|
||||||
|
</>
|
||||||
|
}
|
Loading…
Reference in a new issue