Total Pageviews

Monday, 15 June 2026

ChatRoom, React前台+Node.js后台搭建的聊天室.


👋 这是我个人在学习react过程中做的一个练习用项目。

一个聊天室💬,可以登录、创建房间、加入房间以及聊天。

前端基于React + Redux + Typescript + Antd,

后端基于node.js + express + socket.io

🔨 Usage

前端:

cd ChatRoom/chatroom

npm install

npm start

后端:

cd ChatRoom/chatroomServe

npm install

npm start

from  https://github.com/Magren0321/ChatRoom

( https://github.com/brightmann/ChatRoom)


cloud-music


✌️ 该项目是模仿安卓网易云音乐APP的UI制作的移动端网页版网易云音乐,实现了部分功能。

项目基于Vue + Typescript + Vuetify UI构建。

后台由网易云音乐api提供。

👉 本项目是个人学习而制作,正常使用请到网易云音乐

功能

  • 登录
  • 获取歌单
  • 创建歌单
  • 删除/取消收藏歌单
  • 播放歌曲
  • 排行榜
  • 每日推荐
  • 推荐歌单

项目截图

运行

首先请根据网易云音乐api文档配置后台,接着将接口地址填入配置文件(vue.config.js)中。

接着开始运行项目 🚀

npm install

npm run serve

 from  https://github.com/Magren0321/cloud-music

( https://github.com/brightmann/cloud-music)

 

 

DNS 的更新是如何工作的?

已经看到很多人对更新站点的 DNS 记录以更改 IP 地址感到困惑。为什么这么慢?是否真的需要等待 2 天才能更新所有内容?为什么有些人看到新 IP,有些人看到旧 IP?发生了什么?

这里记录一下更新 DNS 背后所发生了些什么。
DNS 的分类:递归 vs 权威 DNS 服务器

首先,我们需要解释一些有关 DNS 的知识。DNS 服务器有两种:权威服务器和递归服务器。

权威DNS 服务器(也称为名称服务器)具有一个负责其每个域名的 IP 地址数据库。例如,github.com 的权威 DNS 服务器是 ns-421.awsdns-52.com。你可以通过 dig 命令来获取 github.com 的 IP。
Terminal window

dig @ns-421.awsdns-52.com github.com

递归DNS 服务器本身对谁拥有什么 IP 地址一无所知。它们通过询问正确的权威 DNS 服务器来确定域名的 IP 地址,然后缓存该 IP 地址,以防再次被问到。8.8.8.8 是递归 DNS 服务器。

当人们访问你的网站时,他们可能正在对递归 DNS 服务器进行 DNS 查询。那么,递归 DNS 服务器如何工作?让我们来看看!
递归 DNS 服务器如何查询 github.com?

我们来看一个递归 DNS 服务器(如 8.8.8.8)在你请求 github.com 的 IP 地址(A 记录)时的功能的示例。首先–如果已经缓存了某些内容,它将为您提供缓存的内容。但是,如果所有缓存均已过期怎么办?这是发生了什么:

步骤 1:在源代码中硬编码根 DNS 服务器的 IP 地址。您可以在unbound 的源代码中看到这一点。假设198.41.0.4从开始就选择。这是这些硬编码 IP 地址的正式来源,也称为“根目录提示文件”。

步骤 2:向根域名服务器查询github.com。

我们可以大致再现发生的情况dig。这给我们提供了一个新的权威名称服务器:.comIP 的名称服务器192.5.6.30。

$ dig @198.41.0.4 github.com
...
com.            172800  IN  NS  a.gtld-servers.net.
...
a.gtld-servers.net.    172800  IN  A   192.5.6.30
...

DNS 响应的详细信息比这要复杂一些–在这种情况下,其中有一个具有一些 NS 记录的授权部分,而另一个具有 A 记录的部分,因此您无需进行额外的查找即可获得这些名称服务器 IP 地址。

(实际上,它已经有 99.99%的时间已经缓存了.com名称服务器的地址,但是我们假装实际上是从头开始的)

步骤 3:向.com域名服务器查询有关github.com。

$ dig @192.5.6.30 github.com
...
github.com.        172800  IN  NS  ns-421.awsdns-52.com.
ns-421.awsdns-52.com.    172800  IN  A   205.251.193.165
...

我们有一个新的 IP 地址要询问!这是github.com的名称服务器。

步骤 4:向github.com域名服务器询问有关github.com。

$ dig @205.251.193.165 github.com

github.com.        60  IN  A   140.82.112.4

OK!我们现在有一个github.com的A记录!现在,递归名称服务器具有github.com的 IP 地址,可以将其返回给您。它通过仅硬编码几个IP 地址即可完成所有这些操作:即根名称服务器的地址。
如何查看所有递归 DNS 服务器: dig+trace

当我想查看解析一个域名时递归 DNS 服务器将执行的操作,我运行以下命令:

$ dig @8.8.8.8 +trace github.com

这显示了它请求的所有 DNS 记录,从根 DNS 服务器开始—我们刚刚完成的所有 4 个步骤。
如何更新 DNS 记录?

既然我们了解了 DNS 工作原理,那么让我们更新一些 DNS 记录,看看会发生什么。

更新 DNS 记录时,有两个主要选项:

    保持相同的名称服务器
    更改名称服务器

关于 TTL

这里我们先说明一下 TTL 这个概念,我们之前说过递归 DNS 服务器将缓存记录直到它们过期,而决定记录是否应过期的方式是查看其TTL(Time To Live)。

下面的示例中,A 记录 github 的名称服务器为其 DNS 记录返回的 TTL 为60,这意味着 60 秒:

$ dig @205.251.193.165 github.com
github.com.        60  IN  A   140.82.112.4

这是一个非常短的 TTL,*从理论上讲,*如果每个人的 DNS 实施都遵循DNS 标准,则意味着如果 Github 决定更改 IP 地址github.com,则每个人都应在 60 秒内获得新的 IP 地址。让我们看看实际情况如何。
选项 1:在相同的名称服务器上更新 DNS 记录

首先,我更新了我的名称服务器(Cloudflare),使其具有新的 DNS 记录:映射test.jvns.ca到的 A 记录 1.2.3.4。

$ dig @8.8.8.8 test.jvns.ca
test.jvns.ca.        299 IN  A   1.2.3.4

这会立即生效!根本不需要等待,因为test.jvns.ca在可以缓存之前没有 DNS 记录。但是看起来新记录被缓存了大约 5 分钟(299 秒)。

那么,如果我们尝试更改该 IP 怎么办?我将其更改为5.6.7.8,然后运行了相同的 DNS 查询。

$ dig @8.8.8.8 test.jvns.ca
test.jvns.ca.        144 IN  A   1.2.3.4

嗯,好像 DNS 服务器的1.2.3.4记录仍在缓存 144 秒。有趣的是,如果我8.8.8.8多次查询实际上却得到不一致的结果–有时它会给我新的 IP,有时会给我旧的 IP,我想是因为 8.8.8.8 实际上将负载平衡到一堆不同的后端,每个后端都有自己的缓存。

我等了 5 分钟后,所有8.8.8.8缓存均已更新,并且始终返回新5.6.7.8记录。不得不说,这相当的快!
你不能总是依靠 TTL

与大多数 Internet 协议一样,并非所有内容都遵循 DNS 规范。某些 ISP DNS 服务器将缓存记录的时间长于 TTL 指定的时间,例如 2 天而不是 5 分钟。人们总是可以在/etc/hosts 中对旧 IP 地址进行硬编码。

在使用 5 分钟的 TTL 更新 DNS 记录时,我期望在实践中会发生的事情是,很大比例的客户端会迅速(例如在 15 分钟之内)移到新 IP,然后会有一些慢的客户端在接下来的几天内会慢慢更新。
选项 2:更新名称服务器

我们已经看到,当您在不更改名称服务器的情况下更新 IP 地址时,许多 DNS 服务器将很快获取新 IP。但是,如果您更改名称服务器会怎样?

我不想更新我的博客的域名服务器,所以examplecat.com。

以前,我的名称服务器设置为 dns1.p01.nsone.net。我决定将它们切换到 Google 的名称服务器-ns-cloud-b1.googledomains.com等等。

进行更改后,我的域名注册商有点不愉快地弹出了消息-“对 examplecat.com 的更改已保存。它们将在接下来的 48 小时内生效。” 然后,我为该域设置了一个新的 A 记录,使其指向1.2.3.4

OK,让我们看看是否有任何作用:

$ dig @8.8.8.8 examplecat.com
examplecat.com.        17  IN  A   104.248.50.87

没变化。如果我询问其他 DNS 服务器,它将返回新 IP 地址:

$ dig @1.1.1.1 examplecat.com
examplecat.com.        299 IN  A   1.2.3.4

但是 8.8.8.8 仍然毫无变化。即使我在 5 分钟前刚刚更改它,1.1.1.1 能看到新 IP 的原因大概是以前没有人向 1.1.1.1 询问过 examplecat.com,因此它的缓存中没有任何内容。
名称服务器的 TTL 更长

我的注册服务商说“这将花费 48 小时”的原因是 NS 记录上的 TTL(这是递归名称服务器如何知道要询问哪个名称服务器)更长!

新的域名服务器肯定会返回新的 IP 地址 examplecat.com

$ dig @ns-cloud-b1.googledomains.com examplecat.com
examplecat.com.        300 IN  A   1.2.3.4

但是还记得当我们查询github.com域名服务器时发生了什么吗?

$ dig @192.5.6.30 github.com
...
github.com.        172800  IN  NS  ns-421.awsdns-52.com.
ns-421.awsdns-52.com.    172800  IN  A   205.251.193.165
...

172800 秒是 48 个小时!因此,与不更改名称服务器而仅更新 IP 地址相比,名称服务器更新通常需要更长的时间才能从缓存中到期并传播。
域名服务器如何更新?

当我更新的域名服务器时examplecat.com,发生的事情是 .com域名服务器获得了NS新域名的新记录。像这样:

dig ns @j.gtld-servers.net examplecat.com

examplecat.com.        172800  IN  NS  ns-cloud-b1.googledomains.com

但是,新的 NS 记录如何到达那里?发生的事情是,我通过在网站上更新域名告诉域名注册商我希望新的域名服务器是什么,然后域名注册商告诉.com域名服务器进行更新。

对于.com,这些更新发生的速度非常快(在几分钟之内),但是我认为对于其他一些 TLD,TLD 域名服务器可能无法尽快应用更新。
程序的 DNS 解析器库可能还会缓存 DNS 记录.

实际中可能不遵守 TTL 的另一个原因:许多程序需要解析 DNS 名称,并且某些程序还将无限期地将 DNS 记录缓存在内存中(直到程序重新启动)。

例如,AWS 有一篇关于为 DNS 名称查找设置 JVM TTL的文章(https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/java-dg-jvm-ttl.html)。我没有编写太多可以自己进行 DNS 查找的 JVM 代码,但是通过对 JVM 和 DNS 的一些仔细研究,似乎可以配置 JVM,以便它无限期地缓存每个 DNS 查找。(例如此 elasticsearch 问题-
https://github.com/elastic/elasticsearch/issues/16412)

p.s. TTL 不能说明 DNS 工作原理的全部–即使像 8.8.8.8 这样的主要 DNS 服务器,某些递归 DNS 服务器也绝对不尊重 TTL。因此,即使您只是用短的 TTL 更新 A 记录,实际上还是很有可能在一两天内收到对旧 IP 的一些请求。


参考:
https://jvns.ca/blog/how-updating-dns-works

------

What happens when you update your DNS?

 

I’ve seen a lot of people get confused about updating their site’s DNS records to change the IP address. Why is it slow? Do you really have to wait 2 days for everything to update? Why do some people see the new IP and some people see the old IP? What’s happening?

So I wanted to write a quick exploration of what’s happening behind the scenes when you update a DNS record.

how DNS works: recursive vs authoritative DNS servers

First, we need to explain a little bit about DNS. There are 2 kinds of DNS servers: authoritative and recursive.

authoritative DNS servers (also known as nameservers) have a database of IP addresses for each domain they’re responsible for. For example, right now an authoritative DNS server for github.com is ns-421.awsdns-52.com. You can ask it for github.com’s IP like this;

dig @ns-421.awsdns-52.com github.com

recursive DNS servers, by themselves, don’t know anything about who owns what IP address. They figure out the IP address for a domain by asking the right authoritative DNS servers, and then cache that IP address in case they’re asked again. 8.8.8.8 is a recursive DNS server.

When people visit your website, they’re probably making their DNS queries to a recursive DNS server. So, how do recursive DNS servers work? Let’s see!

how does a recursive DNS server query for github.com?

Let’s go through an example of what a recursive DNS server (like 8.8.8.8) does when you ask it for an IP address (A record) for github.com. First – if it already has something cached, it’ll give you what it has cached. But what if all of its caches are expired? Here’s what happens:

step 1: it has IP addresses for the root DNS servers hardcoded in its source code. You can see this in unbound’s source code here. Let’s say it picks 198.41.0.4 to start with. Here’s the official source for those hardcoded IP addresses, also known as a “root hints file”.

step 2: Ask the root nameservers about github.com.

We can roughly reproduce what happens with dig. What this gives us is a new authoritative nameserver to ask: a nameserver for .com, with the IP 192.5.6.30.

$ dig @198.41.0.4 github.com
...
com.			172800	IN	NS	a.gtld-servers.net.
...
a.gtld-servers.net.	172800	IN	A	192.5.6.30
...

The details of the DNS response are a little more complicated than that – in this case, there’s an authority section with some NS records and an additional section with A records so you don’t need to do an extra lookup to get the IP addresses of those nameservers.

(in practice, 99.99% of the time it’ll already have the address of the .com nameservers cached, but we’re pretending we’re really starting from scratch)

step 3: Ask the .com nameservers about github.com.

$ dig @192.5.6.30 github.com
...
github.com.		172800	IN	NS	ns-421.awsdns-52.com.
ns-421.awsdns-52.com.	172800	IN	A	205.251.193.165
...

We have a new IP address to ask! This one is the nameserver for github.com.

step 4: Ask the github.com nameservers about github.com.

We’re almost done!

$ dig @205.251.193.165 github.com

github.com.		60	IN	A	140.82.112.4

Hooray!! We have an A record for github.com! Now the recursive nameserver has github.com’s IP address and can return it back to you. And it could do all of this by only hardcoding a few IP addresses: the addresses of the root nameservers.

how to see all of a recursive DNS server’s steps: dig +trace

When I want to see what a recursive DNS server would do when resolving a domain, I run

$ dig @8.8.8.8 +trace github.com

This shows all the DNS records that it requests, starting at the root DNS servers – all the 4 steps that we just went through.

let’s update some DNS records!

Now that we know the basics of how DNS works, let’s update some DNS records and see what happens.

When you update your DNS records, there are two main options:

  1. keep the same nameservers
  2. change nameservers

let’s talk about TTLs

We’ve forgotten something important though! TTLs! You know how we said earlier that the recursive DNS server will cache records until they expire? The way it decides whether the record should expire is by looking at its TTL or “time to live”.

In this example, the TTL for the A record github’s nameserver returns for its DNS record is 60, which means 60 seconds:

$ dig @205.251.193.165 github.com

github.com.		60	IN	A	140.82.112.4

That’s a pretty short TTL, and in theory if everybody’s DNS implementation followed the DNS standard it means that if Github decided to change the IP address for github.com, everyone should get the new IP address within 60 seconds. Let’s see how that plays out in practice

option 1: update a DNS record on the same nameservers

First, I updated my nameservers (Cloudflare) to have a new DNS record: an A record that maps test.jvns.ca to 1.2.3.4.

$ dig @8.8.8.8 test.jvns.ca
test.jvns.ca.		299	IN	A	1.2.3.4

This worked immediately! There was no need to wait at all, because there was no test.jvns.ca DNS record before that could have been cached. Great. But it looks like the new record is cached for ~5 minutes (299 seconds).

So, what if we try to change that IP? I changed it to 5.6.7.8, and then ran the same DNS query.

$ dig @8.8.8.8 test.jvns.ca
test.jvns.ca.		144	IN	A	1.2.3.4

Hmm, it seems like that DNS server has the 1.2.3.4 record still cached for another 144 seconds. Interestingly, if I query 8.8.8.8 multiple times I actually get inconsistent results – sometimes it’ll give me the new IP and sometimes the old IP, I guess because 8.8.8.8 actually load balances to a bunch of different backends which each have their own cache.

After I waited 5 minutes, all of the 8.8.8.8 caches had updated and were always returning the new 5.6.7.8 record. Awesome. That was pretty fast!

you can’t always rely on the TTL

As with most internet protocols, not everything obeys the DNS specification. Some ISP DNS servers will cache records for longer than the TTL specifies, like maybe for 2 days instead of 5 minutes. And people can always hardcode the old IP address in their /etc/hosts.

What I’d expect to happen in practice when updating a DNS record with a 5 minute TTL is that a large percentage of clients will move over to the new IPs quickly (like within 15 minutes), and then there will be a bunch of stragglers that slowly update over the next few days.

option 2: updating your nameservers

So we’ve seen that when you update an IP address without changing your nameservers, a lot of DNS servers will pick up the new IP pretty quickly. Great. But what happens if you change your nameservers? Let’s try it!

I didn’t want to update the nameservers for my blog, so instead I went with a different domain I own and use in the examples for the HTTP zine: examplecat.com.

Previously, my nameservers were set to dns1.p01.nsone.net. I decided to switch them over to Google’s nameservers – ns-cloud-b1.googledomains.com etc.

When I made the change, my domain registrar somewhat ominously popped up the message – “Changes to examplecat.com saved. They’ll take effect within the next 48 hours”. Then I set up a new A record for the domain, to make it point to 1.2.3.4

Okay, let’s see if that did anything

$ dig @8.8.8.8 examplecat.com
examplecat.com.		17	IN	A	104.248.50.87

No change. If I ask a different DNS server, it knows the new IP:

$ dig @1.1.1.1 examplecat.com
examplecat.com.		299	IN	A	1.2.3.4

but 8.8.8.8 is still clueless. The reason 1.1.1.1 sees the new IP even though I just changed it 5 minutes ago is presumably that nobody had ever queried 1.1.1.1 about examplecat.com before, so it had nothing in its cache.

nameserver TTLs are much longer

The reason that my registrar was saying “THIS WILL TAKE 48 HOURS” is that the TTLs on NS records (which are how recursive nameservers know which nameserver to ask) are MUCH longer!

The new nameserver is definitely returning the new IP address for examplecat.com

$ dig @ns-cloud-b1.googledomains.com examplecat.com
examplecat.com.		300	IN	A	1.2.3.4

But remember what happened when we queried for the github.com nameservers, way back?

$ dig @192.5.6.30 github.com
...
github.com.		172800	IN	NS	ns-421.awsdns-52.com.
ns-421.awsdns-52.com.	172800	IN	A	205.251.193.165
...

172800 seconds is 48 hours! So nameserver updates will in general take a lot longer to expire from caches and propagate than just updating an IP address without changing your nameserver.

how do your nameservers get updated?

When I update the nameservers for examplecat.com, what happens is that he .com nameserver gets a new NS record with the new domain. Like this:

dig ns @j.gtld-servers.net examplecat.com

examplecat.com.		172800	IN	NS	ns-cloud-b1.googledomains.com

But how does that new NS record get there? What happens is that I tell my domain registrar what I want the new nameservers to be by updating it on the website, and then my domain registrar tells the .com nameservers to make the update.

For .com, these updates happen pretty fast (within a few minutes), but I think for some other TLDs the TLD nameservers might not apply updates as quickly.

your program’s DNS resolver library might also cache DNS records

One more reason TTLs might not be respected in practice: many programs need to resolve DNS names, and some programs will also cache DNS records indefinitely in memory (until the program is restarted).

For example, AWS has an article on Setting the JVM TTL for DNS Name Lookups. I haven’t written that much JVM code that does DNS lookups myself, but from a little Googling about the JVM and DNS it seems like you can configure the JVM so that it caches every DNS lookup indefinitely. (like this elasticsearch issue)

that’s all!

I hope this helps you understand what’s going on when updating your DNS!

As a disclaimer, again – TTLs definitely don’t tell the whole story about DNS propagation – some recursive DNS servers definitely don’t respect TTLs, even if the major ones like 8.8.8.8 do. So even if you’re just updating an A record with a short TTL, it’s very possible that in practice you’ll still get some requests to the old IP for a day or two.

Also, I changed the nameservers for examplecat.com back to their old values after publishing this post.

from  https://jvns.ca/blog/how-updating-dns-works/

Sunday, 14 June 2026

基于Julia的静态网站生成器Franklin.jl

 

Building static websites in Julia

Franklin is a simple, customisable static site generator oriented towards technical blogging and light, fast-loading pages.

Key features

click on the '✓' sign to know more

  • Augmented markdown allowing definition of LaTeX-like commands,

  • Easy inclusion of user-defined div-blocks,

  • Maths rendered via KaTeX, code via highlight.js both can be pre-rendered,

  • Can live-evaluate Julia code blocks,

  • Live preview of modifications,

  • Simple optimisation step to compress and pre-render the website,

  • Simple publication step to deploy the website,

  • Straightforward integration with Literate.jl.

⚠ Note
If you already have experience with Franklin and just want to keep an eye on (new) tips and tricks, have a look at the short demos

Quick start

To install Franklin with Julia ≥ 1.3,

(v1.6) pkg> add Franklin

You can then just try it out:

julia> using Franklin
julia> newsite("mySite", template="pure-sm")
✓ Website folder generated at "mySite" (now the current directory).
→ Use serve() from Franklin to see the website in your browser.

julia> serve()
→ Initial full pass...
→ Starting the server...
✓ LiveServer listening on http://localhost:8000/ ...
  (use CTRL+C to shut down)

If you navigate to that URL in your browser, you will see the website. If you then open index.md in an editor and modify it at will, the changes will be live rendered in your browser. You can also inspect the file menu1.md which offers more examples of what Franklin can do.

Installing optional extras

Franklin allows a post-processing step to compress HTML and CSS and pre-render code blocks and math environments. This requires a couple of dependencies:

  • python3 for the minification of the site,

  • node.js for the pre-rendering of KaTeX and code highlighting.

You will then need to install highlight.js, which you should do from Julia using the NodeJS.jl package:

julia> using NodeJS
julia> run(`sudo $(npm_cmd()) install highlight.js`)

Note: a key advantage of using NodeJS for this instead of using npm yourself is that it puts the libraries in the "right place" for Julia to find them.

Assuming you have python3, Franklin will try to install the python package css_html_js_minify if via pip3.

⚠ Note
You don't have to install these libraries and you can safely ignore any message suggesting you install those. Also note that if you do want this but it doesn't work locally due to some node weirdness or related, things will likely still work if you use GitHub to deploy.

grtblog,由 SvelteKit 与 Go 驱动,静态先行、实时交互的现代化博客系统

 

不仅是博客,也是全新的内容基础设施。

grtblog.js.org/

现代化博客系统 — 静态先行、实时注水、联合社交

GitHub release GitHub top language GitHub languages count

GrtBlog 是一个面向创作者的博客系统,以纯静态 HTML 分发实现极致首屏速度,通过 WebSocket 实现毫秒级实时更新,并内置联合社交协议让博客不再是孤岛。

联合协议仍在内测和修复中,将在 v2.1.0 正式发布。 旧版已归档至 https://github.com/grtsinry43/grtblog-legacy

特性

  • 极速加载 — 页面以纯静态 HTML 分发,首屏 < 0.5s,Go 后端宕机时 Nginx 仍可降级只读服务
  • 实时更新 — WebSocket 驱动的内容热更新,修改文章后读者无需刷新即可看到最新内容
  • 联合社交 — 自有联合协议 + ActivityPub 兼容,Mastodon 等 Fediverse 平台可关注你的博客
  • 丰富内容 — 文章、手记 (Moments)、思考 (Thinking)、友链、时间线,满足多种表达需求
  • 管理后台 — 美观且功能完备的 Vue 3 后台,Markdown 实时预览、评论管理、数据统计
  • 一键部署 — Docker Compose 一键启动,多架构镜像 (amd64/arm64) 自动打包,方便拉取

截图

image image image

架构

                      ┌──────────┐
                      │  用户/CDN │
                      └────┬─────┘
                           │
                      ┌────▼─────┐
                      │  Nginx   │  静态文件优先,回退到 SSR
                      └────┬─────┘
                           │
             ┌─────────────┼─────────────┐
             │             │             │
       ┌─────▼─────┐ ┌────▼────┐ ┌──────▼──────┐
       │ 静态 HTML  │ │ Go API  │ │  Admin SPA  │
       │           │ │  :8080  │ │  (Vue 3)    │
       └───────────┘ └────┬────┘ └─────────────┘
                          │
             ┌────────────┼────────────┐
             │            │            │
       ┌─────▼─────┐ ┌───▼───┐ ┌──────▼──────┐
       │ PostgreSQL │ │ Redis │ │  SvelteKit  │
       │            │ │       │ │  Renderer   │
       └────────────┘ └───────┘ └─────────────┘

三个平面:

平面 组件 职责
控制平面 Go (Fiber) API、ISR 调度、WebSocket Hub、联合协议、认证鉴权
渲染平面 SvelteKit SSR 渲染工厂,由 Go 后端驱动生成静态 HTML
数据平面 Nginx 静态文件分发、反向代理、降级只读网关

ISR (Incremental Static Regeneration): 内容变更时,Go 后端计算受影响路径 → 请求 SvelteKit 渲染 → 原子写入静态文件 → WebSocket 广播实时更新。

技术栈

技术
后端 Go 1.24+, Fiber, GORM, Goose, Casbin, JWT
前台 SvelteKit, Svelte 5 (Runes), Tailwind CSS v4, TanStack Query
后台 Vue 3.5, Naive UI, Tailwind CSS, Pinia, Vite
数据库 PostgreSQL 17
缓存 Redis 7
部署 Docker Compose, Nginx, GitHub Actions, GHCR / Docker Hub / CNB

快速开始

使用预构建的镜像部署(推荐)

一键安装(推荐):

bash <(curl -fsSL https://raw.githubusercontent.com/grtsinry43/grtblog/main/deploy/install.sh)
# 国内:
bash <(curl -fsSL https://cnb.cool/grtsinry43/grtblog/-/git/raw/main/deploy/install.sh)

脚本会自动检测环境、选择镜像源、生成密钥、下载配置并启动服务。

手动安装

首次启动会自动拉取镜像、运行数据库迁移。

  • 博客首页: http://your-server-ip
  • 管理后台: http://your-server-ip/admin/

本地部署

git clone https://github.com/grtsinry43/grtblog.git
# 国内加速:
# git clone https://cnb.cool/grtsinry43/grtblog.git
cd grtblog/deploy
cp .env.example .env
# 编辑 .env:设置密码和密钥(IMAGE_REPO_PREFIX 留空)

mkdir -p storage/html storage/uploads storage/geoip
docker compose up -d --build

详细部署说明见 部署文档

升级

# 修改 .env 中的 APP_VERSION,然后:
docker compose pull server renderer
docker compose up -d server renderer

Nginx 无需重启,自动发现新容器。

本地开发

# 1. 后端
cd server && cp .env.example .env && make migrate-up && make run   # :8080

# 2. 管理后台
cd admin && pnpm i && pnpm dev   # :5799

# 3. 前台
cd web && pnpm i && pnpm dev     # :5173

详细开发说明见 CONTRIBUTING.md

项目结构

grtblog-v2/
├── server/         # Go 后端(控制平面)
├── web/            # SvelteKit 前台(渲染平面)
├── admin/          # Vue 3 管理后台
├── shared/         # 前端共享代码(Markdown 组件等)
├── deploy/         # Docker Compose 部署配置
├── scripts/        # 工具脚本(发布、迁移等)
└── docs/           # 文档(VitePress)

文档

文档 说明
项目介绍 核心特性与定位
快速部署 部署步骤与配置
写作指南 内容创作与管理
个性化配置 站点设置
架构总览 系统设计与 ISR 机制
后端架构 Go 服务端 DDD 架构
前端架构 SvelteKit 前台设计
管理后台 Vue 3 Admin 开发

数据迁移(v1 -> v2)

已提供 API 迁移脚本:scripts/migrate-v1-to-v2.mjs 使用说明见:scripts/migrate-v1-to-v2.md

致谢

本项目的许多设计灵感与交互理念来源于 InneiShiro,包括布局、文章手记、创作律动等模块的视觉风格与体验设计均深受其启发,万分感谢 Innei 大佬为开源社区带来的优秀作品!

from  https://github.com/grtsinry43/grtblog

ArticleVault, 一个专业的网页文章转PDF的在线工具

 

ArticleVault

一个专业的网页文章转PDF在线工具,支持智能内容提取、可视化编辑和自定义样式。

✨ 功能特点

  • 🚀 快速转换 - 输入网址,一键转换,几秒钟内获得高质量PDF
  • 🧠 智能提取 - 使用Mozilla Readability算法自动识别和提取正文内容
  • ✏️ 可视化编辑 - 使用TipTap富文本编辑器,支持内容调整和样式自定义
  • 📄 高质量输出 - 使用html-pdf-node生成格式优美、内容清晰的PDF文档
  • 🔗 来源追踪 - 自动在PDF中添加原文链接和作者信息
  • 📱 响应式设计 - 支持桌面端和移动端使用
  • 💰 完全免费 - 无限制使用,无需注册
  • 🛡️ 安全可靠 - 完整的错误处理和数据验证

🛠 技术栈

  • 前端框架: Next.js 14 + TypeScript + TailwindCSS
  • 状态管理: Zustand
  • 富文本编辑器: TipTap
  • 后端服务: Next.js API Routes
  • 网页抓取: Playwright
  • 内容提取: Mozilla Readability + JSDOM
  • PDF生成: html-pdf-node
  • 错误处理: React Error Boundary
  • 部署: Vercel (推荐), Docker

快速开始

环境要求

  • Node.js 18+
  • npm 或 yarn

安装依赖

npm install

环境配置

复制 .env.local 文件并根据需要修改配置:

cp .env.local.example .env.local

启动开发服务器

npm run dev

访问 http://localhost:3000 查看应用。

构建生产版本

npm run build
npm start

项目结构

src/
├── app/                    # App Router (Next.js 13+)
├── components/             # React 组件
│   ├── layout/            # 布局组件
│   ├── ui/                # UI 组件
│   ├── seo/               # SEO 组件
│   └── editor/            # 编辑器组件
├── lib/                   # 工具函数
│   ├── playwright.ts      # 网页抓取
│   ├── readability.ts     # 内容提取
│   ├── pdf-generator.ts   # PDF 生成
│   └── utils.ts           # 通用工具
├── pages/                 # Pages Router
│   ├── api/               # API 路由
│   └── *.tsx              # 页面组件
├── types/                 # TypeScript 类型
├── styles/                # 样式文件
└── hooks/                 # React Hooks 
from   https://github.com/MichaelChan-hub/ArticleVault

launch-react-nextjs-tips

 

NextJS React Mastery Tutorial - Top 8 Patterns That Cover 95% of Use Cases

A progressive React tutorial designed for vibe coders and developers who want to master React fundamentals through practical examples.

📹 Full YouTube Guide: Youtube link

🚀 X Post: X link

💻 Launch Full Stack Product: Github Repo

☕️ Buy me a coffee: Cafe Latte

🤖️ Discord: Invite link

🎯 Why This Tutorial Exists

Many developers using AI coding tools like Cursor, Lovable, and v0 get stuck because they don't understand the fundamental React concepts. This tutorial teaches the 8 essential patterns that power 95% of React applications.

📚 What You'll Learn

🔥 Top 8 React Patterns

  1. useState + useEffect - State management & side effects
  2. Component Composition & Props - Reusable UI components
  3. Conditional Rendering - Loading states, error states, feature flags
  4. List Rendering & Keys - Displaying arrays efficiently
  5. Event Handling - User interactions (clicks, forms, keyboard)
  6. Form Handling & Validation - User input collection
  7. Context API - Global state management

🎬 TCustom Hooks - Reusable logic extractionutorial Structure (Perfect for 40-minute video)

Part 1: Foundation (12 minutes)

  • Pattern 1: useState/useEffect in Counter widget
  • Pattern 2: Side effects in Clock widget
  • Pattern 3: Props & composition in Button component

Part 2: Data Handling (12 minutes)

  • Pattern 4: Conditional rendering in UserProfile widget
  • Pattern 5: List rendering in TodoList widget
  • Pattern 6: Event handling in ContactForm widget

Part 3: Advanced Patterns (12 minutes)

  • Pattern 7: Context API in ThemeToggle widget
  • Pattern 8: Custom hooks in NotesWidget

Part 4: Integration (4 minutes)

  • Demo: All patterns working together
  • Next Steps: Building real applications

🚀 Getting Started

1. Install Dependencies

npm install

2. Start Development Server

npm run dev

3. Open Your Browser

Navigate to http://localhost:3000

from  https://github.com/ShenSeanChen/launch-react-nextjs-tips