这是一篇可直接放进仓库的全面教程(README/RELEASE 文档风格),覆盖项目功能目录说明开发启动Cloudflare Pages 打包Electron 打包用 Git Tag 触发 CI 发布以及最快验收 AppImage 的方法与注意事项。把它直接复制到 README.mdRELEASE.md 即可使用。


概览(功能一览)

MyCloudNote 是一个跨平台离线优先云端同步的笔记应用,面向桌面(Electron)与 Web(Next.js + Cloudflare)。核心功能:

  • 离线优先:本地使用 IndexedDB(Dexie)保存笔记,断网也能编辑。
  • 增量云同步:基于时间戳的增量同步机制,只同步自上次同步以来发生变化的数据,高效节省流量。
  • 无感同步与状态隔离:将编辑器输入状态与后台保存状态完全解耦,确保在频繁自动保存和离线同步时,用户的打字体验流畅无中断,彻底杜绝光标跳动或输入丢失问题。
  • 图片存储:图片上传到 Cloudflare R2。
  • 回收站与自动清理:软删除 + tombstone(硬删除标志),客户端自动清理超过阈值的数据。
  • 桌面客户端:通过 Electron 打包,应用核心通过内嵌本地 Cloudflare Pages 服务 (wrangler) 运行,确保离线体验与 Web 版本完全一致
  • 发布功能:将笔记渲染为 HTML,并通过服务端代理发布到个人博客(安全保存 API 密钥)。
  • 多端冲突合并策略:避免旧数据回插(ON CONFLICT + 时间与删除状态策略)。
  • 富文本与公式支持: 支持 Markdown 语法,并通过 MathJax 和 KaTeX 完美渲染复杂的数学公式。
  • 数据导入/导出: 支持将所有笔记数据导出为 JSON 格式进行本地备份,也可以从 JSON 文件恢复数据,确保数据安全可控。
  • 客户端全文搜索:基于 FlexSearch.js 在浏览器端为所有笔记建立实时索引,实现毫秒级的离线全文搜索、关键词高亮和相关性排序。

仓库结构与每个目录/文件的作用

(基于你给出的目录列举,下面按项写明用途没用或不存在的跳过)

.github/              # GitHub Actions workflows(CI/CD)Issue templates 等自动化相关配置
.vscode/              # 推荐的 VSCode workspace 配置(便于团队统一开发环境)
assets/               # 图标logoicon.icnsicon.ico 等打包资源,会被 electron-builder 引入
build-temp/           # 构建中间产物(可临时存放清理用)
electron/             # Electron 主进程代码(main.jsdatabase manageripc handlers)
migrations/           # 数据库迁移脚本(D1 / 本地 sqlite / dexie 的迁移 SQL)
public/               # Next.js 静态资源(manifestfavicon公共图片)
src/                  # 应用源码(Next.js pages / app router / components / lib 等)
.gitignore
.npmrc
cloudflare-env.d.ts   # Cloudflare 绑定类型声明(便于 TS 在 Cloudflare Worker/D1/R2 上编译时校验)
env.d.ts              # 项目级类型声明(例如 MyCloudflareEnv全局类型)
eslint.config.mjs
next.config.js
package-lock.json
package.json          # 脚本依赖electron-builder 配置build.extraResources(含 .vercel/outputassets)
postcss.config.mjs
README.md             # 项目说明(可替换为此文件)
schema.sql            # D1 / SQLite 初始化表结构(用于在 D1 控制台或 script 里建表)
tsconfig.json
wrangler.toml         # Wrangler/Cloudflare 本地与部署配置(bindingsr2d1 等)

快速开始(本地开发)

请先确保 Node.js >= 18,npm/yarn 安装正确。若要使用 wrangler,建议全局安装或使用 npx wrangler

       node版本:22.18.0(版本过高可能npm install 出错)

  1. 安装依赖
sudo apt install build-essential python3 make g++ libsqlite3-dev
npm ci

 解决 npm 安装 better-sqlite3 报错

make: g++: 没有那个文件或目录
make: *** [better_sqlite3.target.mk:121:Release/obj.target/better_sqlite3/src/better_sqlite3.o] 错误 127
npm ERR! gyp ERR! build error
npm ERR! gyp ERR! stack Error: `make` failed with exit code: 2
npm ERR! prebuild-install warn install Request timed out

问题原因

  1. 缺少 C++ 编译工具链

  2. 无法下载预编译包

解决方法(Kubuntu / Debian / Ubuntu 系)

sudo apt update
sudo apt install -y build-essential python3

 

  1. 运行 Next.js 开发服务器
npm run dev:next
# 或:next dev --port 3000
  1. 构建用于 Pages 的输出(用于 wrangler 本地预览或生产构建)
npm run build:web
# 会调用 @cloudflare/next-on-pages,输出 .vercel/output
  1. 本地用 wrangler 预览(推荐指向 .vercel/output,包含 worker)
# 推荐用 .vercel/output(包含 _worker.js),而不是只传 static
npx wrangler pages dev .vercel/output --port 8788 --local
  1. 启动 Electron(开发模式,脚本会并行启动 Next 并在可访问后打开 Electron)
npm run electron:dev

关键后端路由说明(常见实现建议)

/api/sync(云端同步)

  • 接受客户端的 notebooksnotes(或增量),数据库使用 INSERT ... ON CONFLICT ... DO UPDATE

  • 合并策略(优先级高 → 低):

    1. isDeleted 更大的优先(2 表示硬删除,1 软删,0 正常)
    2. isDeleted 相同,则 updatedAt 更晚的版本优先
  • 支持硬删除操作 action=permanently-delete,并记录 tombstone(防止其他端回插旧数据)。

必须:不要把 userId 写死。上线前用 session/jwt(推荐 next-auth)获取 userId 做多用户隔离。

/api/upload(图片/附件上传到 R2)

  • 在边缘/worker 中尽量使用 await file.arrayBuffer() 将文件读为 Uint8Array 后写入 R2,兼容性最佳。
  • 返回文件可访问 URL,客户端把 markdown 占位符替换成最终 URL。

/api/publish(发布到博客 — 服务端代理

  • 不要在前端保存 blog secret 并直接请求第三方博客。应该在服务端读取环境变量 BLOG_API_SECRET 并代替前端发起请求(防止密钥泄露)。

示例(Next.js Edge route):

// src/app/api/publish/route.ts
import { NextResponse } from 'next/server'
export const runtime = 'edge'
export async function POST(req: Request) {
  const { title contentHtml categoryId } = await req.json()
  const BLOG_API = process.env.BLOG_API_URL
  const BLOG_SECRET = process.env.BLOG_API_SECRET
  if (!BLOG_API || !BLOG_SECRET) return NextResponse.json({ error: 'not configured' } { status: 500 })

  const resp = await fetch(`${BLOG_API}/api/publish-note` {
    method: 'POST'
    headers: { 'Content-Type': 'application/json' }
    body: JSON.stringify({ title content: contentHtml categoryId secretKey: BLOG_SECRET })
  })
  const data = await resp.json()
  return NextResponse.json(data { status: resp.status })
}

Web 打包与部署(Cloudflare Pages / next-on-pages)

  1. 构建 Pages 输出:
npx @cloudflare/next-on-pages
# 生成 .vercel/output(含 static 和 worker)
  1. 本地用 wrangler 测试:
npx wrangler pages dev .vercel/output/static
  1. 部署到 Cloudflare Pages(推荐用 Git 集成):
  • 把仓库连接到 Cloudflare Pages(或在 CI 中调用 next-on-pages 并上传 .vercel/output)。
  • 在 Cloudflare Pages 控制台绑定 D1 / R2 / Secrets(environment variables)。

注意

  • .dev.vars 仅作为本地开发用,不要提交包含敏感密钥的文件到仓库。
  • Cloudflare Pages 的生产环境 secrets 必须在控制台里手动添加(Bindings / Environment variables)。

Electron 打包(桌面发行)

package.json 中需要包含 electron-builder 的 build 字段(示例):

"build": {
  "appId": "work.yysresume.note"
  "productName": "MyCloudNote"
  "asar": false
  "directories": { "output": "release" }
  "files": ["**/*"]
  "extraResources": [
    { "from": "assets/" "to": "assets/" }
    { "from": ".vercel/output" "to": ".vercel/output" }
  ]
  "win": { "target": "nsis" "icon": "assets/icon.ico" }
  "mac": { "target": "dmg" "icon": "assets/icon.icns" }
  "linux": { "target": ["AppImage""deb"] "icon": "assets/icons" }
}

构建命令

# 打包 Electron(会生成 release/*)
npm run electron:build

 

报错总结:

fedora linux 42 下构建 Electron/Next.js 常见报错与解决办法清单

1.Electron 构建失败(exit status 127libcrypt.so.1

日志的关键错误是:

error while loading shared libraries: libcrypt.so.1: cannot open shared object file: No such file or directory

这是因为 Electron-builder 打包 DEB 或 AppImage 时,依赖了系统的 libcrypt.so.1,但是 Fedora 42 默认使用 libxcrypt-compat 库名称不同或未安装。

解决方法:

安装缺失库

sudo dnf install libxcrypt-compat # fedora 系统

好的👌 我来帮你把 报错 1 + 报错 2 的完整解决方案写成一个一目了然的排查清单,今后直接照着执行就行:


WSL 下构建 Electron/Next.js 常见报错与解决办法清单

温馨提示:不要把项目放/mnt 目录下,速度更快


📌 报错 1

wsl: 检测到 localhost 代理配置,但未镜像到 WSL。
NAT 模式下的 WSL 不支持 localhost 代理。

✅ 解决方法:开启 WSL 镜像网络模式

  1. 在 Windows 用户目录下新建 .wslconfig
    路径:

    C:\Users\<你的用户名>\.wslconfig
    

    ⚠️ 文件名前面有点,没有扩展名

  2. 写入以下内容:

    [experimental]
    autoMemoryReclaim=gradual
    networkingMode=mirrored
    dnsTunneling=true
    firewall=true
    autoProxy=true
    
  3. 重启 WSL:

    wsl --shutdown
    

    然后重新进入 WSL。

✅ 作用:让 WSL 直接继承 Windows 网络和代理设置,避免 localhost 代理不可用。


📌 报错 2

⚡️ Unexpected error: {"cmd":"npm --version""stdout":"""stderr":""}
Executing: npm --version in D:\Nextcloud\go\note

✅ 原因

构建时调用了 Windows 的 Node/NPM(路径显示 D:\...),而不是 WSL 内的版本。

✅ 解决方法

  1. 检查当前 Node/npm 路径

    which node
    which npm
    
    • 如果是 /mnt/c/Program Files/... → ❌ 错误(Windows Node)
    • 如果是 /usr/bin/node/home/.../nvm/... → ✅ 正确(WSL Node)
  2. 安装 Node 到 WSL(推荐用 nvm):

    # 安装 nvm
    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
    source ~/.bashrc
    
    # 安装最新 LTS 版本
    nvm install --lts
    nvm use --lts
    
  3. 删除旧依赖并重新安装:

    rm -rf node_modules package-lock.json
    npm install
    
  4. 确保构建目录在 WSL 原生路径,不要直接在 /mnt/d/... 下操作。
    建议把代码放在 /home/用户名/... 目录再构建,避免路径兼容问题。


🎯 最佳实践总结

  • 报错 1 → 用 .wslconfig + networkingMode=mirrored 解决网络/代理问题。
  • 报错 2 → 强制使用 WSL 内安装的 Node/npm,不要用 Windows 的。
  • 依赖管理 → 每次切换环境(Windows/WSL)后,最好 rm -rf node_modules && npm install
  • 构建路径 → 代码尽量放在 /home/...,而不是 /mnt/c/...,避免奇怪权限和路径错误。

 

AppImage 打包工具下载超时

Get "https://github.com/electron-userland/electron-builder-binaries/...": connect: connection timed out
 

# 1. 设置 npm 国内镜像
npm config set registry https://registry.npmmirror.com
# 2. 设置 Electron 官方镜像(环境变量)
export ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/
# 3. 设置 better-sqlite3 预编译包镜像
export PREBUILD_INSTALL_MIRROR=https://npmmirror.com/mirrors/better-sqlite3/
# 4. 设置 electron-builder-binaries 镜像
export ELECTRON_BUILDER_BINARIES_MIRROR=https://npmmirror.com/mirrors/electron-builder-binaries/

 

主进程注意点

  • 在开发时用 npx wrangler pages dev .vercel/output 启动静态与 Worker,主进程需要兼容开发/打包路径(app.isPackaged + process.resourcesPath)。
  • 为了兼容 .vercel/output 有或无 _worker.js 的情况,建议在 startWranglerDev() 里优先用 .vercel/output,不存在时 fallback 到 .vercel/output/static

示例伪代码(startWranglerDev 的 args 选择):

const target = fs.existsSync(pagesDir) ? pagesDir : staticDir
const args = ['wrangler' 'pages' 'dev' target '--port' String(PORT) '--local']

Git Tag 管理与 CI(自动构建并发布 Desktop 版本)

推荐:用 Git Tag(例如 v1.0.0)触发 CI(GitHub Actions)来构建 Electron 并把产物上传到 GitHub Releases。

本地创建并推送 Tag

git tag -a v1.0.0 -m "Release v1.0.0"
git push origin v1.0.0

示例 GitHub Actions 工作流(.github/workflows/release-desktop.yml

name: Build & Release Desktop (AppImage)

on:
  push:
    tags:
      - 'v*'

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: ཐ'

      - name: Install
        run: npm ci

      - name: Build web for pages
        run: npm run build:web

      - name: Generate icons
        run: npm run icons:gen

      - name: Build Electron (Linux AppImage)
        env:
          CI: true
        run: npm run electron:build

      - name: Create GitHub Release
        id: create_release
        uses: softprops/action-gh-release@v1
        with:
          tag_name: ${{ github.ref_name }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Upload AppImage
        uses: softprops/action-gh-release@v1
        with:
          files: release/*.AppImage
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

说明:上面示例仅针对 Linux AppImage生产环境通常需要多平台构建(WindowsmacOS),可使用 matrix runner 或专门的构建服务(例如 electron-builder 的远程构建或使用 self-hosted runner)。


好的,你总结得非常到位!这确实是解决这个复杂项目打包问题的核心流程和关键点。

我来帮你把这些零散的要点整理成一份清晰完整的笔记,方便你以后查阅。


 Windows 应用打包终极指南

本指南提供了两种为 MyCloudNote 打包 Windows 桌面应用 (.exe) 的策略。根据在 Windows 11 + WSL (Ubuntu 24.04.1 LTS) 上的成功实践,强烈推荐方法 1

方法 1:在 WSL (Linux) 环境下直接打包 Windows 应用 (最推荐)

此方法将所有构建步骤统一在 WSL 环境中完成,流程统一,无需在不同操作系统间切换和传输文件,也是 CI/CD 自动化构建的理想选择。

环境准备:

  1. 一个配置好的 WSL2 环境 (推荐 Ubuntu 24.04 或更高版本)。
  2. 在 WSL 内部安装好 Node.js (推荐使用 nvm 管理)。
  3. 重要:将项目代码克隆或放置在 WSL 的原生文件系统下 (例如 /home/your-user/note),绝对不要放在 /mnt/c/ 等挂载的 Windows 盘符下,否则会遇到严重的性能和权限问题。

打包步骤:

第一步:安装项目基础及编译依赖

# 首先,安装 C++ 编译工具链和 better-sqlite3 所需的库
sudo apt update
sudo apt install -y build-essential python3 make g++ libsqlite3-dev

# 然后,使用 npm ci 安装项目依赖,速度更快且能保证版本一致性
npm ci

第二步:安装并完整配置 Wine (核心步骤)

Wine 是一个兼容层,能让 electron-builder 在 Linux 上运行 Windows 打包工具。一次正确的干净的安装可以避免绝大多数奇怪的错误。

  1. (可选) 彻底清理旧的 Wine 环境 (如果之前安装失败过)
     

    sudo apt-get purge --autoremove -y wine* libwine*
    sudo dpkg --remove-architecture i386
    rm -rf ~/.wine
    sudo apt-get update && sudo apt-get clean
    

    如果卸载不掉报错:dpkg: 错误: 无法移除体系结构 i386 ,当前它仍被数据库使用。参考:全面版Wine卸载教程(Ubuntu/Debian系适用)

  2. 干净地安装 Wine (包含 32 位支持,下载比较大,换国内源如阿里云的win10 linux 子系统, centos7, debian 10切换源)

    # 启用 32位 架构支持
    sudo dpkg --add-architecture i386
    sudo apt-get update
    
    # 安装 Wine 并确保所有推荐的依赖(含32位和64位核心库)都被安装
    sudo apt-get install -y --install-recommends wine
    
  3. 初始化 Wine 环境
    运行 winecfg 命令,它会自动创建并配置一个干净的 .wine 目录。

    winecfg
    

    在执行过程中,Wine 可能会弹窗提示您安装 "Wine Mono" 和 "Gecko" 两个包。请务必全部点击 "Install"。当看到一个标题为 "Wine configuration" 的窗口出现时,说明环境已准备就绪,可以直接关闭该窗口。

第三步:设置国内镜像源 (强烈推荐,避免下载超时)

electron-builder 在打包时需要从 GitHub 下载 nsis 等资源,设置镜像是最稳妥的办法。

# 在 WSL 终端中设置临时环境变量 (仅对当前终端窗口有效)
export ELECTRON_BUILDER_BINARIES_MIRROR=https://npmmirror.com/mirrors/electron-builder-binaries/

提示:为了永久生效,可以将这行命令添加到 ~/.bashrc~/.zshrc 文件的末尾。

第四步:执行打包命令

现在,一切准备就绪,直接运行打包脚本即可。

npm run electron:build:win

第五步:查找产物

打包成功后,您将在项目根目录下的 release/ 文件夹中找到最终生成的 MyCloudNote Setup 8.5.3.exe 安装包。


方法 2:跨平台分离构建 (备选方案)

当在 WSL 中配置 Wine 遇到难以解决的问题时,可以使用此备用方案。它将前端构建和桌面打包分离在两个最适合它们的平台进行。

 

第一部分:核心构建策略(两步走)

由于 npm run build:web (使用 @cloudflare/next-on-pages) 在 Linux 环境下兼容性最好,而 .exe 打包必须在 Windows 上进行,因此我们采用跨平台分离构建的策略。

步骤 1:在 Linux (推荐使用 WSL) 构建前端

  1. 目的:生成纯净独立的前端静态资源。
  2. 环境:准备一个 Linux 环境(或 Windows Subsystem for Linux),克隆项目代码。
  3. 命令
    # 安装依赖
    npm install
    # 执行构建,生成 .vercel/output 文件夹
    npm run build:web
    
  4. 产物:将生成的 .vercel/output 文件夹完整复制出来,准备传送到 Windows 环境,最好压缩复制过去 zip -r output.zip output。

💡 技巧:建议为 Linux 和 Windows 准备两份独立的项目文件夹,避免因 node_modules 平台差异导致需要频繁重装依赖。

步骤 2:在 Windows 上打包 Electron 应用

  1. 准备:在 Windows 的项目文件夹中,确保代码是最新版本,并将上一步生成的 .vercel/output 文件夹放入项目根目录。
  2. 命令
    # 安装 Windows 平台的依赖
    npm install
    # 执行打包命令(使用 cross-env 保证环境变量的兼容性)
    npx cross-env NODE_ENV=production electron-builder --win
    

win10报错:

ERROR: Cannot create symbolic link  #客户端没有所需的权限

用管理员运行cmd或powershell


第二部分:最关键的 package.json build 配置

错误的配置是导致体积过大文件缺失应用崩溃的根源。以下是经过调试后的最佳配置:

"build": {
    "appId": "work.yysresume.note"
    "productName": "MyCloudNote"
    "asar": true // 开启 asar,提升读取性能
    "files": [
        // ✅ 只包含应用逻辑的核心文件
        "electron/**/*"
        "package.json"
    ]
    "asarUnpack": [
        // ✅ 必须解包原生依赖,否则无法调用
        "**/node_modules/better-sqlite3/**/*"
    ]
    "extraResources": [
        // ✅ 将所有外部资源明确地复制到打包目录
        {
            "from": ".vercel/output"  // 前端构建产物
            "to": "app/.vercel/output"
        }
        {
            "from": "assets"          // 图标等静态资源
            "to": "app/assets"
        }
        {
            "from": "wrangler.toml"   // Cloudflare 配置,解决 nodejs_compat 问题
            "to": "app/wrangler.toml"
        }
        {
            "from": ".dev.vars"       // (如果需要)环境变量文件
            "to": "app/.dev.vars"
        }
    ]
    // ... win mac linux 的具体配置 ...
}

第三部分:常见错误与解决方案

错误 1:gyp ERR! find VS ... You need to install Visual Studio

  • 原因:这是打包过程中最常见的错误。electron-builder 尝试为 Electron 重新编译原生依赖(如 better-sqlite3),但你的 Windows 系统缺少 C++ 编译工具链。
  • 解决方案 (推荐):安装 Visual Studio Community,并在安装时勾选 “使用 C++ 的桌面开发” 工作负载。
  • 备选方案 (网络原因):有时是无法下载预编译好的二进制文件导致的回退编译。可以尝试为 npm 设置代理来解决网络问题。

错误 2:Error: Cannot find module './database'.../assets/icon.png'

  • 原因:应用启动了,但代码中 require() 的本地模块或文件找不到了。这是因为 package.jsonbuild 配置不正确,没有将这些文件打包进去。
  • 解决方案:检查 filesextraResources 配置。
    • 应用逻辑代码 (如 database 文件夹) 应加入 files
    • 外部资源 (如 assets 文件夹) 应加入 extraResources

错误 3:Node.JS Compatibility Error (no nodejs_compat flag set)

  • 原因:应用内部的 miniflare 本地服务器需要 Node.js 兼容模式才能运行 Next.js,但它没有找到配置文件。
  • 解决方案:确保 wrangler.toml 文件被正确打包。在 build.extraResources 中添加 { "from": "wrangler.toml" "to": "app/wrangler.toml" }

错误 4:打包体积过大 (比 CI/CD 环境大一倍)

  • 原因:通常是 files 配置为 "**/*" 导致的。这个设置会把项目目录下所有文件,包括 .git源代码所有 node_modules (含开发依赖) 全部打包。
  • 解决方案:采用本笔记第二部分中推荐的精确 filesextraResources 配置,只打包运行时必需的文件。

错误 5:electron-builder 打包时资源下载超时失败

在使用 electron-builder 打包 Windows 应用(执行命令 npx cross-env NODE_ENV=production electron-builder --win)时,出现如下错误:

⨯ Get "https://github.com/electron-userland/electron-builder-binaries/releases/download/nsis-resources-3.4.1/nsis-resources-3.4.1.7z": read tcp ...: wsarecv: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.  

⨯ Get "https://github.com/.../winCodeSign-2.6.0.7z": read tcp ...: wsarecv: A connection attempt failed...

 

最终提示 app-builder.exe process failed,打包中断。

原因分析

该错误的核心是 网络连接问题electron-builder 打包时需要从 GitHub 下载 nsis-resources 等依赖资源(NSIS 是 Windows 安装包制作工具),但由于 GitHub 在国内的网络访问不稳定(如链路拥堵、超时等),导致资源下载失败,进而中断打包流程。

解决办法

方法 1解决方案 (最推荐 - 镜像源法):
直接告诉构建工具使用国内的 npmmirror 镜像,无需手动下载文件,也无需挂代理。

在 PowerShell 中执行以下:

$env:ELECTRON_BUILDER_BINARIES_MIRROR = "https://npmmirror.com/mirrors/electron-builder-binaries/"

或者cmd中执行

set ELECTRON_BUILDER_BINARIES_MIRROR=https://npmmirror.com/mirrors/electron-builder-binaries/

方法 2:手动下载资源并放入缓存目录

适用于能通过浏览器 / 下载工具成功获取资源的场景。

  1. 获取资源链接从报错信息中复制需要下载的资源链接(如本例中的 https://github.com/electron-userland/electron-builder-binaries/releases/download/nsis-resources-3.4.1/nsis-resources-3.4.1.7z)。

  2. 手动下载文件用浏览器或下载工具(可搭配代理)下载该文件,确保文件完整(无损坏)。

  3. 放入缓存目录将下载的 nsis-resources-3.4.1.7z 放入 electron-builder 的缓存目录,路径为:

    C:\Users\[你的用户名]\AppData\Local\electron-builder\Cache\nsis-resources\3.4.1\  
    

    (若目录不存在,手动创建对应的文件夹层级,例如 nsis-resources\3.4.1)。

  4. 重新打包再次执行打包命令,electron-builder 会优先读取缓存文件,无需重复下载:

    npx cross-env NODE_ENV=production electron-builder --win  
    

方法 3:通过临时代理解决网络问题

若镜像源未覆盖所需资源,可通过临时代理访问 GitHub。

  1. 在 CMD 中设置临时代理假设代理端口为 10808(根据实际代理工具配置调整),执行以下命令(临时生效):

    cmd

    # 若为 Socks5 代理  
    set http_proxy=socks5://127.0.0.1:10808  
    set https_proxy=socks5://127.0.0.1:10808  
    
    # 若为 HTTP 代理  
    set http_proxy=http://127.0.0.1:10808  
    set https_proxy=http://127.0.0.1:10808  
    
  2. 重新打包代理生效后,执行打包命令,通过代理访问 GitHub 下载资源:

    cmd

    npx cross-env NODE_ENV=production electron-builder --win  
    

通过以上方法,可解决 electron-builder 因网络问题导致的资源下载失败,确保打包流程正常执行。

 

第四部分:写个快捷打开app的bat文件


注意AppPath不是固定的

@echo off
rem ===========================
rem check_mycloudnote.bat
rem 功能:如果 MyCloudNote.exe 已运行 -> 打开 URL
rem       否则 -> 启动指定应用程序(找不到则提示)
rem ===========================

setlocal

rem --- 可修改的配置 ---
set "ProcessName=MyCloudNote.exe"
set "URL=http://localhost:8788/"
set "AppPath=C:\Users\yys\AppData\Local\Programs\my-cloud-note\MyCloudNote.exe"
rem ------------------------

rem 检查进程是否存在
tasklist /FI "IMAGENAME eq %ProcessName%" 2>nul | find /I "%ProcessName%" >nul
if %ERRORLEVEL%==0 (
    echo %ProcessName% 已在运行,打开 %URL% ...
    start "" "%URL%"
    goto :EOF
)

echo %ProcessName% 未在运行,尝试启动程序...

rem 如果程序存在则启动
if exist "%AppPath%" (
    echo 启动: %AppPath%
    start "" "%AppPath%"
    goto :EOF
) else (
    echo 错误:找不到应用程序:
    echo    %AppPath%
    echo 请检查路径是否正确或手动启动程序。
    pause
)

endlocal
exit /b 0

第五部分:其他电脑运行需要环境

AppImage:快速测试与解包运行(最快验收方法)

当你在本地或 CI 里拿到 MyCloudNote-<ver>.AppImage,有两种快速方法测试。

方式 A:直接运行(最快)

chmod +x ./MyCloudNote-1.0.0.AppImage
./MyCloudNote-1.0.0.AppImage

直接运行会自动挂载并执行 AppImage 内的程序。若遇到 sandbox 问题或在容器环境,可配合 --no-sandbox 参数(仅用于测试):

./MyCloudNote-1.0.0.AppImage --no-sandbox

方式 B:解包并运行(便于调试内部文件)

# 解包./MyCloudNote-1.0.0.AppImage --appimage-extract
./MyCloudNote-*.AppImage --appimage-extract

# 进入解包目录
cd squashfs-root/

# 查找可执行文件
find . -type f -executable -maxdepth 3

# 找到可执行后运行(示例)
./my-cloud-note --no-sandbox
# 或
./squashfs-root/my-cloud-note --no-sandbox

./squashfs-root/my-cloud-note: error while loading shared libraries: libnss3.so: cannot open shared object file: No such file or directory

这个错误表明你的 Linux 系统缺少 libnss3 库。这是 Electron 应用(以及 Chrome/Chromium)运行所必须的基础依赖库。

根据你的系统环境(通常是 Ubuntu/Debian 或基于它们的发行版,比如 WSL),请运行以下命令进行安装。

1. 针对 Ubuntu / Debian / Deepin / Kali

打开终端,运行:

sudo apt-get update
sudo apt-get install libnss3

如果安装后仍然报错提示缺少其他库(例如 libatklibdrm 等),建议直接安装 Electron 运行所需的完整依赖包

sudo apt-get install libnss3 libatk1.0-0 libatk-bridge2.0-0 libcups2 libgbm1 libasound2 libpangocairo-1.0-0 libxss1 libgtk-3-0

2. 针对 CentOS / Fedora / RedHat

sudo dnf install nss

3. 针对 Arch Linux / Manjaro

sudo pacman -S nss

为什么会发生这个错误?

你正在运行的程序(my-cloud-note)是基于 Electron 开发的。虽然 AppImage 或打包后的 Linux 应用通常包含了很多依赖,但它们通常默认系统已经安装了基础的图形界面库(如 GTKNSSALSA 音频库等)。在一个纯净的 Linux 环境(尤其是服务器版或 WSL)中,这些库通常默认没有安装。

安装完 libnss3 后,再次尝试运行你的命令即可:

./squashfs-root/my-cloud-note --no-sandbox

 

查看 .asar 文件内容

在 Node.js 环境中查看 .asar 文件内容,你可以使用官方提供的 asar 工具。这是 Electron 团队开发的专门用于处理 .asar 归档文件的工具。

以下是具体步骤:

  1. 首先安装 asar 工具:
npm install -g asar
  1. 查看 .asar 文件内容列表:
asar list app.asar
  1. 如果需要提取文件内容到指定目录:
asar extract app.asar ./extracted

注意事项

  • --no-sandbox 会降低安全性,只在测试或 CI 中临时使用。在生产或用户发布版中尽量避免。
  • AppImage 的可执行文件位置会因打包配置差异而不同,请按实际解包结果运行。
  • 确保操作系统可运行 Electron 所需的依赖(libgtklibnsslibxss 等)。

 

核心机制:增量同步工作原理

本应用的核心是高效的增量同步,它避免了每次都上传全部数据,极大提升了同步速度并节省了网络资源。其工作流程如下:

  1. 最后同步时间戳 (lastSyncTimestamp):

    • 客户端在本地(如 localStorage)维护一个 lastSyncTimestamp,记录上次与服务器成功同步的时间。

    • 如果是首次同步,该时间戳为一个极早的日期(如 1970-01-01)。

  2. 客户端推送变更 (Client Push):

    • 当用户触发同步时,客户端会查询本地 IndexedDB 中所有 updatedAt 大于 lastSyncTimestamp 的记录(包括新建、修改、软删除isDeleted: 1、待永久删除isDeleted: 2的条目)。

    • 客户端将这些增量数据连同 lastSyncTimestamp 一起 POST 到 /api/sync。

  3. 服务端处理与合并 (Server Reconciliation):

    • 服务器接收到客户端的增量数据。

    • 使用 INSERT ... ON CONFLICT ... DO UPDATE 语句将这些变更合并到 D1 数据库中。合并规则严格遵循我们定义的冲突解决策略(isDeleted 优先,其次 updatedAt)。

    • 如果收到 isDeleted: 2 的条目,服务器会将其从主数据表中永久删除,并在 Tombstones 表中创建一条记录。

  4. 服务端返回变更 (Server Pull):

    • 服务器记录下当前的时间作为本次同步的 newSyncTimestamp。

    • 服务器查询 D1 数据库中所有 updatedAt 大于客户端传来的 lastSyncTimestamp 的记录(这包含了其他设备在此期间同步的变更)。

    • 服务器同时查询 Tombstones 表中 deletedAt 大于 lastSyncTimestamp 的记录。

    • 服务器将这些增量数据需要永久删除的ID列表、以及 newSyncTimestamp 一起返回给客户端。

  5. 客户端应用变更 (Client Apply):

    • 客户端收到服务器的响应。

    • 在一个原子事务中,先处理永久删除的ID,然后使用智能合并逻辑(smartMerge)将服务器返回的增量数据应用到本地 IndexedDB。

    • 同步成功后,客户端将本地的 lastSyncTimestamp 更新为服务器返回的 newSyncTimestamp。

这个闭环确保了数据在多端之间以最小的代价保持最终一致。

如何验证增量同步(查看网络负载)

你可以通过浏览器的开发者工具直观地验证增量同步是否正常工作。

  1. 打开开发者工具: 在应用页面按 F12 或 Ctrl+Shift+I,切换到 网络(Network) 面板。

  2. 首次同步 (全量基准):

    • 清除 localStorage 中的 lastSyncTimestamp 并刷新页面。

    • 触发一次同步。你会看到对 /api/sync 的请求,其**载荷(Payload)**中 changes 包含了本地所有数据。这是正常的基准同步。

  3. 无变更同步 (最小负载):

    • 不做任何修改,再次触发同步。

    • 查看新的 /api/sync 请求,你会发现其载荷中 changes 的值为 { notebooks: [], notes: [] }。这证明了在无数据变更时,客户端没有发送任何冗余数据。

  4. 少量变更同步 (增量负载):

    • 只修改一篇笔记的标题,再次触发同步。

    • 查看最新的 /api/sync 请求,你会发现其载荷中 changes.notes 数组里仅包含你刚刚修改的那一篇笔记

通过观察这三次同步请求载荷的变化,你就可以 100% 确定你的应用正在执行高效的增量同步。

 


更换favicon.ico 

 在src/app/ 目录,里面favicon.ico 替换即可


安全建议(必须阅读)

  1. 密钥管理:所有密钥(D1R2博客 API secret)不要写在前端或提交到仓库。使用 Cloudflare Pages 的 Secrets / Environment bindings 或 CI 的 Secrets 管理。
  2. 鉴权:服务端 /api/sync/api/publish 必须验证用户身份(推荐 next-auth / JWT)。切勿把 userId = "test-user" 留到生产。
  3. XSS 防护:Markdown 转 HTML 后务必做 sanitize(例如 DOMPurify),尤其是公开发布到博客或呈现在 Web 的 HTML。
  4. Tombstone 清理策略:在服务端或周期任务中清理 isDeleted=2 且超过阈值(例如 90 天)的记录,避免 D1 数据无限膨胀。
  5. 速率限制与滥用防护:对上传接口与发布接口做速率限制与鉴权,避免滥用。
  6. Electron 沙箱:生产环境尽量保持 Electron 的 sandbox 安全策略,调试时临时使用 --no-sandbox

Debug & 常见问题排查清单

  • API 404(本地 wrangler 调试):优先把 wrangler pages dev 指向 .vercel/output(包含 _worker.js)。若只指 static,静态页面能看,但 API/Workers 可能不可用。
  • Electron 打包后找不到资源:确认 extraResources 包含 .vercel/outputassets,并在主进程用 process.resourcesPath 获取路径。
  • 图片上传报错(e.getReader is not a function):改用 file.arrayBuffer() 读取文件并传给 R2。
  • Markdown 发布后 XSS 报告:在服务器端或博客端做严格 sanitize。
  • 同步冲突(数据被旧版本覆盖):日志里打印每次 db.batch 的 affected rows,并确认 ON CONFLICT 语句逻辑(以 isDeletedupdatedAt 为合并权重)。

发布前核查清单(Release checklist)

  • 移除客户端代码里不当的 export const runtime = 'edge'(客户端组件不应声明 runtime)。
  • 接入用户鉴权,不再使用硬编码 userId
  • 将博客发布改为服务端代理路由(如 /api/publish),并在服务端持有密钥。
  • 在 Cloudflare Pages 控制台绑定 D1 / R2 / Secrets。
  • 确保 .vercel/output(含 worker)已包含在 electron 的 extraResources 并会打包进 release。
  • 服务端对 HTML 输出做 sanitize。
  • 在 CI 中为 Tag 推送配好 Release workflow 并测试自动上传产物。
  • 确认 AppImage 在目标 Linux 发行版上可本地运行。

待解决问题

  • 打包后给其他电脑安装需要安装nodejs才能运行

结语

本文档提供了从功能目录开发Web 打包Electron 打包CI 发布到最快验收 AppImage 的完整流程与实践注意点。
如果你希望,我可以基于你当前仓库自动生成以下任意一项并给出完整文件内容供你复制粘贴:

  1. .github/workflows/release-desktop.yml 完整可运行版(默认为产出 AppImage 并上传 Release)。
  2. src/app/api/publish/route.ts(服务端代理示例)。
  3. Electron startWranglerDev() 的 fallback 版本(自动选择 .vercel/outputstatic)。
  4. 一个简明的 RELEASE.md(本文即可转为该文件)。