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",
|
||||
"marked": "^13.0.2",
|
||||
"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",
|
||||
},
|
||||
jsxFragment: "Fragment",
|
||||
jsxFactory: "Nano.h",
|
||||
jsxImportSource: "nano-jsx",
|
||||
jsxFactory: "h",
|
||||
jsxImportSource: "preact",
|
||||
jsx: "transform",
|
||||
write: false,
|
||||
bundle: true,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
"module": "ESNext",
|
||||
"moduleDetection": "force",
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "nano-jsx/esm",
|
||||
"jsxImportSource": "preact",
|
||||
"allowJs": true,
|
||||
|
||||
// Bundler mode
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Nano, { Component, Fragment } from "nano-jsx"
|
||||
import { BlogPage } from "./blog_page";
|
||||
import { Giscus } from "./giscus";
|
||||
import { useState } from "nano-jsx/esm/hooks/useState.js";
|
||||
import { h, Component, Fragment, render } from 'preact';
|
||||
import { useEffect, useState } from 'preact/hooks';
|
||||
import { Giscus } from './giscus';
|
||||
import { BlogPost } from './blog_post';
|
||||
|
||||
export interface Metadata {
|
||||
title: string;
|
||||
|
@ -12,74 +12,58 @@ export interface Metadata {
|
|||
|
||||
const blog_posts = __BLOG_POSTS__ as string[];
|
||||
|
||||
const fetchBlogPosts = async () => {
|
||||
const metadatas: Metadata[] = [];
|
||||
const Blog = () => {
|
||||
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) {
|
||||
const req = await fetch("/blogs/" + blog + ".json");
|
||||
const json = await req.json()
|
||||
json.filename = blog;
|
||||
metadatas.push(json);
|
||||
}
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const metadatas: Metadata[] = [];
|
||||
|
||||
return metadatas
|
||||
}
|
||||
|
||||
class Main extends Component {
|
||||
async didMount() {
|
||||
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;
|
||||
for await (const blog of blog_posts) {
|
||||
const req = await fetch("/blogs/" + blog + ".json");
|
||||
const json = await req.json()
|
||||
json.filename = blog;
|
||||
metadatas.push(json);
|
||||
}
|
||||
}
|
||||
|
||||
blogPosts[1](metadatas);
|
||||
})();
|
||||
}, [])
|
||||
|
||||
if (pageOpenValueRender) {
|
||||
return <div><BlogPage metadata={pageOpenValueRender} updateParent={this.handleSelfUpdate.bind(this)}></BlogPage></div>
|
||||
if (blogPosts[0]) {
|
||||
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