作者: meathill

  • 将 Next.js 项目从 Vercel 迁移到 Cloudflare

    将 Next.js 项目从 Vercel 迁移到 Cloudflare

    一起逃离 Vercel 拥抱 Cloudflare 吧

    Vercel 再次调价之后,性价比越来越低,每个月 $20 的额度根本扛不住什么访问量;而且建站所需的各种服务(数据库,KV 等)也欠缺,所以我觉得是时候迁离 Vercel,投奔赛博菩萨 Cloudflare 的怀抱了。

    不过由于 Cloudflare 平台的整体架构,其 Edge Runtime 和 Serverless runtime 都跟 Vercel,或者说标准架构存在一些不同之处,所以迁移的过程中往往需要我们做一些工作。本篇博客就来分享这些经验。

    Cloudflare 云服务

    首先,Cloudflare 不仅提供 Serverless / Edge 托管,更提供一整套几乎是必须的服务器组件:

    1. SQLite 接口的关系型数据库 D1,速度很快,第三方工具很多
    2. 形似 Redis 的 KV 数据库
    3. 存储服务 R2,兼容 AWS S3
    4. Queue、Durable Object 等几乎所有服务器长线运营必须的工具

    而且以上大部分都包含慷慨的免费额度,当你的产品度过极早期,需要更多额度时,$5/月也够用很久。总之,对比 Vercel 万国造且每个都要独立付费,当然是 Cloudflare 更好用。

    (当然,也会越来跟 Cloudflare 绑定越来越深,这方面见仁见智吧。)

    接下来,Cloudflare 更推荐我们使用他们家的 Worker 平台。以我的经验,使用 Worker 而不是 Pages 有以下好处:

    1. 实时日志,方便我们查看运行时错误和 debug
    2. 支持 cron trigger,可以方便的执行一些自动化操作
    3. 以及更好的缓存策略,比如预渲染

    自然,Worker 需要更多的工作,我们必须整体迁移到 OpenNext 才行。

    迁移到 OpenNext

    首先,请参考官方文档:https://opennext.js.org/cloudflare/get-started

    接下来,我也会捋一遍迁移过程,并分享我的经验。

    安装 @opennextjs/cloudflare

    这个适配器会帮我们在 Cloudflare 上运行我们的 Next.js 应用。

    pnpm install @opennextjs/cloudflare@latest

    安装 Wrangler

    Wrangler 是 Cloudflare 提供的命令行工具,可以帮我们完成很多工作,也是上面适配器的必备工具。

    pnpm install --save-dev wrangler@latest

    创建 wrangler 配置文件

    这个配置文件会影响到最后的部署和其它云服务使用。我建议大家使用 JSON 格式,因为语法更熟悉。

    {
      "$schema": "node_modules/wrangler/config-schema.json",
      "main": ".open-next/worker.js",
      "name": "<应用名称>",
      "compatibility_date": "<最近的日期>",
      "compatibility_flags": [
        "nodejs_compat",
        "global_fetch_strictly_public",
      ],
      "account_id": "<你的 account id>",
      "assets": {
        "directory": ".open-next/assets",
        "binding": "ASSETS",
      },
      "services": [
        {
          "binding": "WORKER_SELF_REFERENCE",
          "service": "<应用名称>",
        },
      ],
      "r2_buckets": [
        {
          "binding": "NEXT_INC_CACHE_R2_BUCKET",
          "bucket_name": "<BUCKET_NAME>",
        },
      ],
      "vars": {
        "NEXT_PUBLIC_SITE_URL": "<你的网站域名>"
      }
    }

    添加 open-next.config.ts 配置文件

    在根目录添加 open-next.config.ts 配置文件。

    import { defineCloudflareConfig } from "@opennextjs/cloudflare";
    import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";
     
    export default defineCloudflareConfig({
      incrementalCache: r2IncrementalCache,
    });

    添加 .dev.vars 文件

    在根目录添加 .dev.vars 文件,告诉 Next.js 它应该使用哪一个 .env 文件。

    NEXTJS_ENV=development

    环境变量是比较难处理的一项工作。首先,线上使用的环境变量通常分两部分,一部分就是普通的变量,应该直接放在 wrangler.jsoncvars 字段里;另一部分是需要加密的比如各种 apiKey,需要通过 wrangler 工具放到 secrets 里。

    线上的环境变量必须保存在 wrangler.jsonc 里。这里我们只需要把本地开发环境所需的变量放在 .env.development,覆盖线上的即可。本地密钥也可以放在 .env 文件里。

    更新 package.json

    需要给 package.json 加上以下命令,方便开发和部署。

    "build": "next build",
    "preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview",
    "deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy",
    "upload": "opennextjs-cloudflare build && opennextjs-cloudflare upload",
    "cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts",

    其中,deploy 用来完成主动部署,upload 用来部署开发分支,cf-typegen 用来生成描述文件,让 IDE 的代码补全更强力。

    添加静态资源缓存

    创建 /public/_headers 文件,添加以下内容,让 Cloudflare CDN 默认缓存所有静态资源,加速网站访问。

    /_next/static/*
      Cache-Control: public,max-age=31536000,immutable

    移除 pages 相关内容

    从代码中移除 export const runtime = "edge";

    并卸载掉 @cloudflare/next-on-pages

    忽略掉 .open-next 和 .wrangler

    .gitignore 添加更多的忽略项。如果使用 ESLint,也可能需要添加。

    .open-next
    .next
    .wrangler

    本地开发

    修改 next.config.ts,增加 @opennextjs/cloudflare 提供的适配器。之后,你就可以使用 Cloudflare 提供的开发环境了。

    import type { NextConfig } from "next";
     
    const nextConfig: NextConfig = {
      /* config options here */
    };
     
    export default nextConfig;
     
    import { initOpenNextCloudflareForDev } from "@opennextjs/cloudflare";
    initOpenNextCloudflareForDev();

    【可选】移除首页的预渲染缓存

    如果你的首页需要加载远程数据,那么可能需要手动避免首页被预渲染,否则你可能会面对一个静态的首页。解决方案并不复杂,只需要给首页的 page.tsx 里添加下面的语句即可:

    // 完全不缓存,每次都重新渲染并加载
    export const dynamic = 'force-dynamic';
    // 或者如果不希望完全动态,只是希望数据不缓存
    // export const revalidate = 0;

    完成第一次部署

    接下来,建议大家执行 pnpm run deploy 完成第一次部署,这样会在 Cloudflare 里添加一个新的 worker,然后我们才好添加 secrets。

    关联 GitHub 仓库

    找到刚才创建的 Worker,在设置面板里找到“构建”,即可关联到我们的 GitHub 仓库。在构建配置里:

    1. 删除“构建命令”(Build command)
    2. 部署命令(Deploy comment)为 pnpm run deploy
    3. 非生产分支部署命令(Non-production branches deploy comment)为 pnpm run upload

    部署完成

    至此,迁移完成,后面正常推代码就可以触发自动部署了。

    总结

    其实还有一些工作要做,比如配置缓存,配置可见性,等等。大家可以根据需要来操作。

    希望这篇文章对大家所有帮助。如果大家对 Vercel,Cloudflare,Next.js 有任何问题或想法,欢迎留言讨论。

  • React Native + Expo 入门级实战开发多平台应用 WhiteScreen:3. 深入开发,完成应用主体

    React Native + Expo 入门级实战开发多平台应用 WhiteScreen:3. 深入开发,完成应用主体

    感谢剪辑同学的努力工作,第三集上线。

    油管地址:https://youtu.be/0Ix-Y-MPQY0

    B站地址:https://www.bilibili.com/video/BV1CxnJzfEAk/

    继续分享 React Native+Expo 应用开发,帮大家补上全栈开发的最后一块拼图:移动应用开发。

    在这个系列视频里,我会用一个入门级小应用 WhiteScreen 作为范例,介绍如何使用 React Native+Expo 开发移动应用,并上传到应用商店。虽然国内市场基本被几个超级应用垄断,但是海外的广阔天地仍然大有可为。而 React Native 可以最大限度的利用我们已有的技术积累,让我们快速完成原型开发与需求验证,是全栈开发的不二之选。

    这期是第三次课,主要介绍:

    1. 使用 Zustand 管理状态,在页面间同步数据
    2. 使用原生组件进行布局
    3. 实现简单动画
    4. 实现本地数据存储于使用

    希望能给大家带来更多的可能性,在这个不那么容易的年代,让大家都有更多的选择余地与发展空间。

    希望大家留下宝贵的一键三连分享收藏,让更多的人能看到我的视频。

    有任何问题和建议,欢迎留言弹幕一起讨论。

    谢谢大家!

  • 【视频教程】React Native + Expo 入门级实战开发多平台应用 WhiteScreen:1. 移动应用开发现状+项目简介+技术栈简介

    【视频教程】React Native + Expo 入门级实战开发多平台应用 WhiteScreen:1. 移动应用开发现状+项目简介+技术栈简介

    前几天我在博客 感谢赞助商 Mizu Financial,重启我的自媒体之路 提到,因为工作调整,下一阶段我要捡起自媒体,在新的工作开始之前,提升一下自身的品牌价值。所以,我开启了新系列视频教程的录制。

    现在新视频终于上线,敬请观看。

    油管地址:https://youtu.be/YEPvihSIQkw

    B站地址:https://www.bilibili.com/video/BV1ZgHoztE4v/

    (更多…)
  • 跟风吐槽一下小米

    跟风吐槽一下小米

    前两天小米市场部总经理王某被辞退,在数码媒体圈甚嚣尘上。我不认识这位,不便评价。不过我跟小米有些过节,所以赶紧跟风吐槽一下。开篇名义:我能不买小米就不买小米,因为我早就认为小米市场部很垃圾。

    我曾经不止一次说过,我不会买小米,也不会买魅族。这两家在我这里的问题是一样的:市场部人员不够诚心,欺骗老同事。

    (更多…)
  • 解决 React Native + Expo 面对 Google Play 的 16KB memory page 问题

    解决 React Native + Expo 面对 Google Play 的 16KB memory page 问题

    最近开始尝试开发 App,倒不是什么复杂的大项目,只是把朋友网站上的功能移植到移动端。技术栈仍然是 React Native + Expo,不过以前只做过 iOS,这次连 Android 一起做。

    那么自然的,这次就要踩 React Native Android 的坑。以后会分享所有相关的知识体验和坑,今天先分享最近两天花了不少时间解决的 Google Play 16KB memory page 问题。

    我们的应用提交到 Google Play 后,原本一切正常,前两天突然收到 Google 的政策通知:

    为确保您的应用能在最新版 Android 上正常运行,Google Play 要求以 Android 15 及更高版本为目标平台的应用支持 16 KB 内存页面大小。

    自 2026年5月30日起,如果您的应用更新不支持 16 KB 内存页面大小,您将无法发布相应更新。

    您的最新正式版应用不支持 16 KB 内存页面大小。

    嗯,必须承认,看到这个问题我一头雾水。不过好在我也不需要把它理解透彻,只要知道该怎么改就好。可惜的是,Gemini 对这个问题没什么了解,我只好去阅读 Google 的文档,得到的结论是:

    我需要修改 /android/app/build.gradle 其中的配置 useLegacyPackaging 将其改成 true

    android {
        packagingOptions {
            jniLibs {
                useLegacyPackaging true
            }
        }

    不过我使用的是最新版 expo prebuild 生成的 Android 项目,所以这个配置本身依赖 app.json 的配置,那么理论上,我只需要添加下面这行:

    {
      "expo": {
        "android": {
          "useLegacyPackaging": true
        }
      }
    }

    于是我改好配置重新打包上传,结果还是不行。认真阅读 app bundle 详细信息,发现错误位于 base/lib/arm64-v8a/librnskia.sobase/lib/x86_64/librnskia.so ,很明显,这是 @shopify/react-native-skia 包,也就是我们的绘图依赖。

    因为我的项目里用到 Expo,所以我一般用 Expo 安装依赖,安装的版本也由 Expo 决定。目前版本的 Expo 要求的 @shopify/react-native-skia 版本是 v2.0.0-next.4,在 GitHub issues 里搜索一下,发现这个版本果然不支持 16KB Memory page,而修复的版本是 v2.0.6。

    按照我的习惯,有新不用旧。于是直接升级到 2.2.9,然后应用就挂了……于是降级到 v2.0.7(2.0 版本的最高版本),测试没问题。打包上传,终于解决了 16KB 警告。

    简单总结一下:

    1. 不同平台有不同要求,不过大多可能和 RN 无关,通过项目配置就能解决
    2. React Native 由于跨平台,跨运行时,依赖之间的关系很复杂,不能乱升级,尽量控制小版本,只升补丁版本
  • 感谢赞助商 Mizu Financial,重启我的自媒体之路

    感谢赞助商 Mizu Financial,重启我的自媒体之路

    感谢 Mizu Financial 成为本站的新赞助商,也帮助我重新拾起自媒体之路。今年由于种种原因,我的博客和视频直播几乎彻底中断。最近终于有了一些富裕时间,在开启下一份职业生涯之前,我准备先把自媒体捡回来。

    介绍下赞助商:Mizu Financial 是一家硅谷初创企业,为北美和亚洲的中小型传统企业提供稳定币与比特币的财务管理 SaaS 服务,帮助客户在传统财务系统中安全接入数字资产,实现对加密资金的透明管理与自动化对账。公司成立于 2025 年 3 月,创始团队成员包括资深硅谷Web2/Web3 投资人、前 Meta 工程师、CMU 博士等连续创业者。

    接下来,我会尽量在白天保持直播,写各种自己的和甲方的项目,把以前挖的各种坑填上,并保持博客周更,以对得起赞助商的支持。

    (更多…)
  • 【已招到】【远程直聘】美国稳定币管理服务公司招聘全栈开发(偏后端)

    【已招到】【远程直聘】美国稳定币管理服务公司招聘全栈开发(偏后端)

    关于我们

    Mizu Financial 是一家硅谷初创企业,为北美和亚洲的中小型传统企业提供稳定币与比特币的财务管理 SaaS 服务,帮助客户在传统财务系统中安全接入数字资产,实现对加密资金的透明管理与自动化对账。公司成立于 2025 年 3 月,创始团队成员包括资深硅谷Web2/Web3 投资人、前 Meta 工程师、CMU 博士等连续创业者。

    (更多…)
  • 从40秒到11毫秒:TiDB Cloud一次SQL深潜优化实战

    从40秒到11毫秒:TiDB Cloud一次SQL深潜优化实战

    此文参加了 TiDB 社区第四届专栏征文大赛,获得二等奖。感谢 TiDB,感谢 Gemini,感谢跟我一起做 Awesome Comment 的某同学。

    有空的同学麻烦帮我投个票:https://asktug.com/t/topic/1046966 搜索“深潜”就能找到给我投票的地方

    在数据库应用中,慢SQL是常见的性能瓶颈。本文将详细记录一次针对TiDB Cloud v7.5.2环境中复杂评论查询的SQL优化过程,如何通过分析执行计划、添加索引、改写SQL(使用EXISTSUNION)等手段,将一个40多秒的查询逐步优化到11毫秒,希望能为读者提供有价值的实战参考。

    不知道什么时候,TiDB Cloud 升级到 v7.5.2,于是我们的评论应用 RU 消耗开始起飞,达到以往月份的 3 倍左右。没办法,只好拖着病榻之躯来 Debug。还好 Gemini 2.5 Pro 给力,很快我就完成了这次优化,记录在这篇博客里。另外,这篇博客也是 Gemini 2.5 Pro 帮我写的,AI 之力,恐怖如斯 😱😱。

    (更多…)
  • 计划参加 2025 年 7 月广州 IPL 力量举比赛,诚征赞助商

    计划参加 2025 年 7 月广州 IPL 力量举比赛,诚征赞助商

    我准备报名参加今年 7 月在广州举办的 IPL 的力量举三项赛,具体组别是大师组 100KG。预测成绩510KG=S175+B135+D200。据说不会有很多选手,所以大概率能拿名次~

    现在诚征赞助商!10块8块不嫌少,300、500不嫌多。全身广告位均可用,我还会配合博客、视频增加赞助商曝光,欢迎各位老板踊跃赞助,感恩,比心。

    (更多…)