Norman Wang

Front-end / Electronjs Development Engineer

Hugo 博客迁移实录:从 0.111.3 到 0.164.0

我的旧博客基于 Hugo 0.111.3 + hugo-coder 主题运行了三年多,最近升级到 Hugo 0.164.0 并换用了 PaperMod 主题。整个过程比预想的顺利,但还是踩了几个坑,记录一下供有类似需求的朋友参考。 迁移背景 旧博客 新博客 Hugo 版本 0.111.3 0.164.0 主题 hugo-coder PaperMod 配置文件 config.toml hugo.yaml 域名 blog.wangyu.link wangyu.link 两个版本隔了约 50 个 minor 版本,配置格式从 TOML 切换到 YAML,主题也完全不同。迁移的核心工作就是三个:内容搬迁、配置映射、兼容性处理。 内容搬迁 这一步最简单——直接把 content/ 目录下的所有 markdown 文件复制过去就行。 cp -r personal-blog/content/* NormanBlog/content/ 我的旧博客有 90+ 篇文章和 3 个独立页面(About、Projects、List),frontmatter 都是标准的 Hugo 格式,不需要任何修改就能被新版本识别。 静态资源同理: cp -r personal-blog/static/* NormanBlog/static/ favicon、avatar、site.webmanifest 等直接搬过去即可。 配置映射:从 hugo-coder 到 PaperMod 这才是迁移的重头戏。两个主题的参数体系完全不同,需要逐一对照映射。 基本配置 # hugo.yaml (PaperMod) baseURL: https://wangyu.link/ locale: en # Hugo 0.158+ 废弃了 languageCode title: Norman's Blog theme: ["PaperMod"] paginate: 20 旧配置中的 languagecode = "en" 在 Hugo 0.158.0 之后被废弃了,需要改成 locale: en。如果继续用 languageCode,构建不会失败,但会一直弹出 deprecation 警告。 ...

July 18, 2026 · 2 min · 380 words · Norman Wang

婚礼邀请函微信小程序,使用微信云开发,不需要域名和服务器

前提 申请一个小程序账号 入门 cloneWedding-invitation,并通过微信开发工具导入,导入时填入你的appid 开通云开发(选择免费套餐即可) 新建四个集合,集合名分别是bless photos comment invitation user 打开sql文件夹,按照集合名称导入数据 修改根目录app.js文件里面的env字段为你的云开发环境id wx.cloud.init({ env: '' }) 右键点击functions选择当前云开发环境,在get_openId右键选第三项上传并部署:云端安装依赖 重新编译 数据格式说明 bless是好友祝福页面的数据 comment数据表是留言评论页面的数据 photos数据表是甜蜜相册页面数据 user表是用户数据 invitation 数据表(只有一条数据)是基本信息,此数据用于小程序的首页和地图页面,数据格式如下 { // 新郎姓名 "boy": "周杰伦", // 公历结婚日期 "date": "2020-10-01 12:00:00", // 新娘姓名 "girl": "昆凌", // 结婚地点(酒店教堂名称即可) "hotel": "英国约克郡塞尔比教堂", // 农历结婚日期 "lunar": "庚子年八月十五", // 背景音乐url "music": "https://6465-dev-1goaza5i509ecff5-1258198969.tcb.qcloud.la/audio/ido.mp3?sign=f186b54afeca081690c8c03c2573521c&t=1601797034", // 背景音乐是否自动播放 "autoPlay": false, // 首页背景大图 "image": "https://6465-dev-1goaza5i509ecff5-1258198969.tcb.qcloud.la/photos/cover.jpeg?sign=5ebe072ba028b0a2da8aa54fb82586a0&t=1601799069", // 结婚地点地址 "address": "英国约克郡塞尔比镇", // 结婚地点经纬度 "latitude": 38.446324, "longitude": 112.735426, // 新郎&新娘手机号 "boyPhone": "13412344321", "girlPhone": "13698766789" } 注意⚠️⚠️⚠️ 如遇到小程序页面显示异常,请关闭ES6转ES5功能 由于小程序用户头像昵称获取规则调整现在已经不能通过调用wx.getUserProfile直接获取用户昵称和头像,所以Wedding-invitation按照官方要求修改,用户在首次使用祝福和评论功能时会跳转到填写用户昵称和头像的页面,引导用户填写内容。 需要把云开发的数据库所有表 和 存储 修改为自定义安全规则。规则如下: ...

April 20, 2023 · 1 min · 84 words · Norman Wang

Nodejs使用protobuf格式进行前后端数据交互

Protocol Buffers(簡稱:ProtoBuf)是一種開源跨平台的序列化資料結構的協定。其對於儲存資料或在網絡上進行通訊的程式是很有用的。這個方法包含一個介面描述語言,描述一些資料結構,並提供程式工具根據這些描述產生程式碼,這些代碼將用來生成或解析代表這些數據結構的位元組流。 ProtoBuf类似于json xml是一种网络数据交换的新格式。以下例子使用nodejs作为后端,原生html+js作为前端,使用protobufjs这个纯js库处理ProtoBuf。其中后端使用proto文件作为消息类,前端使用json对象作为消息类。 后端 const express = require('express') const protobuf = require('protobufjs') const path = require('path') const app = express() const port = 3000 const htmlPath = path.join(__dirname, './index.html') const protoPath = path.join(__dirname, './awesome.proto') const payload = { name: 'lihua', age: 28, address: '上海市浦东新区纳贤路701号' } app.get('/', (req, res) => { res.sendFile(htmlPath) }) app.get('/api', async (req, res) => { const root = await protobuf.load(protoPath) const AwesomeMessage = root.lookupType("awesomepackage.AwesomeMessage") const errMsg = AwesomeMessage.verify(payload); if (errMsg) throw Error(errMsg); const message = AwesomeMessage.create(payload); const buffer = AwesomeMessage.encode(message).finish(); res.setHeader('content-type', 'application/x-protobuf') res.send(buffer); }) app.listen(port, () => { console.log(`Example app listening on port ${port}`) }) awesome.proto ...

April 11, 2023 · 2 min · 248 words · Norman Wang

[转]ChatGPT镜像站点分享

Free ChatGPT Site List 这儿为你准备了众多免费好用的ChatGPT镜像站点 发布网站: https://cc.ai55.cc/ (😃敬请收藏和分享) 分享站点、站点失效、标注错误,请🌺点此🌺告诉我 🔗支持我,给你更长久的陪伴:【🧡赞赏🧡】 👆http://chatgpt3.icu [ad.] 站点列表 ⭐:使用稳定,不受限,推荐 🔑:需要进行登录或需要密码 ⛔:有限地使用次数或字数,需提供key或进行充值进行服务升级 [⭐⭐] https://chatbot.theb.ai/ [🔑⭐] https://poe.com/ [⭐⭐] https://chat9.yqcloud.top/ [⭐⭐] https://ai.bo-e.com/ [⭐⭐] https://chat4.xeasy.me/ [⭐⭐] http://ai.usesless.com/ [⭐⭐] https://gpt.intercat.cn/ [⭐⭐] https://chat.extnav.com/ [⭐⭐] http://openmao.com/ [⭐⭐] https://chat3.geekr.dev [⭐⭐] https://www.aiai.zone [⭐⭐] https://chat3.xeasy.me [⭐⭐] https://chat.wobcw.com/ [⭐⭐] https://qachat.cc [⭐⭐] https://ai.ls/ [⭐⭐] https://desk.im/ https://94gpt.com/ https://chat.wuguokai.cn/s/chatgpt https://chat1.wuguokai.top/s/chatgpt https://www.teach-anything.com/ https://ai117.com/ http://www.tdchat.vip/ https://ai.ci [密码:openai] http://43.156.110.219:3002/ https://trychatgp.com/ https://beta.character.ai/ https://xc.com/ https://gpt.getshare.net/ http://175.178.88.119/ http://ai.jjzn.top/ https://openprompt.co/ChatGPT https://www.ftcl.store/ http://chat.livepo.top/ [⛔] http://gitopenchina.gitee.io/gpt [🔑] https://chat.eaten.fun/ [⛔] https://chatforai.com/ [🔑] https://chat.paoying.net/ [⛔] https://ai.okmiku.com/chat/ [🔑] https://www.typingmind.com/ [⛔] https://ai.yiios.com/ [🔑] https://www.ohmygpt.com/ [🔑] https://chat.wxredcover.cn/ [⛔] https://chat.51buygpt.com/ [⛔] https://chat35.com/ [⛔] https://chatcat.pages.dev/ [🔑] https://www.bz1y.cn/ ...

March 27, 2023 · 2 min · 238 words · Norman Wang

go语言学习 - 结构体

结构体声明 结构体可以理解为多种类型的集合,是一种自己定义的复杂类型 package main import "fmt" type Stduent struct { Name string Age int16 Score int16 Address string } func main() {} 结构体使用 package main import "fmt" type Stduent struct { Name string Age int16 Score int16 Address string } func main() { // 先声明再赋值 var norman Stduent norman.Name = "norman" norman.Age = 34 norman.Score = 99 // 声明并赋值 wangyu := Stduent{Name: "wangyu", Age: 23, Score: 89, Address: "上海市松江区"} } 结构体的方法 一个结构体的专属方法,可以实现面向对象操作 ...

March 7, 2023 · 2 min · 251 words · Norman Wang

go语言学习 - map数据类型

map声明及赋值 map是一种key value类型数据,无序数据 // 1.只声明,内容为空,不能赋值 var data map[string]string // 2.make声明,有默认值 var data = make(map[string]string) // 3.声明并赋值 var data = map[string]string{"name": "wangyu", "age": "12", "like": "ba"} // 4.赋值 data["name"] = "wangyu" map增删改查 var data = make(map[string]string) // 增加/修改 data["name"] = "wangyu" // 查询 fmt.Println(data["name"]) // 删除 delete(data, "name") // map[] fmt.Println(data) map遍历 // 创建了一个map数据,key为string,value为切片。双层循环遍历数据 var data = make(map[string][]string) data["山西"] = []string{"大同", "忻州", "太原"} data["北京"] = []string{"朝阳", "海淀", "通州"} data["上海"] = []string{"静安", "浦东", "黄埔"} data["陕西"] = []string{"西安", "咸阳", "宝鸡"} // fmt.Println(data["山西"][2]) for province, city := range data { for index, item := range city { fmt.Println(index, "--", item, "--", province) } }

March 3, 2023 · 1 min · 100 words · Norman Wang

go语言学习 - 切片扩容、增加、插入、删除

切片增加 使用append方法可以给切片后面追加数据,返回新切片; 容量够追加 如果一个切片数据,足够容纳追加的数据,那么不会新开辟内存 package main import "fmt" func main() { // make函数创建切片make(类型,长度,容量) var slice = make([]int, 5, 10) s1 := append(slice, 2, 3) fmt.Println(slice) fmt.Println(s1) // 修改第二个数据 s1[1] = 111 // [0 111 0 0 0] fmt.Println(slice) // [0 111 0 0 0 2 3] fmt.Println(s1) } 容量不够追加 切片容量不够追加,会创建新变量并2倍扩容 package main import "fmt" func main() { var slice = make([]int, 5, 10) s1 := append(slice, 2, 3, 4, 5, 6, 7) s1[1] = 111 // 【0 0 0 0 0】 fmt.Println(slice) // [0 111 0 0 0 555 3 4 5 6 7] fmt.Println(s1) } ...

March 1, 2023 · 1 min · 146 words · Norman Wang

go语言学习 - 切片存储原理

从数组到切片 数组通过切片操作可以生成切片,切片是引用数据类型,源数组改变,切片就会变。切片在内存中包含三个数据。开始地址、长度、容量;容量是切片开始位置到数组最后的长度 package main import "fmt" func main() { var a = [5]int{1, 2, 3, 4, 5} // 生成切片slice,slice全切 var slice = a[:] fmt.Println(slice) // 切片slice也可以进行再切片,由于是引用数据,其实就是对源数据a进行切片 var newSlice = slice[1:3] fmt.Println(newSlice) // 修改newSlice[1]其实就是修改a[2] newSlice[1] = 233 // 下面数据都发生了变化 fmt.Println(a) fmt.Println(slice) fmt.Println(newSlice) var b = [5]int{1, 2, 3, 4, 5} var c = b[1:3] // cap查看容量 fmt.Println(len(c), cap(c)) } ...

February 27, 2023 · 1 min · 71 words · Norman Wang

go语言学习 - 数组

数组声明 数组就是数据的集合,声明时候需要指定数据长度和类型,之后不能修改 var arr [5]int16 // 打印 [0,0,0,0,0] 默认值 fmt.Println(arr) 数组在内存中是多个连续的地址 数组赋值 // 声明后赋值,索引操作 var arr [5]int16 arr[0] = 10 fmt.Println(arr) // 声明并赋值 var arr1 = [5]string{"a", "s", "d", "f", "g"} fmt.Println(arr1) // ...会自动匹配长度 var arr2 = [...]string{"a", "s", "d", "f", "g", "p"} fmt.Println(arr1) // 给特定索引赋值 var arr3 = [...]string{0: "we", 2: "are", 4: "young"} fmt.Println(arr1) 数组切片 数组[start:end],取前不取后 var arr4 = [5]int16{1, 2, 3, 4, 5} s := arr4[1:3] // [2,3] fmt.Println(s) s := arr4[:3] // [1,2,3] fmt.Println(s) s := arr4[1:] // [2,3,4,5] fmt.Println(s) 数组遍历 数组遍历推荐用range函数 ...

February 26, 2023 · 1 min · 112 words · Norman Wang

go语言学习 - new函数

前置知识 go中有两大类数据类型基本数据类型 引用数据类型。基本数据类型包括整型、浮点型、布尔型、数组、结构体,它们内存中都存储的具体值,所以也叫值类型。引用数据类型存储的是数据引用,包括指针、切片、map、channel,引用类型为赋值时没有开辟内存空间,既没有默认值. new函数 new函数开辟内存空间,并把其地址赋值给相应的指针 package main import "fmt" func main() { var a *int a = new(int) fmt.Println(*a) *a = 10 fmt.Println(*a) fmt.Println(a) }

February 25, 2023 · 1 min · 25 words · Norman Wang