标签: next.js

  • 将 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 有任何问题或想法,欢迎留言讨论。

  • 系列视频制作中:Next.js 全栈开发每日一签网站

    系列视频制作中:Next.js 全栈开发每日一签网站

    之前的几个系列基本都连载完毕。前些天开了一个新坑:全栈架构师系列。但是这个系列比较难录:讲得深,应用场景就窄,观众就少,像我这种发免费课的方式就比较亏;讲得浅,我觉得也没啥意思,担心将来大家一看,“就这?”。还有一点,技术难题不是每天都能遇到,要积累适合的话题,还要不担心泄漏技术秘密,其实比较难搞。所以只录了一期,因为第二期迟迟没想好怎么录,一直也没发。

    前阵子跟 201 老同事吃饭,了解到她也“毕业”了,正在小红书上创作“每日一签”,突然我觉得可以跟以前做的 拜拜 应用结合起来,搞个每日一签网站:

    1. 固定更新能提供 SEO 价值
    2. 拜佛和求签本身就是强关联的功能,可以把用户留住

    于是我们一拍即合,就有了 每日一签 这个网站。这个网站用到以下技术栈:

    1. 后台使用 Strapi 快速搭建,部署在 Zeabur 的 Docker 服务上
    2. 全栈开发使用 Next.js,App Router,全部 SSR,数据使用 Strapi RESTful API
    3. CSS 使用 TailwindCSS,并且基于 TailwindCSS 家的 Commit 模版二次开发
    4. 网站部署在 Vercel 上
    5. 数据库使用 TiDB Cloud Serverless (这次 TiDB Cloud 在我学习 Strapi 的过程中立了大功)
    6. 存储和 CDN 使用 Cloudflare R2
    7. 统计服务也用 Vercel

    这套技术栈完全免费,各种云服务的免费额度可以跑到一个很高的量。是我非常推荐的全栈技术栈,也是各种独立开发、出海创业的首选。所以从开始我就想把它做成一套全栈开发课程。正好可以作为之前几套全栈开发系列教程的补充:

    1. 基于 Next.js + React,便于大家学习和扩展技术栈
    2. 更复杂的网站,更丰富的功能
    3. 更复杂的数据结构和 API,但是更简单的后端处理
    4. 更全面的基础设施服务

    那么说干就干,我就一边开发一边制作视频。新的课程可能包含以下章节:

    1. 项目介绍,技术栈简介(视频制作中)
    2. 使用 Monorepo 管理复杂项目
    3. 使用 Docker 部署 Strapi 应用到 Zeabur (下周一 10-14 录制,正好填上欠 Zeabur 的推广)
    4. 使用 TiDB Cloud 提供数据库服务
    5. 使用 Cloudflare R2 提供存储和 CDN
    6. 使用 Next.js + Commit 模版开发网站
    7. 使用 Shadcn 组件库
    8. 添加每日页,制作 sitemap,提升 SEO
    9. 使用前端推送功能
    10. 使用 og 开发分享功能

    希望新的系列课程能帮助大家学会现代化的全栈开发,学会使用各种现代化的研发平台,给大家开展独立开发和技术出海带来新的机会。如果你对全栈开发、独立开发、技术出海感兴趣,请关注我的系列视频和博客更新。如果你对相关技术有疑问想寻求解答,欢迎留言。

  • Next.js 14 SEO 最佳实践(2)Next.js 14 SEO 要点

    Next.js 14 SEO 最佳实践(2)Next.js 14 SEO 要点

    继续分享 Next.js 14 SEO 最佳实践。上次主要介绍 SEO 基础知识,以及一般原则,这次重点放在 Next.js 14 上。我先武断暴言一句:Vercel 在 Next.js 14 上的整了个烂活儿,给开发者留下了很大的坑要填。

    页面组件避免 'use client'

    Next.js 14(也可能更早,待查)引入了 serverclient 组件的区分。前者没有状态,渲染一次后就不会变化;后者则可以与用户互动,响应用户操作,并将变化体现在视图之中。

    SEO 有一些必备信息,包括 title, description,需要通过 export const metadatagetMetadata 返回。它们都不支持 client 组件,所以,我们应该避免让页面组件(page.tsx)成为 client

    按照官方文档的说法,client 组件也会在服务器端进行渲染,然后发给客户端,所以比较合适的做法是:

    1. 组件化颗粒度可以细一些,以便将不需要状态的 server 组件和响应用户操作的 client 组件进行隔离。
    2. 必要的数据,尤其是希望搜索引擎抓取并索引的数据,在页面组件里完成读取,然后传递给 client 组件,作为初始值,完成第一次 SSR。
    3. getMetadata 时,可以使用 React.cache 函数将结果缓存起来,重复使用,降低网络请求成本
    4. 限制 client 的功能比较多,比如 createContext,所以工具函数文件不妨也分离得细一些,避免产生影响。

    确保返回页面 metadata

    SEO 需要一些信息来理解页面,并在搜索时呈现给用户,这些信息基本上都要通过 metadata 提交给搜索引擎,所以我们应该保证在 page.tsx 里都有返回合适的 metadata

    一般来说,metadata 需要包含以下数据,后面的代码简单演示了动态获取并返回信息的方式:

    1. 页面 title
    2. 页面内容 description
    3. OpenGraph 信息
    4. Canonical link
    5. 如果有多语言,还应该有 alternate link
    export async function generateMetadata(
    { params, searchParams }: PracticeDetailPageProps,
    parent: any
    ): Promise<Metadata> {
    // 读取路由参数
    const courseId = params.courseId;

    // 这里的加载函数可以提前 cache,以避免重复请求 API
    const courseDetail =
    await webApi.courseApi.fetchCourseDetail<CourseDetailType>(courseId);

    const metadata: Metadata = {
    title: courseDetail.title,
    description: courseDetail.description,
    alternates: {
    canonical: `https://www.hackquest.io/practices/${courseId}`
    },
    openGraph: {
    title: courseDetail.title,
    description: courseDetail.description,
    image: courseDetail.thumbnail,
    },
    };

    return metadata;
    }

    增加组件颗粒度,创造条件使用 server 组件

    因为静态内容更有利于 SEO,而 server 组件是生成静态内容的最好方式,所以我们应该尽量多使用 server 组件。

    问题在于 client 组件具有传染性,当某个组件内部使用状态的时候,它就必须是 client 组件,所以我们应该尝试让组件颗粒化的程度更细,仅在需要交互的组件里使用状态。

    搜索引擎的爬虫可以沿着超链接爬取一个又一个页面,而它们并不知道某个 <div> 上绑定了跳转事件,所以应该使用 <Link> 帮助搜索引擎索引整个网站。

    很多时候,为满足埋点等需求,我们会使用 onClick 事件,没关系,因为事件会先于链接跳转触发,所以我们只需要正常使用埋点功能即可。

    全站使用统一的通用导航

    使用全站通用的顶部导航和底部导航是提升 SEO 和网页收录的好办法。

    通用导航里面可以包含大量站内链接,方便搜索引擎爬虫遍历整个网站,所以我们应该在通用导航里大量使用 <Link> ,让爬虫可以顺藤摸瓜,找到我们网站里的全部内容。当然,从用户角度的来说,通用导航可能并不是每次打开页面的主要目的,所以,通过 CSS 控制通用导航的显示状态,让爬虫可以按图索骥,但是不影响普通用户阅读网页,是我们应该做的。

    所以,我们应该让整个网站使用统一的导航内容,只调整显示状态,而不是每个页面显示不同的导航。

    分离工具函数和依赖,避免污染

    影响 client 组件的因素很多,比如各种 hooks,createContext,等。如果我们在 a 函数里使用了这些功能,然后在 bimport a,会导致 b 也必须是 use client。这就要求我们尽量将引用的工具函数进行分离,比如单独写一个 utils.client.ts 用来存放客户端才需要使用的工具函数。

    使用 [[...slug]] 处理 URL

    如同前面所说,我们应该给所有资源配置好合适的 URL。比如我们有一些博客内容,需要建立博客页面,那么,我们就应该给翻页功能分配好独立的 URL,如 /p/${page},而不是把翻页状态保存在页面状态里。同样,如果我们支持按标签、分类筛选,就可以提供 /tag/${tag-slug} 这样的 URL。

    此时,为了能更好的复用代码、复用组件,我们可以用可选通配符组件 [[...slug]] 来制作页面。

    const Blog: React.FC<BlogProps> = async function ({
    searchParams = {},
    params: { slug = [] }
    }) {
    const limit = 12;
    const minPage = Number(slug[1]) < 1 ? 1 : Number(slug[1]);
    const page = slug[0] === 'p' ? minPage : 1;

    // 处理加载分页后的博客数据
    ....
    }

    制作 robots.txtsitemap.xml

    制作 robots.txt 比较简单,很多时候手写一个放到 /public 目录里即可,所以我不再赘述。

    制作 sitemap.xml 就复杂很多,因为网站可能会有很多页面,其中更有不少需要动态生成,所以我们一般需要创建 sitemap.ts 才能完成。部署的时候,构建脚本会自动调用这个文件,生成新的 sitemap.xml

    详情请参考官方文档:Generating a sitemap using code (.js, .ts)

    小结

    如果你对 Next.js 或者 SEO 有什么问题和想法,欢迎留言讨论。

    本站目前还在招商:本站广告 2024 年招商,欢迎感兴趣的老板私信洽谈。

    系列文章

    系列长文好更不好看,所以我决定以后都在 notion 上做汇总页,方便日后整体阅读。本文实际已经基本写完了,感兴趣的同学可以先去围观:https://meathill.notion.site/Next-js-14-SEO-90d31eee22ff4621af6620524b4b2773?pvs=4

  • Next.js 14 SEO 最佳实践(1)了解 SEO,常规要点

    Next.js 14 SEO 最佳实践(1)了解 SEO,常规要点

    近日搞 SEO 比较多,本来想写篇“Nuxt3 SEO 最佳实践”,但是列完大纲,发现内容不太够,基本上只需要照搬各种 SEO 手册,跟 Nuxt3 关系不大,不符合我对内容的要求。然后我自信满满地想帮朋友搞 Next.js 14 SEO,发现,好难,Next.js 14 的坑真多……于是就有了这系列文章。

    什么是 SEO

    SEO 即搜索引擎优化(Search Engine Optimization),是指通过优化网站以提高网站在搜索引擎中的自然排名,从而增加网站流量,提高品牌曝光度的一系列操作。SEO 主要关注两个方面:站内优化与站外优化。站内优化包括确保网站的结构、内容质量、关键词布局、网页元标签、URL结构等对搜索引擎友好。而站外优化则更多关注于外部链接建设,即增加其他网站对你的网站的链接,这有助于提高网站的权威性和排名。

    作为技术人员我们一般会负责站内优化,本文也主要讨论站内优化。

    为什么要 SEO?

    1. SEO 目前仍然是最便宜的流量来源。
    2. SEO 跟用户体验并不冲突,事实上,搜索引擎一直在想办法把用户体验和搜索排名结合起来。
    3. 我们甚至可以以 SEO 之名,为优化网站争取开发时间

    现代 SEO 的注意事项

    作为一名前端/全栈开发,有一些东西归属于我们的同事,比如创建内容、扩展外链,我们可以不过分深究。但是也有一些注意事项,尽早注意,可以节省大量返工的时间。

    了解必要的知识

    本文主要是我的经验之谈,不是很全面,更多的知识请阅读后面扩展阅读里的各个链接。

    尽量用服务器端渲染

    1. 服务器渲染对 SEO 更加友好。
    2. 对于大部分搜索引擎爬虫来说,如果能采用静态分析,性能会比分析 JS 渲染的页面高很多。
    3. 服务器端渲染对用户体验也有提升。

    尽量用超链接而不是手动跳转

    1. 浏览器爬虫可以通过超链接 <a> 找到更多页面。
    2. onclick 无法做到这一点。
    3. 我们仍然可以使用 onclick 进行数据埋点统计,因为事件会早于链接跳转触发。

    给每个资源一个 URL

    1. 为了能够在用户间共享,以及让搜索引擎可以索引,我们需要给每个资源一个 URL。
    2. 比如一个页面,如果它包含翻页,我们应该给所有页面安排 URL,比如 /p/2/p/3 等等。而不是把状态保存在浏览器内存里,因为这样外界没法获取直接指向它的资源。
    3. 如果是音频、视频等需要长时间播放的资源,则可以利用锚点: #{时间} 来指向某个具体的时间点。长网页上的标题也应使用类似的锚点技术。
    4. 总之,尽量不要在内存里保存状态,都搞成 URL,做成超链接

    确保页面上有合适的 SEO 内容

    1. <title>
    2. <meta name="description" content="{description}" />
    3. <link ref="canonical" href="{canonical link}" />
    4. <link hreflang="{语言}" href="{其它语言链接}" />
    5. 使用 og 库添加 OpenGraph 信息
    6. 大量可以被搜索引擎阅读和理解的文本,少用图片
    7. 图片、音频、视频等,要配备 alt 等文本信息
    8. 使用 aria-* 帮助搜索引擎链接页面
    9. 使用超链接时,使用 rel 来告诉搜索引擎链接目标和本页面的关系

    尽量把内容全部展示出来

    1. 搜索引擎希望能一次抓取所有内容,这样它才能正确地索引全部内容,以及爬取剩下的内容。
    2. 有时候我们基于页面容量,会倾向于把一些内容隐藏起来,等待用户满足特定条件才展开。比如 tab、carousel 等。此时,我们最好使用 CSS 控制显示效果,而不是只输出部分内容。
    3. 当然,如果涉及到付费墙、私密信息等,可以不显示所有内容。

    设计良好的 URL 结构

    1. 良好的 URL 可以帮助搜索引擎理解我们的内容结构
    2. 也拿博客举例:
      1. / 首页
      2. /p/{page} 分页
      3. /tag/{tag-slug} 分类页
      4. /cate 分类页面
      5. /cate/sub-cate/ 子分类页面
      6. /cate/sub-cate/page-slug-一般来说是内容 具体文章页

    其它

    1. 生成正确的 robots.txtsitemap.xml 并提交给搜索引擎
    2. 避免 404 和 500
    3. 利用缓存改进访问速度
    4. 保证使用 heading,但不要滥用 heading 标题,确保 h1~h6 的合理顺序

    小结

    如果你对 Next.js 或者 SEO 有什么问题和想法,欢迎留言讨论。

    本站目前还在招商:本站广告 2024 年招商,欢迎感兴趣的老板私信洽谈。

    系列长文好更不好看,所以我决定以后都在 notion 上做汇总页,方便日后整体阅读。本文实际已经基本写完了,感兴趣的同学可以先去围观:https://meathill.notion.site/Next-js-14-SEO-90d31eee22ff4621af6620524b4b2773?pvs=4

  • SSR,云平台,ChatGPT——我的 2023 技术关键词

    SSR,云平台,ChatGPT——我的 2023 技术关键词

    前言

    2023 年,因为换工作,启动新项目等原因,我对我的技术栈进行了比较大的更新,主要集中在这三个方向:

    1. SSR(Server Side Rendering,服务器端渲染)。之前我开发的项目基本上都是 SPA(Single Page Application),比如 Vue,但之后我会越来越多开始用 Nuxt。由于基础设施的发展,以后 SSR 会更方便更好用。
    2. 云平台。以前我大概买了 3、4 台云服务器用来做各种尝试,在上面各种折腾。去年使用 Vercel、Supabase、CloudFlare 平台之后,我已经不打算再在服务器上浪费时间了,云平台实在太好用了。未来我会努力把所有服务都迁移到云平台上,新增产品都直接云原生。
    3. ChatGPT。相信不只是我,很多人都会把 ChatGPT 作为去年技术的首选关键词。如今我不仅在上面完成产品开发,日常也会使用它替代大部分的搜索;甚至我家孩子写作业也会使用它来帮忙。我认为,未来 ChatGPT 就像是搜索引擎一样,决定了一个人的起点和成长速度。

    接下来逐个分享。

    服务器端渲染,SSR

    起初我不是很看重 SSR,我总觉得,我当年也写过 PHP,有什么“服务器端渲染”我没见过?实际用过之后,我承认:真香……

    首先,使用 SSR 可以提升用户体验,且有利于 SEO,这点相信大家都知道。如果对其原理不太清楚的话,欢迎观看我的视频:从浏览器渲染机制理解 Web 性能——“在浏览器地址栏输入 URL,按下回车后会发生什么?”

    其次,如今的 SSR 与当年 PHP 模版套页面的实现有很大区别:

    1. 语言同构化:开发难度大大降低,没有心智负担。
    2. 数据传递与状态管理:虽然数据不能完全通用,但是框架尽量会帮我们处理好,让我们在服务器端和客户端都能自由使用。
    3. 渲染由边缘计算负责:这一点有点依赖云平台,不过考虑到浏览器的渲染机制,SSR 并不会拖慢渲染速度,用户体验只会更好。
    4. 页面切换不需要重新加载。对于旧的编程语言来说,因为前后端环境割裂,所以页面切换的时候都是重新加载完整页面;但是新框架下,则只需要加载数据即可,此处跟 SPA 的体验无二。

    第三,如今的 SSR 框架都很好的整合了服务器,包括中间件等功能,还有各种官方第三方模块支持,能大大降低我们开发服务器软件的成本。所以已经是我启动新项目的不二之选。

    云平台

    以前我长期维护好几台服务器,一方面可以部署自己做的产品 demo,另一方面也可以部署一些开源项目方便日常使用。因为各种云都有面向新用户的优惠活动,所以成本不高,我觉得值得一搞。

    自己的服务器当然比较比较自由,坏处就是免不了产生运维成本,即使使用 docker 也一样。部署新代码至少要去跑一遍拉取脚本,对吧?我的一位老板朋友甚至请我帮忙写了一套服务器脚本,用来做 CI/CD。

    初期这么搞没问题,但后来就越来越觉得功能不够,性价比也太低,开始寻求替代方案。之前我参加 Hackathon 的时候了解到 Vercel 云平台。它与 GitHub Pages 不同,支持 SSR、支持云函数,配合一些云数据库,比如 Upstash,可以快速搭建起来一套可用的服务。去年年初,我的那位老板朋友想做一套打分系统,放在他的静态网站里,于是,我就尝试用 Nuxt.js + Upstash 开发了一套,并且部署在 Vercel 上,效果非常好,免运维,多环境,推到 GitHub 自动部署,实在太好用。

    我把这个过程制作成了系列课程:Nuxt3+Vercel+Serverless 数据库全栈开发。大家感兴趣不妨看一看。

    后面一发不可收拾,过去一年我不再采购新的单体服务器,旧的服务器用完也不再续费。新产品都部署在 Vercel 等云平台上面,帮我节省了大量的时间。

    Vercel 去年年中的时候开通了存储功能,实际上就是打包了几家云数据库服务来卖,我也很快获准开通。从此,云平台使用就更加顺利了。临近年底,我尝试 CloudFlare Pages,效果也非常好。他们家的优势是自带统计分析功能,远比 Vercel 大方,一站式解决更省心。

    云数据库方面,我使用 Upstash 的 Redis,KV 数据库足以满足大部分产品需求。数据库用 Supabase 和 TiDB 比较多。前者支持 PG Vector,方便我们进行 LLM Embedding & Search;后者则提供 5GB 免费额度,比较好用。云存储有 CF 的 R2,空间和流量也相当充足。如果不是 PHP 太老没人支持,我都想把博客这台机器退掉了。

    ChatGPT,以及其它

    ChatGPT 更是值得大书特书的一个技术关键词。不过考虑到大家去年一整年应该已经被类似的内容淹没了,所以我这里就少写一些,只说说我的情况。

    我目前订阅了 ChatGPT+,方法是借用国外亲戚的手机号注册,并且用他的手机号注册 PayPal,通过 Google Play 订阅。订阅的原因是 ChatGPT 4 + DALL-E 都可以随便用,比 API 便宜得多。

    在编程领域,GPT-4 比 GPT-3.5 好太多了,知识库更新到去年 4 月份之后,除了 next.js 14 的内容外,我日常的编程问题大多可以用 GPT-4 解决,比如:

    • 写正则
    • 写 SQL
    • 查函数、查第三方库
    • 纠正函数错误

    帮我节省了大量的 Google 时间,单凭这点,每月 $19.99 的订阅费用就很值得。

    除此之外,我还在继续使用 GitHub Copilot。Copilot 也很好用,除了生成工具函数、编写测试外,我发现翻译语言和框架方面也有很大的作用。去年我就完全靠它开发了一个 flutter 应用,方法就是把 TS+Vue 写好的代码丢给它让它翻译。

    所以,无论是学习新东西,保障日常开发,还是扩展新领域,AI 对我都帮助巨大。

    总结

    总而言之,如果再有同学问,前端想学后端,应用学什么语言框架以及是否需要搭自己的服务器?我都会建议他们:不要学 Express、Koa;习惯用 Vue 就学 Nuxt,习惯用 React 就学 Next.js;不需要搭建服务器,就用云存储就能解决绝大多数问题。

    我还建议大家,尽快想办法开通 ChatGPT,再不济国产大模型也要用起来,未来是 AI 的时代,学会用 AI,效率会大幅度提升。半年的初入门新人,善用 AI 可以赶上 3 年的老程序员;而老程序员学会用 AI 之后,可以快速把自己的能力扩展到其它领域。

    以上,就是我去年关键的技术栈总结,希望对大家有所帮助。如果大家有什么意见建议,想说的想聊的,欢迎留言。

  • 【代友招聘】【全职远程】全栈 Next.js Web3 教学网站

    【代友招聘】【全职远程】全栈 Next.js Web3 教学网站

    事情是这样的。前厂去年年底把我们遣散后,我就找了一些工作来做,这是其中之一。我们最初要参加一场 Hackathon,作品是 Web3 教学网站,用游戏闯关的模式,吸引更多人来加入 Web3 开发。Hackathon 之后,老板决定把产品延伸扩展,做成独立产品,继续推广,让更多人可以用。

    按约我本打算继续帮他们做开发,但如今我已经确定要跟 Vincent 一起做 AI 应用层的产品,时间上不够两相兼顾,必须辞去一边。经过协商,我接下来会逐步退出这边的开发,初期兼作一些顾问型的工作,直到他们招到合适人选。

    这里,我要帮他们招招人试试看。情况大概如下:

    • 这是一家主要团队在美国的初创企业
    • 他们的主要目标产品是 Web3 教学网站
    • 他们已有产品、设计、课程团队,需要一个比较有经验的全栈开发负责网站研发工作
    • 近几个月工资会以稳定币形式支付,需要自己负责社保等;几个月后他们会回到国内正式注册公司,到时候可以正式跟国内公司签约
      • 不希望稳定币的话,可以要求人民币结算
    • 老板还是很靠谱的,结账很爽利
    • 主要技术栈是 Next.js+TailwindCSS+DynanmoDB+Vercel
    • 工资我不敢承诺,不过应该在远程岗位里算不错
    • 最好有远程工作经验,能做好自我管理,还能辅助管理研发最好

    有兴趣、有能力的同学,请与我取得联系,我会推荐给他们进行进一步的面试。

  • Turbopack 发布后的各方反应:Vite/Webpack/围观群众

    Turbopack 发布后的各方反应:Vite/Webpack/围观群众

    上周整理了一下 Turbopack 发布后的各方反应,以便让自己和各位同学下一步做决策的时候能有所参考。接着忙碌的一周过去,我发现博客这周还没更,于是赶紧来补一下。

    0. TL;DR

    1. Turbopack 的宣传语更多还是“宣传”,实际效果提升并没有那么巨大。
    2. Turbopack 目前只支持 Next.js + React,且没有建立健全插件机制,所以没有生态可言,如果我们的主要开发环境不一致,可能暂时用不到。
    3. Turbopack 基于 Rust 开发,性能提升主要来自 SWC,所以有时间、有兴趣的话,直接使用 SWC 替换编译工具就好。
    4. 非目标开发者群体建议先不考虑迁移。
    5. Turbopack 对于打包过程有不小的改进,值得持续关注。
    6. 如果你日常使用 React,且想在新技术出现时斩获先机,早点动手也挺好。

    2022-10-26

    首先,10月26日,Vercel 发布了 Turbopack,自命 Webpack 继任者,号称速度比 Wepback 快 700 倍,比 Vite 快 10 倍。

    这些是官推亮点:

    • ~700x faster than Webpack -> 比 Webpack 快 700 倍
    • 10x faster than Vite -> 比 Vite 快 10 倍
    • Native incremental architecture built with Rust -> 基于 Rust,具备原生可增长架构
      ◆ Support for React Server Components -> 支持 React 服务器组件
      ◆ Support for TS, JSX, CSS & more -> 支持 TS、JSX、CSS,以及更多

    尤大观点

    很快,Vite 作者 @youyuxi 就跟进表达反驳:

    “10x faster than Vite” isn’t entirely accurate

    “‘比 Vite 快 10 倍’并不完全准确”,他说。

    然后他进一步介绍了自己的理由:

    1. Vite’s default React HMR is still babel-based, while Next/turbopack use swc/rust-based transform, so the HMR performance difference is a bit of apples to oranges.

    因为 Vite 默认的 HMR 仍然基于 Babel,而Next/Turbopack 使用的是基于 Rust 平台的 SWC,所以这里 HMR 的性能差异是关公战秦琼(这个 thread 后面还有若干理由,我就不一一翻译了):

    Vite can switch to the swc/rust transform if necessary, we currently chose not to do that because adding swc to the deps list is extra weight, and even without it HMR is fast enough.

    Vite 当然可以在必要时切换到 swc/rust,但 Vite 开发团队并不想这样做,因为即使只用 Babel(不那样做),HMR 也足够快。使用 SWC 替换 Babel 只是平添开发负担。

    1. turbopack does address Vite’s request congestion issue on large apps. On Vite side we are also exploring how we can solve this via upcoming browser features like web bundles.
    1. Turbopack 确实解决了 Vite 在大型应用上的请求拥塞问题。我们 Vite 团队这边,也在探索如何解决这个问题,比如,是否可以借助即将推出的浏览器功能(Web Bundles)。

    In the long run we may also consider using turbopack under the hood to replace esbuild/Rollup (where suitable), due to its strong caching capabilities.

    1. 从长远来看,由于 Turbopack 强大的缓存能力,我们也会考虑在底层使用 Turbopack 来替换 esbuild/Rollup。如果合适的话。
    1. I’m glad vercel is investing its resources into a proper native-speed successor to webpack (as it should), and that our work on Vite has pushed this to happen. It’ll be interesting to see how it evolves – my hope is it can be made truly framework agnostic, not Next-first.
    1. 我很高兴 Vercel 愿意投入资源,打造 Webpack 的继任者,并着力提升它们的速度表现(应该如此),我们在 Vite 上的努力也达到了这样的目的。我对它们未来的演变很感兴趣——我希望它不要和框架捆绑在一起,不要 Next-first。

    Sean Larkin 观点

    (Sean Larkin 是 Webpack 的核心团队成员。目前好像在 LinkedIn 工作,好像。)

    Sean Larkin 也表达了自己的观点:

    Few thoughts: 几点想法:

    1. Love the innovation but it looks moderately SWC powers and wish there was some more callout there.
    2. Disappointed how entangled this is with next/turborepo. But Vercel needs to make.
    3. The path of migration from webpack for the avg user will be hard.
    4. I like that the dev server is still bundling modules because ESM slower than raw ESM. I need to peel back more layers to try and get a standalone implementation working.
    5. It’s all in alpha so we need to still look at the broader view but I hope we’re selling less going fwd
    1. 我喜欢创新。但看起来,Turbopack 更多是借力于 SWC,希望对方能表达得清楚一些。
    2. 我对 Turborepo 与 Next 的绑定程度感到失望。但是 Vercel 需要挣到更多的 (天使资金),没办法。
    3. 普通用户想 Webpack 迁移过去,会很艰难。
    4. 我倾向于开发服务器上的模块仍然是打包后的,因为 ESM 比原始 ESM 慢。我需要剥离更多层,才能让独立的实现工作。
    5. 目前它还处于 alpha 阶段,所以我们要看开一点,但我仍然希望,销售手腕少一些,好好干开发。

    2022-10-27 ~ 2022-10-28

    这段时间,@youyuxi 觉得 Turbopack 的数据有问题,因为 Vercel benchmark 的设计有问题,于是他尝试调整测试方式,给出了一些数据。不过后来他删除了这些推文,因为数字不太对。

    2022-10-27

    Vite 核心成员之一,@antfu7 在知乎上表达了自己的观点:

    他认为 Vite 更吸引人的是其插件系统,和构建在上面的生态系统。这样才能将改进快速带给其他领域。Turbopack 方面,静观其变吧。

    https://zhihu.com/question/562349205/answer/2733040669
    如何评价Vercel开源的使用Rust实现的Turbopack? – Anthony Fu的回答 – 知乎

    2022-10-29

    经过几天实验,Vite 作者 @youyuxi 发表了新的推文,新推文介绍了他进一步比较 Turbopack 和 Vite 之间性能之后,得到的新结论。

    I updated the vite vs next/turbo benchmark by using swc to transform React refresh for vite. To avoid confusion, I have deleted the previous two tweets with outdated numbers.

    Latest numbers:

    • root: vite 338.2ms / next 334.6ms
    • leaf: vite 141.8ms / next 84.4ms

    我通过搭配 Vite+SWC,重新评测 React 转换之后,更新 Vite vs Next/Turbopack 的基准测试。为避免混淆,我删除了前两条带有过时数字的推文。

    最新的对比数字:

    • 根:Vite 338.2ms / Next 334.6ms
    • 叶:Vite 141.8ms / Next 84.4ms

    The swc transform helps a lot in the root component case because the file is big, and previously cost 300ms in babel transforms alone. This makes vite almost exactly the same speed with turbopack.

    SWC 转换在根组件时候提供了很大帮助。因为文件很大,以前仅在 Babel 中转换就要花费 300 毫秒。替换之后,Vite 的速度几乎与 Turbopack 完全相同。

    Interestingly, in leaf scenarios turbopack is still 69% faster – this entails that Vite HMR actually caught up with turbopack as the file gets bigger, potentially scaling better in larger apps.

    有趣的是,在叶子场景中,Turbopack 的速度仍然更快,提升约有 69%。——这意味着随着文件变大,Vite HMR 实际上赶上了 Turbopack,在较大的应用程序中可能会有更好的扩展性。

    测试用仓库:https://github.com/yyx990803/vite-vs-next-turbo-hmr

    Because we are now testing the HMR of the same framework with the same set of transforms, the result is more relevant for other frameworks compared to previously posted numbers.

    现在,因为我们使用相同的转换集测试同一框架的 HMR,与之前发布的数字相比,结果的相关度更高。

    Just to add a bit of context – in this benchmark, even before using swc for React transforms, turbo is only 2x compared to vite (compared to marketed 10x). So the difference wasn’t that drastic to begin with.

    顺便讲点相关前提:这套基准测试,甚至在替换使用 SWC 转换 React 之前,与 Vite 相比,Turbo 也会仅 2 倍(他们市场宣称要快 10 倍)。所以其实一直以来,差异都没有那么大。

    2022-10-31 及之后

    本文主体整理于 10 月 31 日,之后 @youyuxi 还在孜孜不倦的跑 benchmark,与各路支持、反对、吃瓜者或讨论或争论。但是他的观点变化不大,所以我也就偷懒不继续翻译了,相信大家看完都能做出自己的判断。

    N 神有一些观点,摘录于此:

    vite 为了提升速度,利用了浏览器的特性,在 dev 阶段不打包而用 esbuild 预编译 esm 小包投送给浏览器, 在 build时候用 rollup 再打包。这样 dev 就会非常快(因为无需打包),但写插件就很分裂,要考虑 dev 和 build 两种情况。并且理论上如果依赖小包过多会肯定会遇到浏览器并发瓶颈减慢速度。

    按 Turbopack 的说法,他 dev 和 build 同样走打包流程,还能比 vite 快,那么铁定是更好的。只是太早期了,现在还没有开放插件生态。而且自命 webpack 继任者没毛病,看 github 上就是 webpack 作者主力搞的。

    但另一方面如果未来 non-bundler 成为主流,前端不再需要打包。turbopack就没用了。vite 抛弃 rollup,build 也走 dev 流程就更美了。

    https://twitter.com/nshen121/status/1587333382362763264

    SWC 作者和 Webpack 作者

    这二位目前都在 Vercel 工作,可能受公司公关限制,都只转发了官推,并没有发表更多意见。


    总结

    Turbopack 可能不如官方所说的那么好。它的确带来了 HMR 的提升,但代价是不健全的插件机制和生态环境,以及难以被前端团队掌握的 Rust 平台。

    未来一段时间,我们还要继续坚持在 Vite 平台上。