https://codexun.com 码寻_CodeXun 2025-04-18T13:36:20.674Z https://github.com/jpmonette/feed CodeXun https://codexun.com 技术分享:前后端、Node.js、React、Vue3s https://codexun.com/favicon.svg All rights reserved 2025, CodeXun <![CDATA[Next.js 系列之的SSG、SSR、ISR、CSR 的详细介绍和区别]]> https://codexun.com/posts/nextjs-series-difference-between-ssg-ssr-isr-and-csr-in-nextjs 2025-04-06T16:00:00.000Z
Next.js 提供了多种渲染策略(SSG、SSR、ISR、CSR),每种策略适用于不同的场景。以下是它们的核心区别、实现方式及最佳实践:

1. SSG(Static Site Generation,静态生成)

核心特点

  • 生成时机:在构建时(next build)生成静态 HTML。
  • 数据获取:通过 getStaticProps 获取数据,支持预渲染所有页面。
  • 适用场景:内容不经常变化的页面(如博客、文档、营销页)。
  • 优点:加载最快、SEO 友好、CDN 缓存友好。
  • 缺点:无法实时更新内容,需重新构建才能更新。

实现代码


2. SSR(Server-Side Rendering,服务端渲染)

核心特点

  • 生成时机:每次页面请求时在服务端动态生成 HTML。
  • 数据获取:通过 getServerSideProps 在请求时获取最新数据。
  • 适用场景:需要实时数据的页面(如用户仪表盘、实时股价)。
  • 优点:内容始终最新,支持个性化渲染(如基于 Cookie 的权限验证)。
  • 缺点:TTFB(首字节时间)较慢,服务端压力大。

实现代码


3. ISR(Incremental Static Regeneration,增量静态再生)

核心特点

  • 生成时机:SSG 的扩展,允许在运行时按需重新生成静态页面。
  • 数据获取:在 getStaticProps 中设置 revalidate 参数(秒),触发条件: • 初次访问时生成静态页面。 • 后续访问时,若超过 revalidate 时间,后台重新生成页面。
  • 适用场景:内容更新频率适中的页面(如电商产品页、新闻列表)。
  • 优点:兼具 SSG 的速度和 SSR 的更新能力,减轻服务端压力。
  • 缺点:再生成期间用户可能看到旧数据。

实现代码


4. CSR(Client-Side Rendering,客户端渲染)

核心特点

  • 生成时机:在客户端浏览器中通过 JavaScript 渲染内容。
  • 数据获取:通过 useEffectSWR 在组件挂载后获取数据。
  • 适用场景:交互性强、无需 SEO 的页面(如用户后台、管理面板)。
  • 优点:减少服务端负载,支持动态交互。
  • 缺点:首屏加载慢,SEO 不友好,依赖客户端 JavaScript。

实现代码


5. 对比表格

特性
SSG
SSR
ISR
CSR
生成时机
构建时
每次请求时
构建时 + 按需再生
客户端运行时
数据实时性
低(需重新构建)
高(实时)
中等(可配置更新间隔)
高(动态获取)
SEO 支持
✅ 最佳
✅ 良好
✅ 良好
❌ 差(需额外处理)
首屏加载速度
⚡️ 最快
⏳ 较慢(依赖服务端)
⚡️ 快(缓存优先)
⏳ 慢(需加载 JS)
适用场景
静态内容
实时数据
频繁更新但非实时内容
交互复杂、无需 SEO
服务端压力

6. 混合使用策略

Next.js 允许在同一个项目中灵活组合多种渲染方式: • SSG + CSR:首屏静态渲染,交互部分客户端加载(如博客的评论模块)。 • SSR + ISR:动态页面初次 SSR,后续通过 ISR 缓存(如新闻详情页)。 • App Router 优化:在 app 目录中,使用 React Server Components 减少客户端 JS 体积。

示例:混合 SSG 和 CSR


7. 选择策略的决策树

  1. 是否需要 SEO? • ✅ 是 → 使用 SSG、SSR 或 ISR。 • ❌ 否 → 使用 CSR。
  1. 数据是否频繁更新? • ✅ 是 → 使用 SSR 或 ISR。 • ❌ 否 → 使用 SSG。
  1. 是否有个性化内容? • ✅ 是 → 使用 SSR。 • ❌ 否 → 使用 SSG 或 ISR。

总结

  • SSG:优先用于内容稳定、SEO 关键的页面。
  • SSR:用于实时数据或个性化内容。
  • ISR:平衡速度与更新频率,适合大规模内容站点。
  • CSR:用于交互复杂、无需 SEO 的功能模块。
  • 混合使用:结合不同策略,最大化性能与功能灵活性。

系列文章

 
]]>
<![CDATA[Next.js 系列之 app router 和 page router 的区别]]> https://codexun.com/posts/nextjs-series-difference-between-app-router-and-page-router 2025-04-04T16:00:00.000Z
Next.js 中的 App Router(应用路由)和 Page Router(页面路由)是两种不同的路由架构,主要区别在于 目录结构、功能特性、数据加载方式及布局管理。以下是详细对比:

1. 目录结构与路由定义

特性
App Router (Next.js 13+)
Page Router (Next.js 12 及更早)
目录位置
app 目录
pages 目录
路由生成方式
基于文件夹路径定义路由(如 app/about/page.js/about
基于文件名自动生成路由(如 pages/about.js/about
动态路由
文件夹名用 [param] 标记(如 app/posts/[id]/page.js
文件名用 [param] 标记(如 pages/posts/[id].js
API 路由
支持 API 路由(如 app/api/route.ts
使用 pages/api 目录

2. 核心功能差异

(1)布局与嵌套路由

  • App Router
嵌套布局:通过 layout.js 文件定义层级布局,自动包裹子页面(如 app/dashboard/layout.js 包裹 app/dashboard/page.js)。
模板与错误处理:支持 template.js(局部刷新布局)和 error.js(错误边界)。
流式加载:通过 loading.js 定义页面加载时的骨架屏。
  • Page Router
全局布局:需通过 _app.js_document.js 自定义全局布局,无法自动嵌套。
手动处理嵌套:需在组件内显式引入布局(如 <Layout><Page /></Layout>)。

(2)数据加载

  • App Router
服务端数据获取:组件可直接使用 async/await 获取数据(默认为 React Server Component)。
并行加载:通过 <Suspense> 分块加载多个数据源。
动态 SEO:通过导出 metadata 对象动态设置页面标题、描述等。
  • Page Router
数据方法:需使用 getStaticProps(SSG)、getServerSideProps(SSR)或 getInitialProps(混合渲染)。
SEO 静态化:需手动在 _document.js 或页面组件内设置 <Head> 标签。

3. 渲染模式与性能

特性
App Router
Page Router
默认渲染模式
支持 React Server Components(服务端组件优先)
默认客户端渲染(需手动选择 SSG/SSR)
流式渲染(Streaming)
支持分块传输内容,优先显示关键部分
需自行实现(如使用 React.lazy
静态生成(SSG)
通过 generateStaticParams 预生成动态路由
通过 getStaticPaths 预生成路由

4. 混合使用与迁移

  • 共存支持:Next.js 13+ 允许 apppages 目录共存,可逐步迁移旧项目。
  • 优先级:若同一路由在 apppages 中均有定义,app 目录的页面优先。
  • 适配性:部分第三方库(如 next-auth)可能需调整配置以兼容 App Router。

5. 适用场景对比

场景
App Router 优势
Page Router 优势
新项目
✅ 推荐使用(功能更现代,性能更优)
❌ 不推荐
旧项目维护
⚠️ 需逐步迁移
✅ 适合保留原有结构
复杂布局需求
✅ 嵌套布局和模板支持完善
❌ 需手动管理嵌套
服务端组件需求
✅ 默认支持服务端渲染和数据获取
❌ 需通过 getServerSideProps 实现

总结

  • App Router 是 Next.js 的未来方向,提供更强大的布局管理、流式渲染和服务端组件支持,适合追求高性能和现代特性的项目。
  • Page Router 适合维护旧项目或简单应用,但功能扩展性较弱。
  • 建议新项目直接采用 App Router,旧项目可逐步迁移以利用新特性。

系列文章

 
]]>
<![CDATA[Next.js 系列之Serverless(无服务器架构)介绍]]> https://codexun.com/posts/nextjs-series-introduction-about-serverless-architecture 2025-04-02T16:00:00.000Z
Serverless(无服务器架构)是一种云计算模型,其核心思想是开发者无需关注底层服务器的运维、扩容和资源分配,只需专注于编写业务代码。云服务商(如 AWS、腾讯云、阿里云)会动态管理计算资源的分配,按需执行代码并自动伸缩。在前端开发中,Serverless 主要用于解决后端服务部署、API 管理和静态资源托管等问题,尤其适合结合 SSR(服务端渲染)技术使用。以下是具体解析:

1. Serverless 的核心特点

  • 无服务器管理:开发者无需自行配置服务器或维护基础设施,云平台自动处理资源调度。
  • 事件驱动:代码通过 HTTP 请求、数据库变更等事件触发执行(如用户访问页面触发 SSR 渲染)。
  • 按需付费:根据实际代码执行时间和资源消耗计费,空闲时不产生费用。
  • 自动伸缩:流量激增时自动扩容,避免因服务器性能不足导致服务中断。

2. 前端开发中 Serverless 的典型应用场景

(1)服务端渲染(SSR)

  • 优化首屏加载与 SEO:通过 Serverless 函数(如 AWS Lambda、腾讯云 SCF)动态生成 HTML,提升页面加载速度和搜索引擎友好性。
    • 示例:Next.js 框架的 SSR 页面可部署为云函数,每个页面路由对应一个独立的函数。
  • 与静态资源分离:将渲染逻辑放在云函数中,静态资源(如图片、CSS)托管至对象存储(如 COS、S3),通过 CDN 加速。

(2)API 服务

  • 轻量级后端:前端开发者可用 Node.js 编写 API(如 Express、Koa),直接部署为 Serverless 函数,替代传统后端服务器。
  • 快速集成云服务:通过 Serverless 组件直接调用数据库、消息队列等云服务,无需自行搭建中间件。

(3)静态网站托管

  • 自动化部署:Vercel 等平台支持将 Next.js、Nuxt.js 等前端框架的构建产物自动托管到全球 CDN,并绑定自定义域名。
  • CI/CD 集成:关联代码仓库后,每次 Git Push 自动触发构建和部署流程。

3. Serverless 对前端的核心价值

  • 降低运维成本:无需学习 Linux 或 Nginx 配置,专注业务代码。
  • 快速迭代:通过 Serverless Framework 或 Vercel CLI 实现一键部署,缩短开发周期。
  • 成本可控:小型项目可享受免费额度(如腾讯云每月 40 万 GBs 函数资源)。
  • 生态兼容性:支持主流框架(Next.js、Nuxt.js)、语言(Node.js、Python)和云平台(AWS、阿里云、腾讯云)。

4. 实践注意事项

  • 冷启动问题:函数首次调用时需初始化环境,可能导致延迟(可通过预置并发缓解)。
  • 代码体积限制:云函数代码包通常需压缩至 50MB 以内,需剔除开发依赖(如 npm install --omit=dev)。
  • 环境适配:部分云平台默认 Node.js 版本较低,需自行升级或通过 Layer 功能绑定运行时。
  • 本地调试:使用 Serverless Framework 或 IDE 插件模拟云环境进行测试。

5. 主流部署方案示例

以 Next.js 应用为例:
  1. Vercel 托管:零配置部署,自动识别路由和 API,适合个人项目。
  1. 腾讯云 Web 函数:通过 serverless.yml 配置入口文件和资源,支持自定义域名和 CDN。
  1. AWS Lambda:利用 @vercel/next 构建器将页面拆分为独立函数,优化性能和资源利用率。

总结

Serverless 为前端开发提供了“无运维化”的可能性,尤其适合需要快速迭代、低成本运维的 SSR 应用和轻量级 API 服务。尽管存在冷启动等挑战,但随着云平台优化和工具链完善(如 Cloud Studio 的一键部署),它已成为现代前端工程化的重要方向。

系列文章

]]>
<![CDATA[Next.js 系列之客户端组件(Client Components)和服务端组件(Server Components)的区别]]> https://codexun.com/posts/nextjs-series-difference-between-client-components-and-server-components 2025-03-31T16:00:00.000Z
Next.js 中客户端组件(Client Components)和服务端组件(Server Components)的核心区别在于运行环境、功能特性及适用场景,以下是详细对比:

1. 运行环境与渲染方式

  • 服务端组件
环境:仅在服务器端运行,生成静态 HTML 发送到客户端。
渲染:支持静态渲染(默认)、动态渲染(需调用 fetch 等 API)和流式渲染(分块加载内容)。
示例代码:直接获取数据并返回 HTML,无需客户端交互逻辑。
  • 客户端组件
环境:在浏览器中运行,支持交互逻辑和浏览器 API(如 windowlocalStorage)。
渲染:首次加载时由服务端生成 HTML 预览,随后通过客户端 JavaScript 进行 Hydration(水合)以实现交互性。
示例代码:使用 useState 管理状态并响应用户操作。

2. 功能特性

特性
服务端组件
客户端组件
数据获取
可直接访问数据库、API 或敏感数据。
需通过客户端请求(如 fetch),数据可能暴露。
React Hooks
不支持 useStateuseEffect 等。
支持所有 React Hooks。
浏览器 API
无法访问。
可访问 windowdocument 等。
性能优化
减少客户端 JS 体积,提升 SEO 和首屏加载速度。
增加客户端 JS 体积,但支持动态交互。
嵌套规则
可包含客户端组件。
不可嵌套服务端组件(仅能通过 Props 传递数据)。

3. 适用场景

  • 服务端组件优先使用的情况
• 静态内容展示(如博客文章、产品列表)。
• 需要直接访问数据库或敏感数据的场景。
• SEO 优化需求高的页面。
  • 客户端组件优先使用的情况
• 用户交互(如表单提交、按钮点击)。
• 动态状态管理(如购物车、计数器)。
• 依赖浏览器 API 的功能(如动画、地理位置)。

4. 混合使用与数据传递

  • 组合方式:服务端组件可通过 Props 将数据传递给客户端组件。例如:
  • 限制:客户端组件无法直接导入服务端组件,需通过 Props 或占位符传递。

5. 性能与安全

  • 服务端优势
• 缓存渲染结果,减少重复请求。
• 敏感逻辑(如数据库查询)保留在服务端,避免泄露。
  • 客户端劣势
• 增加客户端 JS 体积,可能影响加载速度。
• 需谨慎处理用户输入和敏感数据。

总结

服务端组件和客户端组件在 Next.js 中形成互补:
服务端组件 侧重于性能优化、数据安全与静态内容渲染。
客户端组件 专注于交互性和动态功能。
合理混合使用两者(如服务端获取数据后传递给客户端处理交互),可构建高效且用户友好的应用。

系列文章

 
]]>
<![CDATA[个税年度汇算时,申报的劳务报酬总收入小于本年度代开的劳务发票总金额,该如何处理?]]> https://codexun.com/posts/resolve-individual-income-tax-declaration-review 2025-03-24T16:00:00.000Z
2024年度个税汇算退税,从 3月21 号开始不需要预约了,然后抓紧时间对 2024 年的个税进行汇算申报,说不定还能退点税呢。
notion image

1、全年一次性奖金计税方式的选择

趁着周末的时间,打开了个税 APP进行了一番操作,其中 24 年因为有一项是奖金,可以尝试选择 计税方式 ,两种计税方式对比一下,在最后一步查看退税或者需要补税的金额大小,选择最优解。
notion image

2、税务审核不通过

昨天收到短信通知,告知审核不通过。查看个税 APP 审核状态,有如下信息:“由于您申报的收入存在待核实的事项,且纳税人年度汇算时申报的劳务报酬总收入小于本年度代开的劳务发票(不含汇总代开发票)总金额,故不予同意本次退税申请。
notion image
搜索有效信息,审核不通过的这个原因的意思是:2024年度代开了劳务发票,但是扣缴义务人未代扣代缴或少代扣代缴了劳务报酬所得的个人所得税,所以需要您更正年度申报,自行添加未申报或少申报的劳务报酬收入。
仔细查看劳务报酬所得,大概率是 京粉返利 导致的数据有出入了。
有其他人遇到了同样的情况,具体就是 “相关情况为23年个税记录申报后,发票延期至24年开具导致。因为开票与申报时间不匹配的原因导致出现此提醒,实际对应金额的收入平台前期均已正常申报。当前可反馈兆盈侧协助提供说明文件,待出具后您可将说明文件上传至个税APP推送补正材料入口(无入口可联系主管税局沟通推送补正材料入口)。如您需兆盈侧协助提供相应说明材料信息, 可填写下方问卷信息以便协助处理。”
京东返利 23 年的发票延期到 24 年开具导致的。

3、税务审核不通过解决办法

如果 申报的劳务报酬总收入 本年度代开的劳务发票总金额 差别不大的话,可以如下解决。

3.1、查看本年度代开的劳务发票总金额

登录个人所得税APP,点击【办&查】,下滑到【发票管理】模块,选择【我的票夹】。
点击【我销售的】—【筛选】,开票日期选择【自定义】,填写汇算年度(一定要自定义选择时间,2024-01-01—2024-12-31),发票类型分别选择【数电票】和【税控发票】,其他默认【全部】,点击【确定】后进行查询,统计代开发票总金额。
notion image
统计本年度代开发票总金额可以有个技巧,在我的票夹下选择批量管理,把所有的全选,左下角显示即是 24 年度代开发票总金额。
notion image

3.2、查看申报的劳务报酬总收入

申报的劳务报酬总收入 这个比较容易看到,在进行申报的时候点进劳务报酬选项内,有金额合计即是 24 年申报的劳务报酬总收入
notion image

3.3、新增一笔劳务报酬,重新申报

第一次申报审核没有通过的原因,就是申报的劳务报酬总收入【78.06元】小于本年度代开的劳务发票总金额【122. 83 元】,也就是这两个金额对不上。
要解决这个问题,可以在劳务报酬这个页面中,右上角点击新增,点击新增一项劳务报酬所得,新增的金额为 44.77 元【122.83-78.06】,这个根据自己实际情况填写
notion image
新增页面的备注可以参考如下填写:
💡
购物返利未申报部分差额 支付人:宿迁兆盈商服科技有限公司 支付地址:江苏省,宿迁市 价税合计122.83元 已申报金额78.06元 差额44.77元 识别号:91321311MA1X716Q06

3.4、第二天成功审核通过

将以上的重新申报提交之后,第二天查看申报记录,已经成功审核通过啦,下一步就是美美的等着退税到账即可。
notion image
]]>
<![CDATA[ 为博客集成utterances 评论组件]]> https://codexun.com/posts/integrate-utterances-comment-component-in-blog 2025-03-20T16:00:00.000Z
utterances 是一个轻量级的评论插件 Utterances,基于 GitHub Issues 构建,无广告、无跟踪、开源且永久免费。它通过 GitHub OAuth 流程授权用户发表评论,所有数据存储在 GitHub 中,支持多种页面与 Issue 的映射方式,并提供多种主题自定义选项。 

1、utterances工作原理

utterances 是基于 GitHub issues 构建的轻量级评论小部件,所有的评论信息也即是存储在 Github issues 中的,使用 GitHub issues管理博客的评论等。
当博客页面中 utterances 的组件加载时,GitHub issues搜索API将根据urlpathnametitle找到与页面关联的 issues。如果我们找不到与该页面匹配的issue,那么utterances 机器人会在第一次发表评论时自动创建 issue。
用户要发表评论,必须使用Github Oauth授权登录,用户在博客下面发布评论,实质上是在对应的GitHub issue上发表评论。

2、utterances 优点

最主要的优点还是轻量接入,utterances插件通过 GitHub OAuth 授权用户发表评论,或者用户可以直接在 GitHub Issue 上评论。
另外,还有如下特点:
  • 支持多种页面与 Issue 的映射方式,如根据页面路径名、URL、标题或 Open Graph 标题等自动匹配或创建 Issue。
  • 可配置特定 Issue 编号或自定义标题关键词以匹配 Issue,同时支持为创建的 Issue 添加标签。
  • 提供多种主题选项,可以定制样式,并通过简单的 script 标签将 Utterances 集成到博客中。

3、utterances 接入步骤

3.1、创建仓库并安装 utterances

1、然后需要创建一个公开的 github repo,接入utterances之后该仓库的 issues 用于存储博客的评论。
2、在你 github repo 中安装 ,点击左边的链接安装到你 账号中,安装之后可以在用
户设置的 Application 中查看已经安装。
安装utterances
安装utterances
 安装成功,并进行配置
安装成功,并进行配置
然后点击 Configure 配置按钮,确保第一步中的 github repo打开了对 utterances 的操作权限。

3.2、代码配置到 blog 文件中

打开 ,在configuration 中配置 github repo 地址。
💡
注意配置的格式是 owner/repo,其中 owner 是 account name,也就是你 github url中的name。
notion image
然后会得到要嵌入到 blog 系统中的一段代码,根据blog 不同的技术实现,粘贴到相应的博客模板位置即可。
使用.utterances和 .utterances-frame选择器自定义布局和样式。

参考资料

 
]]>
<![CDATA[XAPK是什么文件,如何在安卓上安装XAPK?]]> https://codexun.com/posts/how-to-install-xapk-apk-file 2025-03-19T16:00:00.000Z

什么是XAPK?

XAPK文件是一种文件扩展格式,它与APK格式有些相似,但也有所不同。
可以这么理解: XAPK文件= APK文件+ OBB数据文件。(OBB(Opaque Binary Blob)文件格式,是安卓游戏通用数据包)包含了单独的APK文件和OBB cache assets文件。
Google Play 商店要求压缩APK大小不超过100 MB。用户通过Google Play Console每次上传一个APK时可以选择附带一到两个.obb格式的文件,这种.obb文件可以是大小不超过2 GB的任何格式(ZIP,PDF,MP4等)。
XAPK格式确保用户可以顺利下载大型文件避免中断或失败。

为什么使用XAPK?

APK文件是在Android智能手机上安装应用程序的标准格式。由于大小原因,通常必须单独获取OBB文件。
XAPK是一种zip格式,可将所有应用程序数据保存在一个文件中,以方便安装。如果您要下载XAPK文件,则该文件同时包含OBB和APK部分,以及同一存储库中的缓存,图标和其他信息。
但是,XAPK文件不像APK文件那样,可以通过手机上的默认安装器直接安装到安卓手机上。需要找一些三方工具,比如 XAPK Installer,或者 APKPure。

安装XAPK的方法和工具

1、工具 xapk installer

notion image
可以到 Google Play 上搜索 xapk installer,安装好之后扫描xapk 的文件,或者手动选择到 xapk 的路径,然后打开即可安装。

2、工具Install Buddy: XAPK, APKs

notion image
同上,可以在 google 应用商店搜索该应用。

3、工具ApkPure

APKPure XAPK 安装器可以通过最便捷的方式帮你一键安装和管理安卓设备上的APK和XAPK文件。
可以帮你集中浏览和管理所有XAPK和APK文件,同样也可以通过最简单的方式一键更新或者卸载任意XAPK和APK文件。
notion image
💡
需要注意的是,要为 xapk installer 等这些工具打开文件访问、应用安装(未知来源)的权限。
 
]]>
<![CDATA[使用自定义 GitHub Actions CI/CD 部署到 Vercel]]> https://codexun.com/posts/github-actions-deploy-vercel 2025-03-16T16:00:00.000Z
除了上一篇介绍的 使用 Github Action自动执行Vercel 部署 使用Deploy Hooks 的方式进行部署之外,还可以有更复杂的场景。
比如可以将 Vercel 与 GitHub Actions 一起使用作为您的 CI/CD 提供程序,在每次推送代码时生成预览部署,并在代码合并到main分支时部署到生产环境。
这种则需要使用到 Vercel 的访问令牌 access_token 等。

1、获取相关访问令牌

获取VERCEL_TOKENVERCEL_ORG_IDVERCEL_PROJECT_ID 相关token。

1.1、获取 Vercel api 访问令牌VERCEL_TOKEN

在 个人账号设置 → Token 菜单下,创建 api 访问令牌,也即是VERCEL_TOKEN
notion image

1.2、获取VERCEL_PROJECT_ID

在Vercel 具体项目下, 项目设置 下找到 Project Id。
notion image

1.3、获取VERCEL_ORG_ID

  • 使用命令行npm i -g vercel安装Vercel CLI并运行vercel login
  • 在新建文件夹中,运行vercel link以创建一个新的 Vercel 项目,或者是已有的Git 项目,会提示 ✅  Linked to xxx-projects/next-starter-example (created .vercel) 并生成.vercel 文件夹。
  • 在生成的.vercel文件夹中,从project.json{"projectId":"prj_xxx","orgId":"team_xxx"}保存projectId和orgId。
💡
在Account Setting→General 菜单下,有Vercel ID[This is your user ID within Vercel.] API Token,是否可以作为VERCEL_ORG_ID[未验证]
notion image

1.4、配置到 Github 中

将以上VERCEL_TOKENVERCEL_ORG_IDVERCEL_PROJECT_ID添加到 GitHub 项目的 actions secret 配置中。
notion image

2、配置 Github Actions

当代码推送到非 main 分支时,生成预览部署:
 
当代码推送到 main 分支时,生成正式部署:

3、借助marketplace 上的 Github Actions 实现

也可以借助一些已经实现好的 actions 来实现我们的需求。比如:

3.1、代码推送或者发起 pull request 时触发

3.2、另一例:deploy-to-vercel-action

使用 GitHub Actions 将您的项目/站点部署到Vercel。在何时部署站点方面,它比 Vercel 的 GitHub 集成提供了更多的自定义功能。使用 GitHub Actions Events,您可以选择部署每个提交,仅在新版本上或甚至在 cron 计划上部署。该操作还可以部署每个 PR 并使用自定义预览 URL 对其进行评论。它使用 Vercel CLI,也可以自动在 GitHub 上创建部署。

参考资料

 
]]>
<![CDATA[使用 Github Action自动执行Vercel 部署]]> https://codexun.com/posts/automating-vercel-deployment-with-github-actions 2025-03-15T16:00:00.000Z
之前本网站部署在 Netlify 上的,有过一篇文章使用 Github Action自动执行 Netlify 部署以解决每周自动部署网站的功能,详细可点击查看。
最近想查看下国内访问网站的速度情况,所以使用 itdog ping 工具进行了测试,发现国内的情况十分不理想。
所以萌生了起换到 vercel 上的想法,并且 vercel 也有 cdn 功能了,右边是切换到 vercel 上部署的情况,看起来好了很多。
notion image
 
notion image
切到 vercel 重新部署,域名重新解析配置好之后,对于之前 github action 定时部署的情况,需要重新写一份 workflow job。
搜索vercel 同样支持 Deploy Hook 的方式。那就简单了,复制一份 Netlify 的文件,简单修改即可。

1、配置创建 Vercel Build Hooks

参考 Creating & Triggering Deploy Hooks 官方文档。
官方说的清清楚,部署钩子允许您创建接受 HTTPPOST请求的 URL,以触发部署并重新运行构建步骤。这些 URL 与您的项目、存储库和分支唯一链接,因此无需使用任何身份验证机制或向请求提供任何有效负载POST
此功能允许您将 Vercel 部署与其他系统集成。例如,您可以设置:
  • 来自 Headless CMS 的内容更改的自动部署
  • 通过配置第三方 cron 作业服务来触发 Deploy Hook 来进行计划部署
  • 通过命令行强制部署
在vercel 项目设置→Git中找到 Deploy Hooks 创建的地方,输入 hooks 名字,和代码分支,即可创建。
notion image

2、创建 GitHub Actions secrets and variables

在Github 的项目Setting下设置 github actions 所需要的变量。 例如,创建VECEL_BUILD_HOOK变量,value 为上一步获得的 vecel build hook 地址。
notion image

3、实现 GitHub Actions

触发 hooks 的示例请求为:
响应示例:
发送请求后,您可以在项目仪表板上看到它触发了部署。
那么,实现 github actions 代码就比较简单了,参考如下:

参考资料

 
]]>
<![CDATA[GitHub Actions:带有输入的调度和计划工作流程]]> https://codexun.com/posts/github-actions-workflow-with-inputs 2025-03-14T16:00:00.000Z
最近编写了一个项目,需要每天定时从 producthunt 抓取数据并生成阅读良好的 markdown 文档,项目已经上线,参考地址
除此之外,还希望能够输入日期,手动触发抓取这一天的数据。
也就是,工作流有输入。当工作流由 cron 触发时,我需要它使用一些默认变量运行。当手动触发时,我想允许用户覆盖一些默认值。
notion image

Github Actions 工作流示例

比如:有如下 github actions 工作流:
每隔一段时间,输出一段文字Periodically printing passages
如果手动触发时,允许输入参数覆盖这一段文字,可以在定义工作流中,使用 inputs 来定义可以接收的输入,参考如下:
我可以在 GitHub 中的 Actions 标签中触发此操作:
notion image
让这个工作发挥作用的关键是:
echo "MESSAGE=${{ github.event.inputs.text_to_print || env.DEFAULT_MESSAGE }}" >> $GITHUB_ENV
上面一行选择将定义的变量赋值给变量,MESSAGE然后将其注入到变量中$GITHUB_ENV。我们可以在Print some text步骤中引用它。

参考资料

 
]]>
This XML file does not appear to have any style information associated with it. The document tree is shown below.
<feed xmlns="http://www.w3.org/2005/Atom">
<id>https://codexun.com</id>
<title>码寻_CodeXun</title>
<updated>2025-04-18T13:36:20.674Z</updated>
<generator>https://github.com/jpmonette/feed</generator>
<author>
<name>CodeXun</name>
<uri>https://codexun.com</uri>
</author>
<link rel="alternate" href="https://codexun.com"/>
<subtitle>技术分享:前后端、Node.js、React、Vue3s</subtitle>
<icon>https://codexun.com/favicon.svg</icon>
<rights>All rights reserved 2025, CodeXun</rights>
<entry>
<title type="html">
<![CDATA[ Next.js 系列之的SSG、SSR、ISR、CSR 的详细介绍和区别 ]]>
</title>
<id>https://codexun.com/posts/nextjs-series-difference-between-ssg-ssr-isr-and-csr-in-nextjs</id>
<link href="https://codexun.com/posts/nextjs-series-difference-between-ssg-ssr-isr-and-csr-in-nextjs"/>
<updated>2025-04-06T16:00:00.000Z</updated>
<summary type="html">
<![CDATA[ Next.js 提供了多种渲染策略(SSG、SSR、ISR、CSR),每种策略适用于不同的场景。以下是它们的核心区别、实现方式及最佳实践。- SSG:优先用于内容稳定、SEO 关键的页面。- SSR:用于实时数据或个性化内容。- ISR:平衡速度与更新频率,适合大规模内容站点。- CSR:用于交互复杂、无需 SEO 的功能模块。- 混合使用:结合不同策略,最大化性能与功能灵活性。 ]]>
</summary>
<content type="html">
<![CDATA[ <main class="notion light-mode notion-page notion-block-1d1e3f3674f980508840c25cfdce9b4a"><div class="notion-viewport"></div><div class="notion-collection-page-properties"></div><div class="notion-text notion-block-1d1e3f3674f980929c5fd35c63396a34">Next.js 提供了多种渲染策略(SSG、SSR、ISR、CSR),每种策略适用于不同的场景。以下是它们的核心区别、实现方式及最佳实践:</div><hr class="notion-hr notion-block-1d1e3f3674f98023931dcf8a687b2f8c"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f9806f8aaad2bb7289c16f" data-id="1d1e3f3674f9806f8aaad2bb7289c16f"><span><div id="1d1e3f3674f9806f8aaad2bb7289c16f" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f9806f8aaad2bb7289c16f" title="1. SSG(Static Site Generation,静态生成)"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1. SSG(Static Site Generation,静态生成)</b></span></span></h2><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1d1e3f3674f98097bcb6efdd018522ba" data-id="1d1e3f3674f98097bcb6efdd018522ba"><span><div id="1d1e3f3674f98097bcb6efdd018522ba" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f98097bcb6efdd018522ba" title="核心特点"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>核心特点</b></span></span></h3><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980698907cdb799cbb78a"><li><b>生成时机</b>:在构建时(<code class="notion-inline-code">next build</code>)生成静态 HTML。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f9803aafe8f18c2de23651"><li><b>数据获取</b>:通过 <code class="notion-inline-code">getStaticProps</code> 获取数据,支持预渲染所有页面。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f9800fae3fd9d03ec6d8cd"><li><b>适用场景</b>:内容不经常变化的页面(如博客、文档、营销页)。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f9802e89c0c47147c43d2a"><li><b>优点</b>:加载最快、SEO 友好、CDN 缓存友好。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980a2b6f7f506dfe9d333"><li><b>缺点</b>:无法实时更新内容,需重新构建才能更新。</li></ul><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1d1e3f3674f9809daceef78c54373293" data-id="1d1e3f3674f9809daceef78c54373293"><span><div id="1d1e3f3674f9809daceef78c54373293" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f9809daceef78c54373293" title="实现代码"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>实现代码</b></span></span></h3><hr class="notion-hr notion-block-1d1e3f3674f98034a784f0ce23da9528"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f9807599fcd80205c05990" data-id="1d1e3f3674f9807599fcd80205c05990"><span><div id="1d1e3f3674f9807599fcd80205c05990" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f9807599fcd80205c05990" title="2. SSR(Server-Side Rendering,服务端渲染)"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>2. SSR(Server-Side Rendering,服务端渲染)</b></span></span></h2><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1d1e3f3674f98034940dd05416d806b7" data-id="1d1e3f3674f98034940dd05416d806b7"><span><div id="1d1e3f3674f98034940dd05416d806b7" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f98034940dd05416d806b7" title="核心特点"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>核心特点</b></span></span></h3><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980f8ad08cf5c1d4ae901"><li><b>生成时机</b>:每次页面请求时在服务端动态生成 HTML。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f98087923cd8d922dee168"><li><b>数据获取</b>:通过 <code class="notion-inline-code">getServerSideProps</code> 在请求时获取最新数据。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980d7b0ebe33188253d70"><li><b>适用场景</b>:需要实时数据的页面(如用户仪表盘、实时股价)。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f9804ba2efed41710aaf9c"><li><b>优点</b>:内容始终最新,支持个性化渲染(如基于 Cookie 的权限验证)。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980dd9040e9910b1d409d"><li><b>缺点</b>:TTFB(首字节时间)较慢,服务端压力大。</li></ul><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1d1e3f3674f9805b9609d857b8a568cb" data-id="1d1e3f3674f9805b9609d857b8a568cb"><span><div id="1d1e3f3674f9805b9609d857b8a568cb" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f9805b9609d857b8a568cb" title="实现代码"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>实现代码</b></span></span></h3><hr class="notion-hr notion-block-1d1e3f3674f980bea04dc82bd4f97ab4"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f98080b51ef4b6435c26a8" data-id="1d1e3f3674f98080b51ef4b6435c26a8"><span><div id="1d1e3f3674f98080b51ef4b6435c26a8" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f98080b51ef4b6435c26a8" title="3. ISR(Incremental Static Regeneration,增量静态再生)"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>3. ISR(Incremental Static Regeneration,增量静态再生)</b></span></span></h2><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1d1e3f3674f980ab9f88d7997467cd22" data-id="1d1e3f3674f980ab9f88d7997467cd22"><span><div id="1d1e3f3674f980ab9f88d7997467cd22" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f980ab9f88d7997467cd22" title="核心特点"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>核心特点</b></span></span></h3><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f98041b484d4f1367c2967"><li><b>生成时机</b>:SSG 的扩展,允许在运行时按需重新生成静态页面。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f98006aa25d05bbb0d9460"><li><b>数据获取</b>:在 <code class="notion-inline-code">getStaticProps</code> 中设置 <code class="notion-inline-code">revalidate</code> 参数(秒),触发条件: • 初次访问时生成静态页面。 • 后续访问时,若超过 <code class="notion-inline-code">revalidate</code> 时间,后台重新生成页面。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f98070a2cef37f6683d556"><li><b>适用场景</b>:内容更新频率适中的页面(如电商产品页、新闻列表)。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f9809aa7cecb7f758152da"><li><b>优点</b>:兼具 SSG 的速度和 SSR 的更新能力,减轻服务端压力。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f9808aa4eefd7cf20db187"><li><b>缺点</b>:再生成期间用户可能看到旧数据。</li></ul><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1d1e3f3674f9809998c8ee9bea076105" data-id="1d1e3f3674f9809998c8ee9bea076105"><span><div id="1d1e3f3674f9809998c8ee9bea076105" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f9809998c8ee9bea076105" title="实现代码"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>实现代码</b></span></span></h3><hr class="notion-hr notion-block-1d1e3f3674f98016b7fcf59e1cbce9d5"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f980b9ba82ebbeadb623d9" data-id="1d1e3f3674f980b9ba82ebbeadb623d9"><span><div id="1d1e3f3674f980b9ba82ebbeadb623d9" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f980b9ba82ebbeadb623d9" title="4. CSR(Client-Side Rendering,客户端渲染)"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>4. CSR(Client-Side Rendering,客户端渲染)</b></span></span></h2><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1d1e3f3674f980a49717d19714cf5864" data-id="1d1e3f3674f980a49717d19714cf5864"><span><div id="1d1e3f3674f980a49717d19714cf5864" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f980a49717d19714cf5864" title="核心特点"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>核心特点</b></span></span></h3><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980aaa131e475ae98a746"><li><b>生成时机</b>:在客户端浏览器中通过 JavaScript 渲染内容。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f98038a599fb254318b5e4"><li><b>数据获取</b>:通过 <code class="notion-inline-code">useEffect</code> 或 <code class="notion-inline-code">SWR</code> 在组件挂载后获取数据。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980dd8c90cac76ca6d68d"><li><b>适用场景</b>:交互性强、无需 SEO 的页面(如用户后台、管理面板)。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f9809797bec7a5b7525c42"><li><b>优点</b>:减少服务端负载,支持动态交互。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980c49455d4421c115869"><li><b>缺点</b>:首屏加载慢,SEO 不友好,依赖客户端 JavaScript。</li></ul><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1d1e3f3674f98025bfc8f2a4da509b15" data-id="1d1e3f3674f98025bfc8f2a4da509b15"><span><div id="1d1e3f3674f98025bfc8f2a4da509b15" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f98025bfc8f2a4da509b15" title="实现代码"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>实现代码</b></span></span></h3><hr class="notion-hr notion-block-1d1e3f3674f980bbbc3ac4aa6baf893d"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f9808aa907e469ae6b308f" data-id="1d1e3f3674f9808aa907e469ae6b308f"><span><div id="1d1e3f3674f9808aa907e469ae6b308f" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f9808aa907e469ae6b308f" title="5. 对比表格"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>5. 对比表格</b></span></span></h2><table class="notion-simple-table notion-block-1d1e3f3674f980b7aacbc27dd56efd76"><tbody><tr class="notion-simple-table-row notion-block-1d1e3f3674f980748572f0ef251d281b"><td class="" style="width:130px"><div class="notion-simple-table-cell"><b>特性</b></div></td><td class="" style="width:185px"><div class="notion-simple-table-cell"><b>SSG</b></div></td><td class="" style="width:183px"><div class="notion-simple-table-cell"><b>SSR</b></div></td><td class="" style="width:216px"><div class="notion-simple-table-cell"><b>ISR</b></div></td><td class="" style="width:218.90625px"><div class="notion-simple-table-cell"><b>CSR</b></div></td></tr><tr class="notion-simple-table-row notion-block-1d1e3f3674f980a2ba09e4d235db7b24"><td class="" style="width:130px"><div class="notion-simple-table-cell"><b>生成时机</b></div></td><td class="" style="width:185px"><div class="notion-simple-table-cell">构建时</div></td><td class="" style="width:183px"><div class="notion-simple-table-cell">每次请求时</div></td><td class="" style="width:216px"><div class="notion-simple-table-cell">构建时 + 按需再生</div></td><td class="" style="width:218.90625px"><div class="notion-simple-table-cell">客户端运行时</div></td></tr><tr class="notion-simple-table-row notion-block-1d1e3f3674f9807f9912dd4bc221fc06"><td class="" style="width:130px"><div class="notion-simple-table-cell"><b>数据实时性</b></div></td><td class="" style="width:185px"><div class="notion-simple-table-cell">低(需重新构建)</div></td><td class="" style="width:183px"><div class="notion-simple-table-cell">高(实时)</div></td><td class="" style="width:216px"><div class="notion-simple-table-cell">中等(可配置更新间隔)</div></td><td class="" style="width:218.90625px"><div class="notion-simple-table-cell">高(动态获取)</div></td></tr><tr class="notion-simple-table-row notion-block-1d1e3f3674f98082b49edadd67ae3c0f"><td class="" style="width:130px"><div class="notion-simple-table-cell"><b>SEO 支持</b></div></td><td class="" style="width:185px"><div class="notion-simple-table-cell">✅ 最佳</div></td><td class="" style="width:183px"><div class="notion-simple-table-cell">✅ 良好</div></td><td class="" style="width:216px"><div class="notion-simple-table-cell">✅ 良好</div></td><td class="" style="width:218.90625px"><div class="notion-simple-table-cell">❌ 差(需额外处理)</div></td></tr><tr class="notion-simple-table-row notion-block-1d1e3f3674f98034abdac887b6ba471b"><td class="" style="width:130px"><div class="notion-simple-table-cell"><b>首屏加载速度</b></div></td><td class="" style="width:185px"><div class="notion-simple-table-cell">⚡️ 最快</div></td><td class="" style="width:183px"><div class="notion-simple-table-cell">⏳ 较慢(依赖服务端)</div></td><td class="" style="width:216px"><div class="notion-simple-table-cell">⚡️ 快(缓存优先)</div></td><td class="" style="width:218.90625px"><div class="notion-simple-table-cell">⏳ 慢(需加载 JS)</div></td></tr><tr class="notion-simple-table-row notion-block-1d1e3f3674f9801f850bec589d688a86"><td class="" style="width:130px"><div class="notion-simple-table-cell"><b>适用场景</b></div></td><td class="" style="width:185px"><div class="notion-simple-table-cell">静态内容</div></td><td class="" style="width:183px"><div class="notion-simple-table-cell">实时数据</div></td><td class="" style="width:216px"><div class="notion-simple-table-cell">频繁更新但非实时内容</div></td><td class="" style="width:218.90625px"><div class="notion-simple-table-cell">交互复杂、无需 SEO</div></td></tr><tr class="notion-simple-table-row notion-block-1d1e3f3674f980e5b29cea8d387896fb"><td class="" style="width:130px"><div class="notion-simple-table-cell"><b>服务端压力</b></div></td><td class="" style="width:185px"><div class="notion-simple-table-cell">无</div></td><td class="" style="width:183px"><div class="notion-simple-table-cell">高</div></td><td class="" style="width:216px"><div class="notion-simple-table-cell">低</div></td><td class="" style="width:218.90625px"><div class="notion-simple-table-cell">无</div></td></tr></tbody></table><hr class="notion-hr notion-block-1d1e3f3674f98045ae4cfed5be2f5c59"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f9803db259eff114e5444e" data-id="1d1e3f3674f9803db259eff114e5444e"><span><div id="1d1e3f3674f9803db259eff114e5444e" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f9803db259eff114e5444e" title="6. 混合使用策略"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>6. 混合使用策略</b></span></span></h2><div class="notion-text notion-block-1d1e3f3674f980ee82faeee5a2783be7">Next.js 允许在同一个项目中灵活组合多种渲染方式: • <b>SSG + CSR</b>:首屏静态渲染,交互部分客户端加载(如博客的评论模块)。 • <b>SSR + ISR</b>:动态页面初次 SSR,后续通过 ISR 缓存(如新闻详情页)。 • <b>App Router 优化</b>:在 <code class="notion-inline-code">app</code> 目录中,使用 React Server Components 减少客户端 JS 体积。</div><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1d1e3f3674f9803da63af0a8b4a41193" data-id="1d1e3f3674f9803da63af0a8b4a41193"><span><div id="1d1e3f3674f9803da63af0a8b4a41193" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f9803da63af0a8b4a41193" title="示例:混合 SSG 和 CSR"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>示例:混合 SSG 和 CSR</b></span></span></h3><hr class="notion-hr notion-block-1d1e3f3674f9808ea08edab8907c1144"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f98077bffae41b4456ee83" data-id="1d1e3f3674f98077bffae41b4456ee83"><span><div id="1d1e3f3674f98077bffae41b4456ee83" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f98077bffae41b4456ee83" title="7. 选择策略的决策树"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>7. 选择策略的决策树</b></span></span></h2><ol start="1" class="notion-list notion-list-numbered notion-block-1d1e3f3674f980afbd38cf81a57599ff"><li><b>是否需要 SEO?</b> • ✅ 是 → 使用 SSG、SSR 或 ISR。 • ❌ 否 → 使用 CSR。</li></ol><ol start="2" class="notion-list notion-list-numbered notion-block-1d1e3f3674f980e89e27d6d1a2ea3515"><li><b>数据是否频繁更新?</b> • ✅ 是 → 使用 SSR 或 ISR。 • ❌ 否 → 使用 SSG。</li></ol><ol start="3" class="notion-list notion-list-numbered notion-block-1d1e3f3674f980598b64c53664eda797"><li><b>是否有个性化内容?</b> • ✅ 是 → 使用 SSR。 • ❌ 否 → 使用 SSG 或 ISR。</li></ol><hr class="notion-hr notion-block-1d1e3f3674f98025b157ff0c798d7fb9"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f9803381cfe95d5e387b38" data-id="1d1e3f3674f9803381cfe95d5e387b38"><span><div id="1d1e3f3674f9803381cfe95d5e387b38" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f9803381cfe95d5e387b38" title="总结"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>总结</b></span></span></h2><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980e9afcbc59fe3b5ed1e"><li><b>SSG</b>:优先用于内容稳定、SEO 关键的页面。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980f38c01e2451dbd7082"><li><b>SSR</b>:用于实时数据或个性化内容。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980c28b45f4cae155e05c"><li><b>ISR</b>:平衡速度与更新频率,适合大规模内容站点。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f9805e9d5cc23d60305418"><li><b>CSR</b>:用于交互复杂、无需 SEO 的功能模块。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f9802ba844f1be2bf07cae"><li><b>混合使用</b>:结合不同策略,最大化性能与功能灵活性。</li></ul><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f980a09525f6afe6f9ac3c" data-id="1d1e3f3674f980a09525f6afe6f9ac3c"><span><div id="1d1e3f3674f980a09525f6afe6f9ac3c" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f980a09525f6afe6f9ac3c" title="系列文章"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">系列文章</span></span></h2><div class="notion-text notion-block-1d1e3f3674f9805fbf9dd89d78bbc6c4"><b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://codexun.com/posts/nextjs-series-difference-between-client-components-and-server-components">Next.js 系列之客户端组件(Client Components)和服务端组件(Server Components)的区别</a></b></div><div class="notion-text notion-block-1d1e3f3674f9806593b2e9d27fb2c9b9"><b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://codexun.com/posts/nextjs-series-introduction-about-serverless-architecture">Next.js 系列之Serverless(无服务器架构)介绍</a></b></div><div class="notion-text notion-block-1d1e3f3674f980bdbbb8ff738390c894"><b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://codexun.com/posts/nextjs-series-difference-between-app-router-and-page-router">Next.js 系列之 app router 和 page router 的区别</a></b></div><div class="notion-text notion-block-1d1e3f3674f980e8a890eb2ebc341ddc"><b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://codexun.com/posts/nextjs-series-difference-between-ssg-ssr-isr-and-csr-in-nextjs">Next.js 系列之的SSG、SSR、ISR、CSR 的详细介绍和区别</a></b></div><div class="notion-blank notion-block-1d1e3f3674f980b59032ccc4dbda9289"> </div></main> ]]>
</content>
</entry>
<entry>
<title type="html">
<![CDATA[ Next.js 系列之 app router 和 page router 的区别 ]]>
</title>
<id>https://codexun.com/posts/nextjs-series-difference-between-app-router-and-page-router</id>
<link href="https://codexun.com/posts/nextjs-series-difference-between-app-router-and-page-router"/>
<updated>2025-04-04T16:00:00.000Z</updated>
<summary type="html">
<![CDATA[ Next.js 中的 App Router(应用路由)和 Page Router(页面路由)是两种不同的路由架构,主要区别在于 目录结构、功能特性、数据加载方式及布局管理。- App Router 是 Next.js 的未来方向,提供更强大的布局管理、流式渲染和服务端组件支持,适合追求高性能和现代特性的项目。- Page Router 适合维护旧项目或简单应用,但功能扩展性较弱。- 建议新项目直接采用 App Router,旧项目可逐步迁移以利用新特性。 ]]>
</summary>
<content type="html">
<![CDATA[ <main class="notion light-mode notion-page notion-block-1d1e3f3674f980db95a4e6516605756f"><div class="notion-viewport"></div><div class="notion-collection-page-properties"></div><div class="notion-text notion-block-1d1e3f3674f980e5adf7cfc508bb03ac">Next.js 中的 App Router(应用路由)和 Page Router(页面路由)是两种不同的路由架构,主要区别在于 <b>目录结构、功能特性、数据加载方式及布局管理</b>。以下是详细对比:</div><hr class="notion-hr notion-block-1d1e3f3674f980baa022f626b4991627"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f980c89674de33476da81c" data-id="1d1e3f3674f980c89674de33476da81c"><span><div id="1d1e3f3674f980c89674de33476da81c" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f980c89674de33476da81c" title="1. 目录结构与路由定义"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1. 目录结构与路由定义</b></span></span></h2><table class="notion-simple-table notion-block-1d1e3f3674f980a18f72d9f233e9cbe4"><tbody><tr class="notion-simple-table-row notion-block-1d1e3f3674f98056ba1fc9fcef69d383"><td class="" style="width:120px"><div class="notion-simple-table-cell"><b>特性</b></div></td><td class="" style="width:306px"><div class="notion-simple-table-cell"><b>App Router</b> (Next.js 13+)</div></td><td class="" style="width:427px"><div class="notion-simple-table-cell"><b>Page Router</b> (Next.js 12 及更早)</div></td></tr><tr class="notion-simple-table-row notion-block-1d1e3f3674f980fe8e21d23d0c94266a"><td class="" style="width:120px"><div class="notion-simple-table-cell"><b>目录位置</b></div></td><td class="" style="width:306px"><div class="notion-simple-table-cell"><code class="notion-inline-code">app</code> 目录</div></td><td class="" style="width:427px"><div class="notion-simple-table-cell"><code class="notion-inline-code">pages</code> 目录</div></td></tr><tr class="notion-simple-table-row notion-block-1d1e3f3674f980679646c14ce1ece391"><td class="" style="width:120px"><div class="notion-simple-table-cell"><b>路由生成方式</b></div></td><td class="" style="width:306px"><div class="notion-simple-table-cell">基于文件夹路径定义路由(如 <code class="notion-inline-code">app/about/page.js</code> → <code class="notion-inline-code">/about</code>)</div></td><td class="" style="width:427px"><div class="notion-simple-table-cell">基于文件名自动生成路由(如 <code class="notion-inline-code">pages/about.js</code> → <code class="notion-inline-code">/about</code>)</div></td></tr><tr class="notion-simple-table-row notion-block-1d1e3f3674f980f6bd82efcb2016c049"><td class="" style="width:120px"><div class="notion-simple-table-cell"><b>动态路由</b></div></td><td class="" style="width:306px"><div class="notion-simple-table-cell">文件夹名用 <code class="notion-inline-code">[param]</code> 标记(如 <code class="notion-inline-code">app/posts/[id]/page.js</code>)</div></td><td class="" style="width:427px"><div class="notion-simple-table-cell">文件名用 <code class="notion-inline-code">[param]</code> 标记(如 <code class="notion-inline-code">pages/posts/[id].js</code>)</div></td></tr><tr class="notion-simple-table-row notion-block-1d1e3f3674f980f7a3e9e1ba91ff3589"><td class="" style="width:120px"><div class="notion-simple-table-cell"><b>API 路由</b></div></td><td class="" style="width:306px"><div class="notion-simple-table-cell">支持 API 路由(如 <code class="notion-inline-code">app/api/route.ts</code>)</div></td><td class="" style="width:427px"><div class="notion-simple-table-cell">使用 <code class="notion-inline-code">pages/api</code> 目录</div></td></tr></tbody></table><hr class="notion-hr notion-block-1d1e3f3674f9803c99bed5b4c0078762"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f980558daee657f2fc9dd4" data-id="1d1e3f3674f980558daee657f2fc9dd4"><span><div id="1d1e3f3674f980558daee657f2fc9dd4" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f980558daee657f2fc9dd4" title="2. 核心功能差异"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>2. 核心功能差异</b></span></span></h2><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1d1e3f3674f980ed9016f030d29377dd" data-id="1d1e3f3674f980ed9016f030d29377dd"><span><div id="1d1e3f3674f980ed9016f030d29377dd" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f980ed9016f030d29377dd" title="(1)布局与嵌套路由"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>(1)布局与嵌套路由</b></span></span></h3><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f9806b8251e755ce0821c4"><li><b>App Router</b></li></ul><div class="notion-text notion-block-1d1e3f3674f980229c0dd33df7ccf3f5">• <b>嵌套布局</b>:通过 <code class="notion-inline-code">layout.js</code> 文件定义层级布局,自动包裹子页面(如 <code class="notion-inline-code">app/dashboard/layout.js</code> 包裹 <code class="notion-inline-code">app/dashboard/page.js</code>)。</div><div class="notion-text notion-block-1d1e3f3674f980c89fdbd25c24da4ebf">• <b>模板与错误处理</b>:支持 <code class="notion-inline-code">template.js</code>(局部刷新布局)和 <code class="notion-inline-code">error.js</code>(错误边界)。</div><div class="notion-text notion-block-1d1e3f3674f980188c1efb5d6b86a529">• <b>流式加载</b>:通过 <code class="notion-inline-code">loading.js</code> 定义页面加载时的骨架屏。</div><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980bbbe2ac7e2a00efbfb"><li><b>Page Router</b></li></ul><div class="notion-text notion-block-1d1e3f3674f9803e81d6e25e27562175">• <b>全局布局</b>:需通过 <code class="notion-inline-code">_app.js</code> 和 <code class="notion-inline-code">_document.js</code> 自定义全局布局,无法自动嵌套。</div><div class="notion-text notion-block-1d1e3f3674f9807fbeb7fd9821179b9b">• <b>手动处理嵌套</b>:需在组件内显式引入布局(如 <code class="notion-inline-code">&lt;Layout&gt;&lt;Page /&gt;&lt;/Layout&gt;</code>)。</div><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1d1e3f3674f98080a03cc8dfe9651eb2" data-id="1d1e3f3674f98080a03cc8dfe9651eb2"><span><div id="1d1e3f3674f98080a03cc8dfe9651eb2" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f98080a03cc8dfe9651eb2" title="(2)数据加载"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>(2)数据加载</b></span></span></h3><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f98004afd8e4540e105e5c"><li><b>App Router</b></li></ul><div class="notion-text notion-block-1d1e3f3674f980e5af9cef0b8fcae3f5">• <b>服务端数据获取</b>:组件可直接使用 <code class="notion-inline-code">async/await</code> 获取数据(默认为 React Server Component)。</div><div class="notion-text notion-block-1d1e3f3674f98098ab86f15136b6780d">• <b>并行加载</b>:通过 <code class="notion-inline-code">&lt;Suspense&gt;</code> 分块加载多个数据源。</div><div class="notion-text notion-block-1d1e3f3674f9803e965fed76241d42fd">• <b>动态 SEO</b>:通过导出 <code class="notion-inline-code">metadata</code> 对象动态设置页面标题、描述等。</div><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f9804a91eefe54dd628e4d"><li><b>Page Router</b></li></ul><div class="notion-text notion-block-1d1e3f3674f9809b9197c97ae9581de4">• <b>数据方法</b>:需使用 <code class="notion-inline-code">getStaticProps</code>(SSG)、<code class="notion-inline-code">getServerSideProps</code>(SSR)或 <code class="notion-inline-code">getInitialProps</code>(混合渲染)。</div><div class="notion-text notion-block-1d1e3f3674f98007b065e2df6888701d">• <b>SEO 静态化</b>:需手动在 <code class="notion-inline-code">_document.js</code> 或页面组件内设置 <code class="notion-inline-code">&lt;Head&gt;</code> 标签。</div><hr class="notion-hr notion-block-1d1e3f3674f9809dac7aead04ebd4dc5"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f9808a9732c31c4c66ee70" data-id="1d1e3f3674f9808a9732c31c4c66ee70"><span><div id="1d1e3f3674f9808a9732c31c4c66ee70" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f9808a9732c31c4c66ee70" title="3. 渲染模式与性能"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>3. 渲染模式与性能</b></span></span></h2><table class="notion-simple-table notion-block-1d1e3f3674f980b192acef43b26095c8"><tbody><tr class="notion-simple-table-row notion-block-1d1e3f3674f980ce95c6f13685adc155"><td class="" style="width:183.9921875px"><div class="notion-simple-table-cell"><b>特性</b></div></td><td class="" style="width:401px"><div class="notion-simple-table-cell"><b>App Router</b></div></td><td class="" style="width:359.0078125px"><div class="notion-simple-table-cell"><b>Page Router</b></div></td></tr><tr class="notion-simple-table-row notion-block-1d1e3f3674f9807aa3c6df7a20453f3c"><td class="" style="width:183.9921875px"><div class="notion-simple-table-cell"><b>默认渲染模式</b></div></td><td class="" style="width:401px"><div class="notion-simple-table-cell">支持 React Server Components(服务端组件优先)</div></td><td class="" style="width:359.0078125px"><div class="notion-simple-table-cell">默认客户端渲染(需手动选择 SSG/SSR)</div></td></tr><tr class="notion-simple-table-row notion-block-1d1e3f3674f98052af0de6334a1ed623"><td class="" style="width:183.9921875px"><div class="notion-simple-table-cell"><b>流式渲染(Streaming)</b></div></td><td class="" style="width:401px"><div class="notion-simple-table-cell">支持分块传输内容,优先显示关键部分</div></td><td class="" style="width:359.0078125px"><div class="notion-simple-table-cell">需自行实现(如使用 <code class="notion-inline-code">React.lazy</code>)</div></td></tr><tr class="notion-simple-table-row notion-block-1d1e3f3674f98093a6d9f1ab2654510c"><td class="" style="width:183.9921875px"><div class="notion-simple-table-cell"><b>静态生成(SSG)</b></div></td><td class="" style="width:401px"><div class="notion-simple-table-cell">通过 <code class="notion-inline-code">generateStaticParams</code> 预生成动态路由</div></td><td class="" style="width:359.0078125px"><div class="notion-simple-table-cell">通过 <code class="notion-inline-code">getStaticPaths</code> 预生成路由</div></td></tr></tbody></table><hr class="notion-hr notion-block-1d1e3f3674f9806aa84bd867644ce02a"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f98030ad23f1ef15e0f821" data-id="1d1e3f3674f98030ad23f1ef15e0f821"><span><div id="1d1e3f3674f98030ad23f1ef15e0f821" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f98030ad23f1ef15e0f821" title="4. 混合使用与迁移"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>4. 混合使用与迁移</b></span></span></h2><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f9801b9079c183521165d7"><li><b>共存支持</b>:Next.js 13+ 允许 <code class="notion-inline-code">app</code> 和 <code class="notion-inline-code">pages</code> 目录共存,可逐步迁移旧项目。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f9809eb504dd196cdbb7fc"><li><b>优先级</b>:若同一路由在 <code class="notion-inline-code">app</code> 和 <code class="notion-inline-code">pages</code> 中均有定义,<code class="notion-inline-code">app</code> 目录的页面优先。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980aaaa6bf663592bb177"><li><b>适配性</b>:部分第三方库(如 <code class="notion-inline-code">next-auth</code>)可能需调整配置以兼容 App Router。</li></ul><hr class="notion-hr notion-block-1d1e3f3674f9800f863dc70c2465b573"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f980048798d8e586942b56" data-id="1d1e3f3674f980048798d8e586942b56"><span><div id="1d1e3f3674f980048798d8e586942b56" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f980048798d8e586942b56" title="5. 适用场景对比"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>5. 适用场景对比</b></span></span></h2><table class="notion-simple-table notion-block-1d1e3f3674f980fda85be2ecea19f544"><tbody><tr class="notion-simple-table-row notion-block-1d1e3f3674f98082901af03fc9a20d32"><td class="" style="width:120px"><div class="notion-simple-table-cell"><b>场景</b></div></td><td class="" style="width:332px"><div class="notion-simple-table-cell"><b>App Router 优势</b></div></td><td class="" style="width:367px"><div class="notion-simple-table-cell"><b>Page Router 优势</b></div></td></tr><tr class="notion-simple-table-row notion-block-1d1e3f3674f980cbbf83cc358f41c674"><td class="" style="width:120px"><div class="notion-simple-table-cell"><b>新项目</b></div></td><td class="" style="width:332px"><div class="notion-simple-table-cell">✅ 推荐使用(功能更现代,性能更优)</div></td><td class="" style="width:367px"><div class="notion-simple-table-cell">❌ 不推荐</div></td></tr><tr class="notion-simple-table-row notion-block-1d1e3f3674f980bdb432eb2d4372061f"><td class="" style="width:120px"><div class="notion-simple-table-cell"><b>旧项目维护</b></div></td><td class="" style="width:332px"><div class="notion-simple-table-cell">⚠️ 需逐步迁移</div></td><td class="" style="width:367px"><div class="notion-simple-table-cell">✅ 适合保留原有结构</div></td></tr><tr class="notion-simple-table-row notion-block-1d1e3f3674f98050ba49dfc8990c7411"><td class="" style="width:120px"><div class="notion-simple-table-cell"><b>复杂布局需求</b></div></td><td class="" style="width:332px"><div class="notion-simple-table-cell">✅ 嵌套布局和模板支持完善</div></td><td class="" style="width:367px"><div class="notion-simple-table-cell">❌ 需手动管理嵌套</div></td></tr><tr class="notion-simple-table-row notion-block-1d1e3f3674f980718c53ec2dd38e6c8c"><td class="" style="width:120px"><div class="notion-simple-table-cell"><b>服务端组件需求</b></div></td><td class="" style="width:332px"><div class="notion-simple-table-cell">✅ 默认支持服务端渲染和数据获取</div></td><td class="" style="width:367px"><div class="notion-simple-table-cell">❌ 需通过 <code class="notion-inline-code">getServerSideProps</code> 实现</div></td></tr></tbody></table><hr class="notion-hr notion-block-1d1e3f3674f9806cbde9e64bd54651ff"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f980e99157d7216909bdf9" data-id="1d1e3f3674f980e99157d7216909bdf9"><span><div id="1d1e3f3674f980e99157d7216909bdf9" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f980e99157d7216909bdf9" title="总结"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>总结</b></span></span></h2><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f9802fb351e44feb9f094a"><li><b>App Router</b> 是 Next.js 的未来方向,提供更强大的布局管理、流式渲染和服务端组件支持,适合追求高性能和现代特性的项目。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f98009be0ee509e88227a1"><li><b>Page Router</b> 适合维护旧项目或简单应用,但功能扩展性较弱。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f9805b9e77f3ebb73dc983"><li>建议新项目直接采用 App Router,旧项目可逐步迁移以利用新特性。</li></ul><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f98076aaf4cbed72e48ffa" data-id="1d1e3f3674f98076aaf4cbed72e48ffa"><span><div id="1d1e3f3674f98076aaf4cbed72e48ffa" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f98076aaf4cbed72e48ffa" title="系列文章"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">系列文章</span></span></h2><div class="notion-text notion-block-1d1e3f3674f980bab722c3fecd9a5b8a"><b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://codexun.com/posts/nextjs-series-difference-between-client-components-and-server-components">Next.js 系列之客户端组件(Client Components)和服务端组件(Server Components)的区别</a></b></div><div class="notion-text notion-block-1d1e3f3674f980fcbcb1fc8f2e1007aa"><b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://codexun.com/posts/nextjs-series-introduction-about-serverless-architecture">Next.js 系列之Serverless(无服务器架构)介绍</a></b></div><div class="notion-text notion-block-1d1e3f3674f980ee9841c07cc3f31058"><b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://codexun.com/posts/nextjs-series-difference-between-app-router-and-page-router">Next.js 系列之 app router 和 page router 的区别</a></b></div><div class="notion-text notion-block-1d1e3f3674f98051a781e5ef0944be46"><b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://codexun.com/posts/nextjs-series-difference-between-ssg-ssr-isr-and-csr-in-nextjs">Next.js 系列之的SSG、SSR、ISR、CSR 的详细介绍和区别</a></b></div><div class="notion-blank notion-block-1d1e3f3674f9803ba0e4e8a2331497ac"> </div></main> ]]>
</content>
</entry>
<entry>
<title type="html">
<![CDATA[ Next.js 系列之Serverless(无服务器架构)介绍 ]]>
</title>
<id>https://codexun.com/posts/nextjs-series-introduction-about-serverless-architecture</id>
<link href="https://codexun.com/posts/nextjs-series-introduction-about-serverless-architecture"/>
<updated>2025-04-02T16:00:00.000Z</updated>
<summary type="html">
<![CDATA[ Serverless(无服务器架构)是一种云计算模型,其核心思想是开发者无需关注底层服务器的运维、扩容和资源分配,只需专注于编写业务代码。云服务商(如 AWS、腾讯云、阿里云)会动态管理计算资源的分配,按需执行代码并自动伸缩。在前端开发中,Serverless 主要用于解决后端服务部署、API 管理和静态资源托管等问题,尤其适合结合 SSR(服务端渲染)技术使用。 ]]>
</summary>
<content type="html">
<![CDATA[ <main class="notion light-mode notion-page notion-block-1d1e3f3674f98009a56febead06f853a"><div class="notion-viewport"></div><div class="notion-collection-page-properties"></div><div class="notion-text notion-block-1d1e3f3674f980f4a21eec8d3e3a0694">Serverless(无服务器架构)是一种云计算模型,其核心思想是开发者无需关注底层服务器的运维、扩容和资源分配,只需专注于编写业务代码。云服务商(如 AWS、腾讯云、阿里云)会动态管理计算资源的分配,按需执行代码并自动伸缩。在前端开发中,Serverless 主要用于解决后端服务部署、API 管理和静态资源托管等问题,尤其适合结合 SSR(服务端渲染)技术使用。以下是具体解析:</div><hr class="notion-hr notion-block-1d1e3f3674f980e6825dcc2397e4c72d"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f980bb9227ef9e61d3d36c" data-id="1d1e3f3674f980bb9227ef9e61d3d36c"><span><div id="1d1e3f3674f980bb9227ef9e61d3d36c" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f980bb9227ef9e61d3d36c" title="1. Serverless 的核心特点"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1. Serverless 的核心特点</b></span></span></h2><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f98035bb02f5596439d2f9"><li><b>无服务器管理</b>:开发者无需自行配置服务器或维护基础设施,云平台自动处理资源调度。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f9806eba6fe03484fe0cae"><li><b>事件驱动</b>:代码通过 HTTP 请求、数据库变更等事件触发执行(如用户访问页面触发 SSR 渲染)。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980da9f0cd5cac6380aee"><li><b>按需付费</b>:根据实际代码执行时间和资源消耗计费,空闲时不产生费用。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f9808baa14e63a99a886ed"><li><b>自动伸缩</b>:流量激增时自动扩容,避免因服务器性能不足导致服务中断。</li></ul><hr class="notion-hr notion-block-1d1e3f3674f980b8b5cbc758585b6125"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f980419ca9cea4ddf8381d" data-id="1d1e3f3674f980419ca9cea4ddf8381d"><span><div id="1d1e3f3674f980419ca9cea4ddf8381d" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f980419ca9cea4ddf8381d" title="2. 前端开发中 Serverless 的典型应用场景"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>2. 前端开发中 Serverless 的典型应用场景</b></span></span></h2><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1d1e3f3674f9807b9b04e595ade1c5cd" data-id="1d1e3f3674f9807b9b04e595ade1c5cd"><span><div id="1d1e3f3674f9807b9b04e595ade1c5cd" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f9807b9b04e595ade1c5cd" title="(1)服务端渲染(SSR)"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>(1)服务端渲染(SSR)</b></span></span></h3><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980368b3bc85a1fbb5a82"><li><b>优化首屏加载与 SEO</b>:通过 Serverless 函数(如 AWS Lambda、腾讯云 SCF)动态生成 HTML,提升页面加载速度和搜索引擎友好性。</li><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980368b3bc85a1fbb5a82"><div class="notion-text notion-block-1d1e3f3674f9806f9ab8cd89034e119d"><em>示例</em>:Next.js 框架的 SSR 页面可部署为云函数,每个页面路由对应一个独立的函数。</div></ul></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980e2aa6bd952d1d2a236"><li><b>与静态资源分离</b>:将渲染逻辑放在云函数中,静态资源(如图片、CSS)托管至对象存储(如 COS、S3),通过 CDN 加速。</li></ul><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1d1e3f3674f980e1b40ace26ac799b9f" data-id="1d1e3f3674f980e1b40ace26ac799b9f"><span><div id="1d1e3f3674f980e1b40ace26ac799b9f" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f980e1b40ace26ac799b9f" title="(2)API 服务"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>(2)API 服务</b></span></span></h3><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f9803f825ac41602f15761"><li><b>轻量级后端</b>:前端开发者可用 Node.js 编写 API(如 Express、Koa),直接部署为 Serverless 函数,替代传统后端服务器。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f9801caa35f56d5b33817f"><li><b>快速集成云服务</b>:通过 Serverless 组件直接调用数据库、消息队列等云服务,无需自行搭建中间件。</li></ul><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1d1e3f3674f980c5a3c5dc5d34665879" data-id="1d1e3f3674f980c5a3c5dc5d34665879"><span><div id="1d1e3f3674f980c5a3c5dc5d34665879" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f980c5a3c5dc5d34665879" title="(3)静态网站托管"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>(3)静态网站托管</b></span></span></h3><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980b1a4c1cb2f4f37afd5"><li><b>自动化部署</b>:Vercel 等平台支持将 Next.js、Nuxt.js 等前端框架的构建产物自动托管到全球 CDN,并绑定自定义域名。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f98032ad86e19558bec3d2"><li><b>CI/CD 集成</b>:关联代码仓库后,每次 Git Push 自动触发构建和部署流程。</li></ul><hr class="notion-hr notion-block-1d1e3f3674f9800888b8f4776cecc8f5"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f980b1a6f2d48d0e20515f" data-id="1d1e3f3674f980b1a6f2d48d0e20515f"><span><div id="1d1e3f3674f980b1a6f2d48d0e20515f" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f980b1a6f2d48d0e20515f" title="3. Serverless 对前端的核心价值"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>3. Serverless 对前端的核心价值</b></span></span></h2><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f9804b86aee4a95df19c15"><li><b>降低运维成本</b>:无需学习 Linux 或 Nginx 配置,专注业务代码。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980fabf04fe021e545d8a"><li><b>快速迭代</b>:通过 Serverless Framework 或 Vercel CLI 实现一键部署,缩短开发周期。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980cb9416c10d6b0587a1"><li><b>成本可控</b>:小型项目可享受免费额度(如腾讯云每月 40 万 GBs 函数资源)。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980f6ba3eef7e1e3ec8c3"><li><b>生态兼容性</b>:支持主流框架(Next.js、Nuxt.js)、语言(Node.js、Python)和云平台(AWS、阿里云、腾讯云)。</li></ul><hr class="notion-hr notion-block-1d1e3f3674f98091bc61d45b68081a5e"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f9806ba83fce5957dcfee1" data-id="1d1e3f3674f9806ba83fce5957dcfee1"><span><div id="1d1e3f3674f9806ba83fce5957dcfee1" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f9806ba83fce5957dcfee1" title="4. 实践注意事项"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>4. 实践注意事项</b></span></span></h2><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980ad9645c5e4fb4fad58"><li><b>冷启动问题</b>:函数首次调用时需初始化环境,可能导致延迟(可通过预置并发缓解)。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980ec9d83f7c751148099"><li><b>代码体积限制</b>:云函数代码包通常需压缩至 50MB 以内,需剔除开发依赖(如 <code class="notion-inline-code">npm install --omit=dev</code>)。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980dfae94eb5646d0bb60"><li><b>环境适配</b>:部分云平台默认 Node.js 版本较低,需自行升级或通过 Layer 功能绑定运行时。</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f98003b34ece5bfb384024"><li><b>本地调试</b>:使用 Serverless Framework 或 IDE 插件模拟云环境进行测试。</li></ul><hr class="notion-hr notion-block-1d1e3f3674f98078be5bd10d6c9a0c06"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f980c2bfb1f8542e47126e" data-id="1d1e3f3674f980c2bfb1f8542e47126e"><span><div id="1d1e3f3674f980c2bfb1f8542e47126e" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f980c2bfb1f8542e47126e" title="5. 主流部署方案示例"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>5. 主流部署方案示例</b></span></span></h2><div class="notion-text notion-block-1d1e3f3674f98003b5d1ef7c9ef6c6ff">以 Next.js 应用为例:</div><ol start="1" class="notion-list notion-list-numbered notion-block-1d1e3f3674f980069fe3d37cbe8fc5de"><li><b>Vercel 托管</b>:零配置部署,自动识别路由和 API,适合个人项目。</li></ol><ol start="2" class="notion-list notion-list-numbered notion-block-1d1e3f3674f98019a9fff844c98f6ec0"><li><b>腾讯云 Web 函数</b>:通过 <code class="notion-inline-code">serverless.yml</code> 配置入口文件和资源,支持自定义域名和 CDN。</li></ol><ol start="3" class="notion-list notion-list-numbered notion-block-1d1e3f3674f980f2b6f5fb1b3563d585"><li><b>AWS Lambda</b>:利用 <code class="notion-inline-code">@vercel/next</code> 构建器将页面拆分为独立函数,优化性能和资源利用率。</li></ol><hr class="notion-hr notion-block-1d1e3f3674f980ecad42c3dabe9bfc14"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f9808390e5ce7d1df6ce30" data-id="1d1e3f3674f9808390e5ce7d1df6ce30"><span><div id="1d1e3f3674f9808390e5ce7d1df6ce30" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f9808390e5ce7d1df6ce30" title="总结"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>总结</b></span></span></h2><div class="notion-text notion-block-1d1e3f3674f980a3ad1edb2c53caf99b">Serverless 为前端开发提供了“无运维化”的可能性,尤其适合需要快速迭代、低成本运维的 SSR 应用和轻量级 API 服务。尽管存在冷启动等挑战,但随着云平台优化和工具链完善(如 Cloud Studio 的一键部署),它已成为现代前端工程化的重要方向。</div><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f9802eaa83d68b8244e53b" data-id="1d1e3f3674f9802eaa83d68b8244e53b"><span><div id="1d1e3f3674f9802eaa83d68b8244e53b" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f9802eaa83d68b8244e53b" title="系列文章"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">系列文章</span></span></h2><div class="notion-text notion-block-1d1e3f3674f98014915de100670707fe"><b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://codexun.com/posts/nextjs-series-difference-between-client-components-and-server-components">Next.js 系列之客户端组件(Client Components)和服务端组件(Server Components)的区别</a></b></div><div class="notion-text notion-block-1d1e3f3674f980768743f9cb7e447880"><b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://codexun.com/posts/nextjs-series-introduction-about-serverless-architecture">Next.js 系列之Serverless(无服务器架构)介绍</a></b></div><div class="notion-text notion-block-1d1e3f3674f9802ebe15c4b11805cf88"><b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://codexun.com/posts/nextjs-series-difference-between-app-router-and-page-router">Next.js 系列之 app router 和 page router 的区别</a></b></div><div class="notion-text notion-block-1d1e3f3674f980d4ae46d179008db304"><b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://codexun.com/posts/nextjs-series-difference-between-ssg-ssr-isr-and-csr-in-nextjs">Next.js 系列之的SSG、SSR、ISR、CSR 的详细介绍和区别</a></b></div></main> ]]>
</content>
</entry>
<entry>
<title type="html">
<![CDATA[ Next.js 系列之客户端组件(Client Components)和服务端组件(Server Components)的区别 ]]>
</title>
<id>https://codexun.com/posts/nextjs-series-difference-between-client-components-and-server-components</id>
<link href="https://codexun.com/posts/nextjs-series-difference-between-client-components-and-server-components"/>
<updated>2025-03-31T16:00:00.000Z</updated>
<summary type="html">
<![CDATA[ Next.js 中客户端组件(Client Components)和服务端组件(Server Components)的核心区别在于运行环境、功能特性及适用场景,以下是详细对比。服务端组件和客户端组件在 Next.js 中形成互补,服务端组件 侧重于性能优化、数据安全与静态内容渲染。客户端组件 专注于交互性和动态功能。合理混合使用两者(如服务端获取数据后传递给客户端处理交互),可构建高效且用户友好的应用。 ]]>
</summary>
<content type="html">
<![CDATA[ <main class="notion light-mode notion-page notion-block-1d1e3f3674f980e3a8c4c4174443e329"><div class="notion-viewport"></div><div class="notion-collection-page-properties"></div><div class="notion-text notion-block-1d1e3f3674f98019a1d3e018e97a8f62">Next.js 中客户端组件(Client Components)和服务端组件(Server Components)的核心区别在于运行环境、功能特性及适用场景,以下是详细对比:</div><hr class="notion-hr notion-block-1d1e3f3674f9806a829bd672275b0adf"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f980b3bc06ea1720d761c6" data-id="1d1e3f3674f980b3bc06ea1720d761c6"><span><div id="1d1e3f3674f980b3bc06ea1720d761c6" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f980b3bc06ea1720d761c6" title="1. 运行环境与渲染方式"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>1. 运行环境与渲染方式</b></span></span></h2><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980169472e6a0e077501c"><li><b>服务端组件</b></li></ul><div class="notion-text notion-block-1d1e3f3674f980c791b7e4efe98210c7">• <b>环境</b>:仅在服务器端运行,生成静态 HTML 发送到客户端。</div><div class="notion-text notion-block-1d1e3f3674f98050b4bfcae547435574">• <b>渲染</b>:支持静态渲染(默认)、动态渲染(需调用 <code class="notion-inline-code">fetch</code> 等 API)和流式渲染(分块加载内容)。</div><div class="notion-text notion-block-1d1e3f3674f980b6b629d74336e9035f">• <b>示例代码</b>:直接获取数据并返回 HTML,无需客户端交互逻辑。</div><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980bd8a68f3491ee30f3b"><li><b>客户端组件</b></li></ul><div class="notion-text notion-block-1d1e3f3674f980da8247dcb0e68635ab">• <b>环境</b>:在浏览器中运行,支持交互逻辑和浏览器 API(如 <code class="notion-inline-code">window</code>、<code class="notion-inline-code">localStorage</code>)。</div><div class="notion-text notion-block-1d1e3f3674f98066bb98e3ae51f077db">• <b>渲染</b>:首次加载时由服务端生成 HTML 预览,随后通过客户端 JavaScript 进行 Hydration(水合)以实现交互性。</div><div class="notion-text notion-block-1d1e3f3674f9803a967ccdf762f81ee8">• <b>示例代码</b>:使用 <code class="notion-inline-code">useState</code> 管理状态并响应用户操作。</div><hr class="notion-hr notion-block-1d1e3f3674f9801c9953edf734e78987"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f98031b5e1e7aeef133d27" data-id="1d1e3f3674f98031b5e1e7aeef133d27"><span><div id="1d1e3f3674f98031b5e1e7aeef133d27" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f98031b5e1e7aeef133d27" title="2. 功能特性"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>2. 功能特性</b></span></span></h2><table class="notion-simple-table notion-block-1d1e3f3674f98062af1ef66e38e13222"><tbody><tr class="notion-simple-table-row notion-block-1d1e3f3674f980f2adcaff09424b0d47"><td class="" style="width:121px"><div class="notion-simple-table-cell"><b>特性</b></div></td><td class="" style="width:342px"><div class="notion-simple-table-cell"><b>服务端组件</b></div></td><td class="" style="width:408px"><div class="notion-simple-table-cell"><b>客户端组件</b></div></td></tr><tr class="notion-simple-table-row notion-block-1d1e3f3674f9808e8a37c4e267b5266c"><td class="" style="width:121px"><div class="notion-simple-table-cell"><b>数据获取</b></div></td><td class="" style="width:342px"><div class="notion-simple-table-cell">可直接访问数据库、API 或敏感数据。</div></td><td class="" style="width:408px"><div class="notion-simple-table-cell">需通过客户端请求(如 <code class="notion-inline-code">fetch</code>),数据可能暴露。</div></td></tr><tr class="notion-simple-table-row notion-block-1d1e3f3674f9801d81fcdbf32402bb9a"><td class="" style="width:121px"><div class="notion-simple-table-cell"><b>React Hooks</b></div></td><td class="" style="width:342px"><div class="notion-simple-table-cell">不支持 <code class="notion-inline-code">useState</code>、<code class="notion-inline-code">useEffect</code> 等。</div></td><td class="" style="width:408px"><div class="notion-simple-table-cell">支持所有 React Hooks。</div></td></tr><tr class="notion-simple-table-row notion-block-1d1e3f3674f980548ac1d0772a0ec0b7"><td class="" style="width:121px"><div class="notion-simple-table-cell"><b>浏览器 API</b></div></td><td class="" style="width:342px"><div class="notion-simple-table-cell">无法访问。</div></td><td class="" style="width:408px"><div class="notion-simple-table-cell">可访问 <code class="notion-inline-code">window</code>、<code class="notion-inline-code">document</code> 等。</div></td></tr><tr class="notion-simple-table-row notion-block-1d1e3f3674f980c1b75df0b9a47eb8f9"><td class="" style="width:121px"><div class="notion-simple-table-cell"><b>性能优化</b></div></td><td class="" style="width:342px"><div class="notion-simple-table-cell">减少客户端 JS 体积,提升 SEO 和首屏加载速度。</div></td><td class="" style="width:408px"><div class="notion-simple-table-cell">增加客户端 JS 体积,但支持动态交互。</div></td></tr><tr class="notion-simple-table-row notion-block-1d1e3f3674f980eba125ca151e2189dd"><td class="" style="width:121px"><div class="notion-simple-table-cell"><b>嵌套规则</b></div></td><td class="" style="width:342px"><div class="notion-simple-table-cell">可包含客户端组件。</div></td><td class="" style="width:408px"><div class="notion-simple-table-cell">不可嵌套服务端组件(仅能通过 Props 传递数据)。</div></td></tr></tbody></table><hr class="notion-hr notion-block-1d1e3f3674f98048bb95e707adadc8c0"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f980668b27ec7a927ae6de" data-id="1d1e3f3674f980668b27ec7a927ae6de"><span><div id="1d1e3f3674f980668b27ec7a927ae6de" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f980668b27ec7a927ae6de" title="3. 适用场景"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>3. 适用场景</b></span></span></h2><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f980959f8fd2147b5d6b91"><li><b>服务端组件优先使用的情况</b>:</li></ul><div class="notion-text notion-block-1d1e3f3674f980ee958cc7860bbc6351">• 静态内容展示(如博客文章、产品列表)。</div><div class="notion-text notion-block-1d1e3f3674f9800fbbc9f5fb5da4156f">• 需要直接访问数据库或敏感数据的场景。</div><div class="notion-text notion-block-1d1e3f3674f980d8a08bca9bc71919b5">• SEO 优化需求高的页面。</div><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f98077bdedd4c8cf556bfe"><li><b>客户端组件优先使用的情况</b>:</li></ul><div class="notion-text notion-block-1d1e3f3674f980c094e5c4cae31de2b1">• 用户交互(如表单提交、按钮点击)。</div><div class="notion-text notion-block-1d1e3f3674f98087b40fed423a54cb6d">• 动态状态管理(如购物车、计数器)。</div><div class="notion-text notion-block-1d1e3f3674f980509aa5dfb6984c2093">• 依赖浏览器 API 的功能(如动画、地理位置)。</div><hr class="notion-hr notion-block-1d1e3f3674f98078a22ef553274fdaae"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f980c8af12c4aeb20df760" data-id="1d1e3f3674f980c8af12c4aeb20df760"><span><div id="1d1e3f3674f980c8af12c4aeb20df760" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f980c8af12c4aeb20df760" title="4. 混合使用与数据传递"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>4. 混合使用与数据传递</b></span></span></h2><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f98028b07cde8bd143c8e6"><li><b>组合方式</b>:服务端组件可通过 Props 将数据传递给客户端组件。例如:</li></ul><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f9802a891cc6cc885d414a"><li><b>限制</b>:客户端组件无法直接导入服务端组件,需通过 Props 或占位符传递。</li></ul><hr class="notion-hr notion-block-1d1e3f3674f980bdade4f1ca516bb4ed"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f98056b6c3e1284addd748" data-id="1d1e3f3674f98056b6c3e1284addd748"><span><div id="1d1e3f3674f98056b6c3e1284addd748" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f98056b6c3e1284addd748" title="5. 性能与安全"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>5. 性能与安全</b></span></span></h2><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f9809c939ffe7613c61ed2"><li><b>服务端优势</b>:</li></ul><div class="notion-text notion-block-1d1e3f3674f9803cb807c74010f92da7">• 缓存渲染结果,减少重复请求。</div><div class="notion-text notion-block-1d1e3f3674f9806db4fac40f00922452">• 敏感逻辑(如数据库查询)保留在服务端,避免泄露。</div><ul class="notion-list notion-list-disc notion-block-1d1e3f3674f9801ba2a3c7547aaab720"><li><b>客户端劣势</b>:</li></ul><div class="notion-text notion-block-1d1e3f3674f980078c38c57687f7dd1f">• 增加客户端 JS 体积,可能影响加载速度。</div><div class="notion-text notion-block-1d1e3f3674f9802bb006cccb8f622dc3">• 需谨慎处理用户输入和敏感数据。</div><hr class="notion-hr notion-block-1d1e3f3674f9803cbab6ef4e2b05c7c8"/><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f980af8942eba81c6c9058" data-id="1d1e3f3674f980af8942eba81c6c9058"><span><div id="1d1e3f3674f980af8942eba81c6c9058" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f980af8942eba81c6c9058" title="总结"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>总结</b></span></span></h2><div class="notion-text notion-block-1d1e3f3674f9806ba3dceb4f6a17008f">服务端组件和客户端组件在 Next.js 中形成互补:</div><div class="notion-text notion-block-1d1e3f3674f980a4b750c06031bef193">• <b>服务端组件</b> 侧重于性能优化、数据安全与静态内容渲染。</div><div class="notion-text notion-block-1d1e3f3674f980c494a3c58d517c8e71">• <b>客户端组件</b> 专注于交互性和动态功能。</div><div class="notion-text notion-block-1d1e3f3674f9802d8847e0f92ec1bee9">合理混合使用两者(如服务端获取数据后传递给客户端处理交互),可构建高效且用户友好的应用。</div><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1d1e3f3674f980b98a47f3141bc849f7" data-id="1d1e3f3674f980b98a47f3141bc849f7"><span><div id="1d1e3f3674f980b98a47f3141bc849f7" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1d1e3f3674f980b98a47f3141bc849f7" title="系列文章"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">系列文章</span></span></h2><div class="notion-text notion-block-1d1e3f3674f980faa521ca352fd20a17"><b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://codexun.com/posts/nextjs-series-difference-between-client-components-and-server-components">Next.js 系列之客户端组件(Client Components)和服务端组件(Server Components)的区别</a></b></div><div class="notion-text notion-block-1d1e3f3674f980c691c1d775159d3e77"><b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://codexun.com/posts/nextjs-series-introduction-about-serverless-architecture">Next.js 系列之Serverless(无服务器架构)介绍</a></b></div><div class="notion-text notion-block-1d1e3f3674f9800eb855d48b16244525"><b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://codexun.com/posts/nextjs-series-difference-between-app-router-and-page-router">Next.js 系列之 app router 和 page router 的区别</a></b></div><div class="notion-text notion-block-1d1e3f3674f9803e9dc7e88bf6e8d2a7"><b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://codexun.com/posts/nextjs-series-difference-between-ssg-ssr-isr-and-csr-in-nextjs">Next.js 系列之的SSG、SSR、ISR、CSR 的详细介绍和区别</a></b></div><div class="notion-blank notion-block-1d1e3f3674f980488aa8ecd075ede267"> </div></main> ]]>
</content>
</entry>
<entry>
<title type="html">
<![CDATA[ 个税年度汇算时,申报的劳务报酬总收入小于本年度代开的劳务发票总金额,该如何处理? ]]>
</title>
<id>https://codexun.com/posts/resolve-individual-income-tax-declaration-review</id>
<link href="https://codexun.com/posts/resolve-individual-income-tax-declaration-review"/>
<updated>2025-03-24T16:00:00.000Z</updated>
<summary type="html">
<![CDATA[ 由于您申报的收入存在待核实的事项,且纳税人年度汇算时申报的劳务报酬总收入小于本年度代开的劳务发票(不含汇总代开发票)总金额,故不予同意本次退税申请。税务审核不通过解决办法,新增一笔劳务报酬,重新申报即可。 ]]>
</summary>
<content type="html">
<![CDATA[ <main class="notion light-mode notion-page notion-block-1c1e3f3674f98000a703dee4648977e4"><div class="notion-viewport"></div><div class="notion-collection-page-properties"></div><div class="notion-text notion-block-1c1e3f3674f980ada1abde872a44db7c">2024年度个税汇算退税,从 3月21 号开始不需要预约了,然后抓紧时间对 2024 年的个税进行汇算申报,说不定还能退点税呢。</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1c1e3f3674f98026a004dac72912d436"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:100%"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3A381186c8-279d-4647-b2bd-59180a2b41ad%3Aimage.png?table=block&amp;id=1c1e3f36-74f9-8026-a004-dac72912d436&amp;cache=v2" alt="notion image" loading="lazy" decoding="async"/></div></figure><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1c1e3f3674f980448774c12fbd869599" data-id="1c1e3f3674f980448774c12fbd869599"><span><div id="1c1e3f3674f980448774c12fbd869599" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1c1e3f3674f980448774c12fbd869599" title="1、全年一次性奖金计税方式的选择"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">1、全年一次性奖金计税方式的选择</span></span></h2><div class="notion-text notion-block-1c1e3f3674f9808fa8bdee42449d110c">趁着周末的时间,打开了个税 APP进行了一番操作,其中 24 年因为有一项是奖金,可以尝试选择 <b>计税方式 </b>,两种计税方式对比一下,在最后一步查看退税或者需要补税的金额大小,选择最优解。</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1c1e3f3674f98006a353ed676796193a"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:336px;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3A0b3f0e7c-8402-4699-9b73-95b13d581b63%3A531f5532-b99c-45e5-aeb2-706c16141ac3.png?table=block&amp;id=1c1e3f36-74f9-8006-a353-ed676796193a&amp;cache=v2" alt="notion image" loading="lazy" decoding="async"/></div></figure><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1c1e3f3674f980929a88d4a7bc46697d" data-id="1c1e3f3674f980929a88d4a7bc46697d"><span><div id="1c1e3f3674f980929a88d4a7bc46697d" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1c1e3f3674f980929a88d4a7bc46697d" title="2、税务审核不通过"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">2、税务审核不通过</span></span></h2><div class="notion-text notion-block-1c1e3f3674f980d899abdb06ba677569">昨天收到短信通知,告知审核不通过。查看个税 APP 审核状态,有如下信息:“<b>由于您申报的收入存在待核实的事项,且纳税人年度汇算时申报的劳务报酬总收入小于本年度代开的劳务发票(不含汇总代开发票)总金额,故不予同意本次退税申请。</b>”</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1c1e3f3674f980f390baccca59478363"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:336px;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3A70c431f6-5957-4fc5-95f2-6236144833b4%3Aimage.png?table=block&amp;id=1c1e3f36-74f9-80f3-90ba-ccca59478363&amp;cache=v2" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-1c1e3f3674f9807db90dd21a910666b6">搜索有效信息,审核不通过的这个原因的意思是:2024年度代开了劳务发票,但是扣缴义务人未代扣代缴或少代扣代缴了劳务报酬所得的个人所得税,所以需要您更正年度申报,自行添加未申报或少申报的劳务报酬收入。</div><div class="notion-text notion-block-1c1e3f3674f980389c78e0281d9b77a3">仔细查看劳务报酬所得,大概率是 <span class="notion-red"><b>京粉返利</b></span> 导致的数据有出入了。</div><div class="notion-text notion-block-1c1e3f3674f9805f91c7d573c3a90483">有其他人遇到了同样的情况,具体就是 “<b>相关情况为23年个税记录申报后,发票延期至24年开具导致。因为开票与申报时间不匹配的原因导致出现此提醒,实际对应金额的收入平台前期均已正常申报。当前可反馈兆盈侧协助提供说明文件,待出具后您可将说明文件上传至个税APP推送补正材料入口(无入口可联系主管税局沟通推送补正材料入口)。如您需兆盈侧协助提供相应说明材料信息, 可填写下方问卷信息以便协助处理</b>。”</div><div class="notion-text notion-block-1c1e3f3674f980a789ffd4bf421e99fc">京东返利 23 年的发票延期到 24 年开具导致的。</div><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1c1e3f3674f980efb893d9bd6943a78f" data-id="1c1e3f3674f980efb893d9bd6943a78f"><span><div id="1c1e3f3674f980efb893d9bd6943a78f" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1c1e3f3674f980efb893d9bd6943a78f" title="3、税务审核不通过解决办法"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">3、税务审核不通过解决办法</span></span></h2><div class="notion-text notion-block-1c1e3f3674f980c0adfaf00ef956ed6a">如果 <span class="notion-red"><b>申报的劳务报酬总收入</b></span><b> </b>和<b> </b><span class="notion-red"><b>本年度代开的劳务发票总金额 </b></span><span class="notion-default">差别不大的话,可以如下解决。</span></div><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1c1e3f3674f980708a25d1dc7f1b23e8" data-id="1c1e3f3674f980708a25d1dc7f1b23e8"><span><div id="1c1e3f3674f980708a25d1dc7f1b23e8" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1c1e3f3674f980708a25d1dc7f1b23e8" title="3.1、查看本年度代开的劳务发票总金额"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">3.<span class="notion-default">1、查看</span><span class="notion-default"><b>本年度代开的劳务发票总金额</b></span></span></span></h3><div class="notion-text notion-block-1c1e3f3674f9804a8a44e29305adf57b">登录个人所得税APP,点击【办&amp;查】,下滑到【发票管理】模块,选择【我的票夹】。</div><div class="notion-text notion-block-1c1e3f3674f980b9a34af423ddce9362">点击【我销售的】—【筛选】,开票日期选择【自定义】,填写汇算年度(一定要自定义选择时间,<span class="notion-red">2024-01-01—2024-12-31</span>),发票类型分别选择【数电票】和【税控发票】,其他默认【全部】,点击【确定】后进行查询,统计代开发票总金额。</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1c1e3f3674f980c3a740dc28e9c4aa7d"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:100%"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3Acc819f1a-2cd5-4f6f-84fa-d30d5e39b988%3Aimage.png?table=block&amp;id=1c1e3f36-74f9-80c3-a740-dc28e9c4aa7d&amp;cache=v2" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-1c1e3f3674f980d28642ea95c63d1b18">统计本年度代开发票总金额可以有个技巧,在我的票夹下选择批量管理,把所有的全选,左下角显示即是 <span class="notion-red">24 年度代开发票总金额。</span></div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1c1e3f3674f980fe86dcd862ccadf02a"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:432px;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3A99097dfa-318d-4639-b551-c8366b5c031b%3Aimage.png?table=block&amp;id=1c1e3f36-74f9-80fe-86dc-d862ccadf02a&amp;cache=v2" alt="notion image" loading="lazy" decoding="async"/></div></figure><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1c1e3f3674f980dc94d1ec44d9d790bd" data-id="1c1e3f3674f980dc94d1ec44d9d790bd"><span><div id="1c1e3f3674f980dc94d1ec44d9d790bd" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1c1e3f3674f980dc94d1ec44d9d790bd" title="3.2、查看申报的劳务报酬总收入"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">3.2、查看<span class="notion-default"><b>申报的劳务报酬总收入</b></span></span></span></h3><div class="notion-text notion-block-1c1e3f3674f980419163de07a26d7412"><span class="notion-default"><b>申报的劳务报酬总收入 </b></span><span class="notion-default">这个比较容易看到,在进行申报的时候点进劳务报酬选项内,有金额合计即是 </span><span class="notion-red">24 年申报的劳务报酬总收入</span><span class="notion-default"><b>。</b></span></div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1c1e3f3674f980cd816ff4c14278b800"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:288px;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3A70f00f5f-b6e8-4758-aa65-2d5eea37a4d1%3Aimage.png?table=block&amp;id=1c1e3f36-74f9-80cd-816f-f4c14278b800&amp;cache=v2" alt="notion image" loading="lazy" decoding="async"/></div></figure><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1c1e3f3674f980c29f57c98484e55f60" data-id="1c1e3f3674f980c29f57c98484e55f60"><span><div id="1c1e3f3674f980c29f57c98484e55f60" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1c1e3f3674f980c29f57c98484e55f60" title="3.3、新增一笔劳务报酬,重新申报"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">3.3、新增一笔劳务报酬,重新申报</span></span></h3><div class="notion-text notion-block-1c1e3f3674f9806caf33d8c9e594b202">第一次申报审核没有通过的原因,就是<b>申报的劳务报酬总收入【78.06元】小于本年度代开的劳务发票总金额【122. 83 元】</b>,也就是这两个金额对不上。</div><div class="notion-text notion-block-1c1e3f3674f98028b5d2d8f6d743ee1b">要解决这个问题,可以在劳务报酬这个页面中,右上角点击<b>新增</b>,点击新增一项劳务报酬所得,新增的金额为 44.77 元【122.83-78.06】,<span class="notion-red"><b>这个根据自己实际情况填写</b></span>。</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1c1e3f3674f980f1b91aec594bf74c16"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:528px;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3A004e0bb1-24f8-445d-ab78-0f0441dc24ba%3Aimage.png?table=block&amp;id=1c1e3f36-74f9-80f1-b91a-ec594bf74c16&amp;cache=v2" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-1c1e3f3674f980e18be5d4a2cce041a3">新增页面的备注可以参考如下填写:</div><div class="notion-callout notion-gray_background_co notion-block-1c1e3f3674f980ec92f6eaed84342fce"><div class="notion-page-icon-inline notion-page-icon-span"><span class="notion-page-icon" role="img" aria-label="💡">💡</span></div><div class="notion-callout-text"><div class="notion-text notion-block-1c1e3f3674f980038a5afbf817f21971">购物返利未申报部分差额 支付人:宿迁兆盈商服科技有限公司 支付地址:江苏省,宿迁市 价税合计122.83元 已申报金额78.06元 差额44.77元 识别号:91321311MA1X716Q06</div></div></div><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1c1e3f3674f980b892ccda4823e47776" data-id="1c1e3f3674f980b892ccda4823e47776"><span><div id="1c1e3f3674f980b892ccda4823e47776" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1c1e3f3674f980b892ccda4823e47776" title="3.4、第二天成功审核通过"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">3.4、第二天成功审核通过</span></span></h3><div class="notion-text notion-block-1c1e3f3674f980b1ac8ed46874a6ad9d">将以上的重新申报提交之后,第二天查看申报记录,已经成功审核通过啦,下一步就是美美的等着退税到账即可。</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1c1e3f3674f980a1bd94d3e5c91da05d"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:384px;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3Aabbab52f-e377-416e-b107-f76ce57911f9%3Aimage.png?table=block&amp;id=1c1e3f36-74f9-80a1-bd94-d3e5c91da05d&amp;cache=v2" alt="notion image" loading="lazy" decoding="async"/></div></figure></main> ]]>
</content>
</entry>
<entry>
<title type="html">
<![CDATA[ 为博客集成utterances 评论组件 ]]>
</title>
<id>https://codexun.com/posts/integrate-utterances-comment-component-in-blog</id>
<link href="https://codexun.com/posts/integrate-utterances-comment-component-in-blog"/>
<updated>2025-03-20T16:00:00.000Z</updated>
<summary type="html">
<![CDATA[ utterances 是一个轻量级的评论插件 Utterances,基于 GitHub Issues 构建,无广告、无跟踪、开源且永久免费。它通过 GitHub OAuth 流程授权用户发表评论,所有数据存储在 GitHub 中,支持多种页面与 Issue 的映射方式,并提供多种主题自定义选项。  ]]>
</summary>
<content type="html">
<![CDATA[ <main class="notion light-mode notion-page notion-block-1c0e3f3674f980c9b65ddd51e5a8bd46"><div class="notion-viewport"></div><div class="notion-collection-page-properties"></div><div class="notion-text notion-block-1c1e3f3674f9809dbb6cc437bdd59d9b"> utterances 是一个轻量级的评论插件 Utterances,基于 GitHub Issues 构建,无广告、无跟踪、开源且永久免费。它通过 GitHub OAuth 流程授权用户发表评论,所有数据存储在 GitHub 中,支持多种页面与 Issue 的映射方式,并提供多种主题自定义选项。 </div><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1c1e3f3674f980b69326f87bdd4f228d" data-id="1c1e3f3674f980b69326f87bdd4f228d"><span><div id="1c1e3f3674f980b69326f87bdd4f228d" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1c1e3f3674f980b69326f87bdd4f228d" title="1、utterances工作原理"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">1、utterances工作原理</span></span></h2><div class="notion-text notion-block-1c1e3f3674f9804ab16fea36cfe96c5c">utterances 是基于 GitHub issues 构建的轻量级评论小部件,所有的评论信息也即是存储在 Github issues 中的,使用 GitHub issues管理博客的评论等。</div><div class="notion-text notion-block-1c1e3f3674f980c7b306ed107d3e241b">当博客页面中 utterances 的组件加载时,GitHub issues搜索API将根据<code class="notion-inline-code">url</code>,<code class="notion-inline-code">pathname</code>或<code class="notion-inline-code">title</code>找到与页面关联的 issues。如果我们找不到与该页面匹配的issue,那么utterances 机器人会在第一次发表评论时自动创建 issue。</div><div class="notion-text notion-block-1c1e3f3674f980aa9074edf55cfa0fd7">用户要发表评论,必须使用Github Oauth授权登录,用户在博客下面发布评论,实质上是在对应的GitHub issue上发表评论。</div><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1c1e3f3674f9805c9e67d2393b7f6ca7" data-id="1c1e3f3674f9805c9e67d2393b7f6ca7"><span><div id="1c1e3f3674f9805c9e67d2393b7f6ca7" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1c1e3f3674f9805c9e67d2393b7f6ca7" title="2、utterances 优点"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">2、utterances 优点</span></span></h2><div class="notion-text notion-block-1c1e3f3674f9805bbfe8dd36d2fba373">最主要的优点还是轻量接入,utterances插件通过 GitHub OAuth 授权用户发表评论,或者用户可以直接在 GitHub Issue 上评论。</div><div class="notion-text notion-block-1c1e3f3674f980b3b351e448ee1d79ae">另外,还有如下特点:</div><ul class="notion-list notion-list-disc notion-block-1c1e3f3674f980a8a376f55654d9c8ed"><li>支持多种页面与 Issue 的映射方式,如根据页面路径名、URL、标题或 Open Graph 标题等自动匹配或创建 Issue。</li></ul><ul class="notion-list notion-list-disc notion-block-1c1e3f3674f9807ba9b1f27579917362"><li>可配置特定 Issue 编号或自定义标题关键词以匹配 Issue,同时支持为创建的 Issue 添加标签。</li></ul><ul class="notion-list notion-list-disc notion-block-1c1e3f3674f980f8a29ef8b092989428"><li>提供多种主题选项,可以定制样式,并通过简单的 script 标签将 Utterances 集成到博客中。</li></ul><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1c1e3f3674f9808fbfc7ee0757754b54" data-id="1c1e3f3674f9808fbfc7ee0757754b54"><span><div id="1c1e3f3674f9808fbfc7ee0757754b54" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1c1e3f3674f9808fbfc7ee0757754b54" title="3、utterances 接入步骤"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">3、utterances 接入步骤</span></span></h2><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1c1e3f3674f980f98b7fc0e16c1aed90" data-id="1c1e3f3674f980f98b7fc0e16c1aed90"><span><div id="1c1e3f3674f980f98b7fc0e16c1aed90" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1c1e3f3674f980f98b7fc0e16c1aed90" title="3.1、创建仓库并安装 utterances"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">3.1、创建仓库并安装 utterances</span></span></h3><div class="notion-text notion-block-1c1e3f3674f980c0823df77f03c36399">1、然后需要创建一个公开的 github repo,接入utterances之后该仓库的 issues 用于存储博客的评论。</div><div class="notion-text notion-block-1c1e3f3674f980f792c3eb232d3b0766">2、在你 github repo 中安装 <!-- --> ,点击左边的链接安装到你 账号中,安装之后可以在用</div><div class="notion-text notion-block-1c1e3f3674f98013bdd2ed8ebc328221">户设置的 Application 中查看已经安装。</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1c1e3f3674f9803380a0c1075bfbe59c"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:100%"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3A89aabe25-58a8-4696-b24b-4f4294ea614a%3Aimage.png?table=block&amp;id=1c1e3f36-74f9-8033-80a0-c1075bfbe59c&amp;cache=v2" alt="安装utterances" loading="lazy" decoding="async"/><figcaption class="notion-asset-caption">安装utterances</figcaption></div></figure><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1c1e3f3674f9804fbf85f63368cbf0ff"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:100%"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3A5d14de54-7c09-4a12-9347-25c623b5e25f%3Aimage.png?table=block&amp;id=1c1e3f36-74f9-804f-bf85-f63368cbf0ff&amp;cache=v2" alt=" 安装成功,并进行配置" loading="lazy" decoding="async"/><figcaption class="notion-asset-caption"> 安装成功,并进行配置</figcaption></div></figure><div class="notion-text notion-block-1c1e3f3674f98019bf86e620c605f702">然后点击 Configure 配置按钮,确保第一步中的 github repo打开了对 <b>utterances </b>的操作权限。</div><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1c1e3f3674f98069b91fd07d8e14bd32" data-id="1c1e3f3674f98069b91fd07d8e14bd32"><span><div id="1c1e3f3674f98069b91fd07d8e14bd32" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1c1e3f3674f98069b91fd07d8e14bd32" title="3.2、代码配置到 blog 文件中"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">3.2、代码配置到 blog 文件中</span></span></h3><div class="notion-text notion-block-1c1e3f3674f98096a578dee10c281f49">打开 <!-- -->‣<!-- -->,在configuration 中配置 github repo 地址。</div><div class="notion-callout notion-gray_background_co notion-block-1c1e3f3674f9808cb145feb44c38d479"><div class="notion-page-icon-inline notion-page-icon-span"><span class="notion-page-icon" role="img" aria-label="💡">💡</span></div><div class="notion-callout-text"><div class="notion-text notion-block-1c1e3f3674f980aba1f7f6f64e229082">注意配置的格式是 owner/repo,其中 owner 是 account name,也就是你 github url中的name。</div></div></div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1c1e3f3674f980d088fce01f4689faec"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:100%"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3Acef83a1d-6b4e-4083-ae86-16acfc0f4d11%3Aimage.png?table=block&amp;id=1c1e3f36-74f9-80d0-88fc-e01f4689faec&amp;cache=v2" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-1c1e3f3674f98073bd50db4bac6c212c">然后会得到要嵌入到 blog 系统中的一段代码,根据blog 不同的技术实现,粘贴到相应的博客模板位置即可。</div><div class="notion-text notion-block-1c1e3f3674f9803bae51c2e5721225de">使用<code class="notion-inline-code">.utterances</code>和 <code class="notion-inline-code">.utterances-frame</code>选择器自定义布局和样式。</div><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1c1e3f3674f98067b46ac96a71a584cf" data-id="1c1e3f3674f98067b46ac96a71a584cf"><span><div id="1c1e3f3674f98067b46ac96a71a584cf" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1c1e3f3674f98067b46ac96a71a584cf" title="参考资料"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">参考资料</span></span></h2><div class="notion-text notion-block-1c1e3f3674f980daafbeec7edc4937d3"><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://utteranc.es/">https://utteranc.es/</a></div><div class="notion-text notion-block-1c1e3f3674f980b3b71dc11ac7e50c9b"><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://github.com/utterance/utterances">https://github.com/utterance/utterances</a></div><div class="notion-text notion-block-1c1e3f3674f98036b3b7d9c60972dabf"><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://bruceit.com/p/AGDc6W">使用 utterances 作为博客评论组件</a></div><div class="notion-blank notion-block-1c1e3f3674f980b98e92cce004b4deed"> </div></main> ]]>
</content>
</entry>
<entry>
<title type="html">
<![CDATA[ XAPK是什么文件,如何在安卓上安装XAPK? ]]>
</title>
<id>https://codexun.com/posts/how-to-install-xapk-apk-file</id>
<link href="https://codexun.com/posts/how-to-install-xapk-apk-file"/>
<updated>2025-03-19T16:00:00.000Z</updated>
<summary type="html">
<![CDATA[ XAPK文件是一种文件扩展格式,它与APK格式有些相似,但也有所不同。可以这么理解: XAPK文件= APK文件+ OBB数据文件。(OBB(Opaque Binary Blob)文件格式,是安卓游戏通用数据包)包含了单独的APK文件和OBB cache assets文件。Google Play 商店要求压缩APK大小不超过100 MB。用户通过Google Play Console每次上传一个APK时可以选择附带一到两个.obb格式的文件,这种.obb文件可以是大小不超过2 GB的任何格式(ZIP,PDF,MP4等)。 ]]>
</summary>
<content type="html">
<![CDATA[ <main class="notion light-mode notion-page notion-block-1c0e3f3674f9805a80abfa9abd13a20f"><div class="notion-viewport"></div><div class="notion-collection-page-properties"></div><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1c0e3f3674f9802fafc5f13d8894c3e0" data-id="1c0e3f3674f9802fafc5f13d8894c3e0"><span><div id="1c0e3f3674f9802fafc5f13d8894c3e0" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1c0e3f3674f9802fafc5f13d8894c3e0" title="什么是XAPK?"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">什么是XAPK?</span></span></h2><div class="notion-text notion-block-1c0e3f3674f980728c5eef433ed220ad">XAPK文件是一种文件扩展格式,它与APK格式有些相似,但也有所不同。</div><div class="notion-text notion-block-1c0e3f3674f98068ac7fd49ffb48b349">可以这么理解: <b>XAPK文件= APK文件+ OBB数据文件</b>。(<b>OBB</b>(Opaque Binary Blob)<b>文件</b>格式,是<b>安卓</b>游戏通用数据包)包含了单独的APK文件和OBB cache assets文件。</div><div class="notion-text notion-block-1c0e3f3674f9804aa345cdb2a75f0967">Google Play 商店要求压缩APK大小不超过100 MB。用户通过Google Play Console每次上传一个APK时可以选择附带一到两个.obb格式的文件,这种.obb文件可以是大小不超过2 GB的任何格式(ZIP,PDF,MP4等)。</div><div class="notion-text notion-block-1c0e3f3674f980b38cd3e2f83e614888">XAPK格式确保用户可以顺利下载大型文件避免中断或失败。</div><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1c0e3f3674f98012a024d1735b0145fb" data-id="1c0e3f3674f98012a024d1735b0145fb"><span><div id="1c0e3f3674f98012a024d1735b0145fb" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1c0e3f3674f98012a024d1735b0145fb" title="为什么使用XAPK?"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title"><b>为什么使用</b>XAPK?</span></span></h2><div class="notion-text notion-block-1c0e3f3674f9809ea8b0f8dbe0d6ef36"><b>APK文件</b>是在<b>Android智能手机</b>上安装应用程序的标准格式。由于大小原因,通常必须单独获取OBB文件。</div><div class="notion-text notion-block-1c0e3f3674f980e198a7d46e3500ed35">XAPK是一种zip格式,可将所有应用程序数据保存在一个文件中,以方便安装。如果您要下载XAPK文件,则该文件同时包含OBB和APK部分,以及同一存储库中的缓存,图标和其他信息。</div><div class="notion-text notion-block-1c0e3f3674f980d6a61cc7161c720ddf">但是,XAPK文件不像APK文件那样,可以通过手机上的默认安装器直接安装到安卓手机上。需要找一些三方工具,比如 XAPK Installer,或者 APKPure。</div><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1c0e3f3674f98051bdf2d9f8871186d4" data-id="1c0e3f3674f98051bdf2d9f8871186d4"><span><div id="1c0e3f3674f98051bdf2d9f8871186d4" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1c0e3f3674f98051bdf2d9f8871186d4" title="安装XAPK的方法和工具"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">安装XAPK的方法和工具</span></span></h2><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1c0e3f3674f98072a80de49bc3070c9b" data-id="1c0e3f3674f98072a80de49bc3070c9b"><span><div id="1c0e3f3674f98072a80de49bc3070c9b" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1c0e3f3674f98072a80de49bc3070c9b" title="1、工具 xapk installer"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">1、工具 xapk installer</span></span></h3><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1c0e3f3674f98021b276ec3766ec74b5"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:100%"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3A9e2b2210-68e7-4041-9019-b65dbb50789d%3Aimage.png?table=block&amp;id=1c0e3f36-74f9-8021-b276-ec3766ec74b5&amp;cache=v2" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-1c0e3f3674f980b9a912e49d667ff540">可以到 Google Play 上搜索 xapk installer,安装好之后扫描xapk 的文件,或者手动选择到 xapk 的路径,然后打开即可安装。</div><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1c1e3f3674f9805ebc69e96c777682bd" data-id="1c1e3f3674f9805ebc69e96c777682bd"><span><div id="1c1e3f3674f9805ebc69e96c777682bd" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1c1e3f3674f9805ebc69e96c777682bd" title="2、工具Install Buddy: XAPK, APKs"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">2、工具Install Buddy: XAPK, APKs</span></span></h3><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1c1e3f3674f980c092dbc79d9400b377"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:100%"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3Ac26569a3-91ad-4efd-b0be-4380447862e4%3Aimage.png?table=block&amp;id=1c1e3f36-74f9-80c0-92db-c79d9400b377&amp;cache=v2" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-1c1e3f3674f98082862af751ca804171">同上,可以在 google 应用商店搜索该应用。</div><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1c0e3f3674f980a4885cd83b2a9e9bc4" data-id="1c0e3f3674f980a4885cd83b2a9e9bc4"><span><div id="1c0e3f3674f980a4885cd83b2a9e9bc4" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1c0e3f3674f980a4885cd83b2a9e9bc4" title="3、工具ApkPure"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">3、工具ApkPure</span></span></h3><div class="notion-text notion-block-1c0e3f3674f98054b72dfeee2afc0b62">APKPure XAPK 安装器可以通过最便捷的方式帮你一键安装和管理安卓设备上的APK和XAPK文件。</div><div class="notion-text notion-block-1c0e3f3674f9807a92c4d3b66ba0f3e2">可以帮你集中浏览和管理所有XAPK和APK文件,同样也可以通过最简单的方式一键更新或者卸载任意XAPK和APK文件。</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1c0e3f3674f980c38e30fc4c6f0d706a"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:100%"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3A9b60514c-4223-4a8e-a49a-e97fa9526b8a%3Aimage.png?table=block&amp;id=1c0e3f36-74f9-80c3-8e30-fc4c6f0d706a&amp;cache=v2" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-callout notion-gray_background_co notion-block-1c1e3f3674f98061b95afbb4bcce2b5a"><div class="notion-page-icon-inline notion-page-icon-span"><span class="notion-page-icon" role="img" aria-label="💡">💡</span></div><div class="notion-callout-text"><div class="notion-text notion-block-1c0e3f3674f9809a968dea368b257313">需要注意的是,要为 xapk installer 等这些工具打开文件访问、应用安装(未知来源)的权限。</div></div></div><div class="notion-blank notion-block-1c1e3f3674f98098ae20edd2bb5869bb"> </div></main> ]]>
</content>
</entry>
<entry>
<title type="html">
<![CDATA[ 使用自定义 GitHub Actions CI/CD 部署到 Vercel ]]>
</title>
<id>https://codexun.com/posts/github-actions-deploy-vercel</id>
<link href="https://codexun.com/posts/github-actions-deploy-vercel"/>
<updated>2025-03-16T16:00:00.000Z</updated>
<summary type="html">
<![CDATA[ 通过 GitHub Actions 与 Vercel 集成,实现代码的自动化部署。除了上一篇文章使用Deploy Hooks 的方式进行调用部署之外,还可以有更复杂的场景。比如可以将 Vercel 与 GitHub Actions 一起使用作为您的 CI/CD 提供程序,在每次推送代码时生成预览部署,并在代码合并到main分支时部署到生产环境。具体实现步骤包括获取访问令牌、配置 GitHub Actions,以及利用 GitHub Marketplace 上的现成 Actions 来实现更灵活的部署。 ]]>
</summary>
<content type="html">
<![CDATA[ <main class="notion light-mode notion-page notion-block-1bae3f3674f980d983a1e29d94058fca"><div class="notion-viewport"></div><div class="notion-collection-page-properties"></div><div class="notion-text notion-block-1bae3f3674f9804a8ed5f401b33a8d03">除了上一篇介绍的 <b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://codexun.com/posts/automating-vercel-deployment-with-github-actions">使用 Github Action自动执行Vercel 部署</a></b><b> </b>使用Deploy Hooks 的方式进行部署之外,还可以有更复杂的场景。</div><div class="notion-text notion-block-1bae3f3674f980fead50ccecb4c32722">比如可以将 Vercel 与 GitHub Actions 一起使用作为您的 CI/CD 提供程序,在每次推送代码时生成预览部署,并在代码合并到<code class="notion-inline-code">main</code>分支时部署到生产环境。</div><div class="notion-text notion-block-1bae3f3674f9802d9267e93ca5bbba5b">这种则需要使用到 Vercel 的访问令牌 access_token 等。</div><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1bae3f3674f98037b065dbf46a8cacfa" data-id="1bae3f3674f98037b065dbf46a8cacfa"><span><div id="1bae3f3674f98037b065dbf46a8cacfa" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1bae3f3674f98037b065dbf46a8cacfa" title="1、获取相关访问令牌"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">1、获取相关访问令牌</span></span></h2><div class="notion-text notion-block-1bae3f3674f980a8bdbcf8b8dd2f096c">获取<code class="notion-inline-code">VERCEL_TOKEN</code>、<code class="notion-inline-code">VERCEL_ORG_ID</code>和<code class="notion-inline-code">VERCEL_PROJECT_ID</code> 相关token。</div><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1bae3f3674f980f98fa6f70d1a582782" data-id="1bae3f3674f980f98fa6f70d1a582782"><span><div id="1bae3f3674f980f98fa6f70d1a582782" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1bae3f3674f980f98fa6f70d1a582782" title="1.1、获取 Vercel api 访问令牌VERCEL_TOKEN"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">1.1、<a class="notion-link" href="https://www.notion.so/1bae3f3674f980d983a1e29d94058fca">获取 Vercel api 访问令牌</a>VERCEL_TOKEN</span></span></h3><div class="notion-text notion-block-1bae3f3674f98017b7a0e544cf3b3f6c">在 个人账号设置 → Token 菜单下,创建 api 访问令牌,也即是<code class="notion-inline-code">VERCEL_TOKEN</code>。</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1bae3f3674f980c7a379da4ee44a40af"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:100%"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3A2966ad62-4c5a-44f5-b092-050daa200244%3Aimage.png?table=block&amp;id=1bae3f36-74f9-80c7-a379-da4ee44a40af&amp;cache=v2" alt="notion image" loading="lazy" decoding="async"/></div></figure><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1bae3f3674f980488c91c0aa16bbb813" data-id="1bae3f3674f980488c91c0aa16bbb813"><span><div id="1bae3f3674f980488c91c0aa16bbb813" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1bae3f3674f980488c91c0aa16bbb813" title="1.2、获取VERCEL_PROJECT_ID"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">1.2、获取VERCEL_PROJECT_ID</span></span></h3><div class="notion-text notion-block-1bae3f3674f980eb9e2ef6a8fc7fef29">在Vercel 具体项目下, 项目设置 下找到 Project Id。</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1bae3f3674f9800b8bc9cd6910c1738c"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:100%"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3Abf95e13e-0bc3-4e62-a6f2-cc609c8527f5%3Aimage.png?table=block&amp;id=1bae3f36-74f9-800b-8bc9-cd6910c1738c&amp;cache=v2" alt="notion image" loading="lazy" decoding="async"/></div></figure><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1bae3f3674f98047937fdfcc53fcb4ee" data-id="1bae3f3674f98047937fdfcc53fcb4ee"><span><div id="1bae3f3674f98047937fdfcc53fcb4ee" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1bae3f3674f98047937fdfcc53fcb4ee" title="1.3、获取VERCEL_ORG_ID"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">1.3、获取VERCEL_ORG_ID</span></span></h3><ul class="notion-list notion-list-disc notion-block-1bae3f3674f980249018c77d5208658c"><li>使用命令行<code class="notion-inline-code">npm i -g vercel</code>安装Vercel CLI并运行<code class="notion-inline-code">vercel login</code></li></ul><ul class="notion-list notion-list-disc notion-block-1bae3f3674f980c1b016d39e941501aa"><li>在新建文件夹中,运行<code class="notion-inline-code">vercel link</code>以创建一个新的 Vercel 项目,或者是已有的Git 项目,会提示 <code class="notion-inline-code">✅  Linked to </code><code class="notion-inline-code"><b>xxx-projects/next-starter-example</b></code><code class="notion-inline-code"> (created .vercel)</code> 并生成.vercel 文件夹。</li></ul><ul class="notion-list notion-list-disc notion-block-1bae3f3674f980869ac5fb216ea66b0d"><li>在生成的.vercel文件夹中,从project.json<code class="notion-inline-code">{&quot;projectId&quot;:&quot;prj_xxx&quot;,&quot;orgId&quot;:&quot;team_xxx&quot;}</code>保存projectId和orgId。</li></ul><div class="notion-callout notion-gray_background_co notion-block-1bae3f3674f980e7b2fcd3ec49d05822"><div class="notion-page-icon-inline notion-page-icon-span"><span class="notion-page-icon" role="img" aria-label="💡">💡</span></div><div class="notion-callout-text"><div class="notion-text notion-block-1bae3f3674f98025aa2cd8b2836136ac">在Account Setting→General 菜单下,有<code class="notion-inline-code">Vercel ID[This is your user ID within Vercel.]</code> API Token,是否可以作为<code class="notion-inline-code">VERCEL_ORG_ID</code>?<span class="notion-red"><b>[未验证]</b></span></div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1bae3f3674f98079b202e3e8c18420d7"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:100%"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3A46c67e1b-6f59-4ca1-8af6-e94cd4844ca0%3Aimage.png?table=block&amp;id=1bae3f36-74f9-8079-b202-e3e8c18420d7&amp;cache=v2" alt="notion image" loading="lazy" decoding="async"/></div></figure></div></div><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1bae3f3674f98025bef5e5178c9bcae0" data-id="1bae3f3674f98025bef5e5178c9bcae0"><span><div id="1bae3f3674f98025bef5e5178c9bcae0" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1bae3f3674f98025bef5e5178c9bcae0" title="1.4、配置到 Github 中"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">1.4、配置到 Github 中</span></span></h3><div class="notion-text notion-block-1bae3f3674f980bfb560cdb3debb6b54">将以上<code class="notion-inline-code">VERCEL_TOKEN</code>、<code class="notion-inline-code">VERCEL_ORG_ID</code>和<code class="notion-inline-code">VERCEL_PROJECT_ID</code>添加到 GitHub 项目的 actions secret 配置中。</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1bae3f3674f980499ec8f51e790c8e38"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3Abc540c13-12fa-46f9-ab76-0b4997889edc%3Aimage.png?table=block&amp;id=1bae3f36-74f9-8049-9ec8-f51e790c8e38&amp;cache=v2" alt="notion image" loading="lazy" decoding="async"/></div></figure><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1bae3f3674f9803a9d8aec6825bbeef7" data-id="1bae3f3674f9803a9d8aec6825bbeef7"><span><div id="1bae3f3674f9803a9d8aec6825bbeef7" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1bae3f3674f9803a9d8aec6825bbeef7" title="2、配置 Github Actions"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">2、配置 Github Actions</span></span></h2><div class="notion-text notion-block-1bae3f3674f980ffb128ea013d85c1d5">当代码推送到非 main 分支时,生成预览部署:</div><div class="notion-blank notion-block-1bae3f3674f980e3ab2dc3ff67d7c326"> </div><div class="notion-text notion-block-1bae3f3674f980208b0ac11730f6e1c6">当代码推送到 main 分支时,生成正式部署:</div><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1bae3f3674f980fbbfdcd29d5db9d17c" data-id="1bae3f3674f980fbbfdcd29d5db9d17c"><span><div id="1bae3f3674f980fbbfdcd29d5db9d17c" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1bae3f3674f980fbbfdcd29d5db9d17c" title="3、借助marketplace 上的 Github Actions 实现"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">3、借助marketplace 上的 Github Actions 实现</span></span></h2><div class="notion-text notion-block-1bae3f3674f980c38033da150c62df0d">也可以借助一些已经实现好的 actions 来实现我们的需求。比如:</div><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1bae3f3674f980aa97f0d3e864554483" data-id="1bae3f3674f980aa97f0d3e864554483"><span><div id="1bae3f3674f980aa97f0d3e864554483" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1bae3f3674f980aa97f0d3e864554483" title="3.1、代码推送或者发起 pull request 时触发"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">3.1、代码推送或者发起 pull request 时触发</span></span></h3><h3 class="notion-h notion-h2 notion-h-indent-1 notion-block-1bae3f3674f980ea8fd9c7b09a528c1e" data-id="1bae3f3674f980ea8fd9c7b09a528c1e"><span><div id="1bae3f3674f980ea8fd9c7b09a528c1e" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1bae3f3674f980ea8fd9c7b09a528c1e" title="3.2、另一例:deploy-to-vercel-action"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">3.2、另一例:<a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://github.com/BetaHuhn/deploy-to-vercel-action">deploy-to-vercel-action</a></span></span></h3><div class="notion-text notion-block-1bae3f3674f9805aa554d56ec650721b">使用 GitHub Actions 将您的项目/站点部署到<a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://vercel.com/">Vercel</a>。在何时部署站点方面,它比 Vercel 的 GitHub 集成提供了更多的自定义功能。使用 GitHub Actions <a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://docs.github.com/en/actions/reference/events-that-trigger-workflows">Events,</a>您可以选择部署每个提交,仅在新版本上或甚至在 cron 计划上部署。该操作还可以部署每个 PR 并使用自定义预览 URL 对其进行评论。它使用 Vercel CLI,也可以自动在 GitHub 上创建部署。</div><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1bae3f3674f980cb911ac932dc38304b" data-id="1bae3f3674f980cb911ac932dc38304b"><span><div id="1bae3f3674f980cb911ac932dc38304b" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1bae3f3674f980cb911ac932dc38304b" title="参考资料"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">参考资料</span></span></h2><div class="notion-text notion-block-1bae3f3674f980068e14c76f9cbcb872"><b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://vercel.com/guides/how-can-i-use-github-actions-with-vercel">How can I use GitHub Actions with Vercel?</a></b></div><div class="notion-text notion-block-1bae3f3674f9807aa4b4e88abb2922fd"><b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://github.com/vercel/examples/blob/main/ci-cd/github-actions/README.md">Bring Your Own CI/CD - GitHub Actions</a></b><b> </b></div><div class="notion-blank notion-block-1c1e3f3674f980fbb683f1312e9bb3a2"> </div></main> ]]>
</content>
</entry>
<entry>
<title type="html">
<![CDATA[ 使用 Github Action自动执行Vercel 部署 ]]>
</title>
<id>https://codexun.com/posts/automating-vercel-deployment-with-github-actions</id>
<link href="https://codexun.com/posts/automating-vercel-deployment-with-github-actions"/>
<updated>2025-03-15T16:00:00.000Z</updated>
<summary type="html">
<![CDATA[ 使用 GitHub Actions 定时触发 Vercel 部署,创建 Build Hooks 和设置 GitHub Actions 变量,以实现每天自动构建和部署网站,优化 SEO 和速度。 ]]>
</summary>
<content type="html">
<![CDATA[ <main class="notion light-mode notion-page notion-block-1bae3f3674f980448a8ff67d78c2c8e4"><div class="notion-viewport"></div><div class="notion-collection-page-properties"></div><div class="notion-text notion-block-1bae3f3674f980a9832cede7142b2733">之前本网站部署在 Netlify 上的,有过一篇文章<b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://codexun.com/posts/automating-netlify-deployment-every-24-hours-with-github-actions">使用 Github Action自动执行 Netlify 部署</a></b><b>。 </b>以解决每周自动部署网站的功能,详细可点击查看。</div><div class="notion-text notion-block-1bae3f3674f9804aaf1fd1ff7a43f833">最近想查看下国内访问网站的速度情况,所以使用<a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://www.itdog.cn/"> itdog ping 工具</a>进行了测试,发现国内的情况十分不理想。</div><div class="notion-text notion-block-1bae3f3674f980a8a61cd6f0fd7cd3f9">所以萌生了起换到 vercel 上的想法,并且 vercel 也有 cdn 功能了,右边是切换到 vercel 上部署的情况,看起来好了很多。</div><div class="notion-row notion-block-1bae3f3674f9802197e4c8be210dd5f6"><div class="notion-column notion-block-1bae3f3674f980a38375d4fe772f8135" style="width:calc((100% - (1 * min(32px, 4vw))) * 0.5)"><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1bae3f3674f98068a1edf7dd69491c92"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:288px;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3A0a75618f-0ba9-41b1-8a0c-594980dac15a%3Aimage.png?table=block&amp;id=1bae3f36-74f9-8068-a1ed-f7dd69491c92&amp;cache=v2" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-blank notion-block-1bae3f3674f980b5bbe4fffe801b30da"> </div></div><div class="notion-spacer"></div><div class="notion-column notion-block-1bae3f3674f980c8af2ce55f06f2a246" style="width:calc((100% - (1 * min(32px, 4vw))) * 0.5)"><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1bae3f3674f9800bade3dc69b2e6b71d"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:288px;max-width:100%;flex-direction:column"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3A12463764-3f28-4208-9b18-acfa7e935fca%3Aimage.png?table=block&amp;id=1bae3f36-74f9-800b-ade3-dc69b2e6b71d&amp;cache=v2" alt="notion image" loading="lazy" decoding="async"/></div></figure></div><div class="notion-spacer"></div></div><div class="notion-text notion-block-1bae3f3674f98034a76ee56d2d28c0ff">切到 vercel 重新部署,域名重新解析配置好之后,对于之前 github action 定时部署的情况,需要重新写一份 workflow job。</div><div class="notion-text notion-block-1bae3f3674f980e8840bc6ce91e3287f">搜索vercel 同样支持 Deploy Hook 的方式。那就简单了,复制一份 Netlify 的文件,简单修改即可。</div><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1bae3f3674f98084936acfd743cbad9d" data-id="1bae3f3674f98084936acfd743cbad9d"><span><div id="1bae3f3674f98084936acfd743cbad9d" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1bae3f3674f98084936acfd743cbad9d" title="1、配置创建 Vercel Build Hooks"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">1、配置创建 Vercel Build Hooks</span></span></h2><div class="notion-text notion-block-1bae3f3674f98097a90af7181905253a">参考 <b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://vercel.com/docs/deploy-hooks">Creating &amp; Triggering Deploy Hooks</a></b> 官方文档。</div><div class="notion-text notion-block-1bae3f3674f98089bb77c638dff6ed98">官方说的清清楚,部署钩子允许您创建接受 HTTP<code class="notion-inline-code">POST</code>请求的 URL,以触发部署并重新运行<b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://vercel.com/docs/deployments/configure-a-build">构建步骤</a></b>。这些 URL 与您的项目、存储库和分支唯一链接,因此无需使用任何身份验证机制或向请求提供任何有效负载<code class="notion-inline-code">POST</code>。</div><div class="notion-text notion-block-1bae3f3674f98040b356ece9b36470a2">此功能允许您将 Vercel 部署与其他系统集成。例如,您可以设置:</div><ul class="notion-list notion-list-disc notion-block-1bae3f3674f980e39775f9e339f3dc42"><li>来自 Headless CMS 的内容更改的自动部署</li></ul><ul class="notion-list notion-list-disc notion-block-1bae3f3674f980b281c0cc3df14c2729"><li>通过配置第三方 cron 作业服务来触发 Deploy Hook 来进行计划部署</li></ul><ul class="notion-list notion-list-disc notion-block-1bae3f3674f980f7ad31fea6f7ba4a88"><li>通过命令行强制部署</li></ul><div class="notion-text notion-block-1bae3f3674f980629537f4101f003e63">在vercel 项目设置→Git中找到 Deploy Hooks 创建的地方,输入 hooks 名字,和代码分支,即可创建。</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1bae3f3674f98095a6a9d4567c156673"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:100%"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3Ad7292b1a-5b03-4ebc-a490-1f8db734804e%3Aimage.png?table=block&amp;id=1bae3f36-74f9-8095-a6a9-d4567c156673&amp;cache=v2" alt="notion image" loading="lazy" decoding="async"/></div></figure><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1bae3f3674f980e8b60fd7307d4b2908" data-id="1bae3f3674f980e8b60fd7307d4b2908"><span><div id="1bae3f3674f980e8b60fd7307d4b2908" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1bae3f3674f980e8b60fd7307d4b2908" title="2、创建 GitHub Actions secrets and variables"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">2、创建 GitHub Actions secrets and variables</span></span></h2><div class="notion-text notion-block-1bae3f3674f980129ecafde87278e8ee">在Github 的项目Setting下设置 github actions 所需要的变量。 例如,创建VECEL_BUILD_HOOK变量,value 为上一步获得的 vecel build hook 地址。</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1bae3f3674f980b49ba0f5eb1f9d11ae"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:100%"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3A43dc4546-8dfa-4818-a687-22108d1408b9%3Aimage.png?table=block&amp;id=1bae3f36-74f9-80b4-9ba0-f5eb1f9d11ae&amp;cache=v2" alt="notion image" loading="lazy" decoding="async"/></div></figure><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1bae3f3674f980a5a5d1ec4dae86bdc0" data-id="1bae3f3674f980a5a5d1ec4dae86bdc0"><span><div id="1bae3f3674f980a5a5d1ec4dae86bdc0" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1bae3f3674f980a5a5d1ec4dae86bdc0" title="3、实现 GitHub Actions"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">3、实现 GitHub Actions</span></span></h2><div class="notion-text notion-block-1bae3f3674f98031bd00d58e851915b5">触发 hooks 的示例请求为:</div><div class="notion-text notion-block-1bae3f3674f98079bdfadf16b489fc8a">响应示例:</div><div class="notion-text notion-block-1bae3f3674f980d4a666e724d71a00f0">发送请求后,您可以在项目仪表板上看到它触发了部署。</div><div class="notion-text notion-block-1bae3f3674f9802cb42cff325e20c63a">那么,实现 github actions 代码就比较简单了,参考如下:</div><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1bae3f3674f980fe86ece65af3855bde" data-id="1bae3f3674f980fe86ece65af3855bde"><span><div id="1bae3f3674f980fe86ece65af3855bde" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1bae3f3674f980fe86ece65af3855bde" title="参考资料"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">参考资料</span></span></h2><div class="notion-text notion-block-1bae3f3674f9805d9850f7b1507bc240"><b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://vercel.com/docs/deploy-hooks">Creating &amp; Triggering Deploy Hooks</a></b> 官方文档</div><div class="notion-text notion-block-1bae3f3674f980369e07d157c844e813"><b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://codexun.com/posts/automating-netlify-deployment-every-24-hours-with-github-actions">使用 Github Action自动执行 Netlify 部署</a></b></div><div class="notion-blank notion-block-1c1e3f3674f980c4a480f537854c207a"> </div></main> ]]>
</content>
</entry>
<entry>
<title type="html">
<![CDATA[ GitHub Actions:带有输入的调度和计划工作流程 ]]>
</title>
<id>https://codexun.com/posts/github-actions-workflow-with-inputs</id>
<link href="https://codexun.com/posts/github-actions-workflow-with-inputs"/>
<updated>2025-03-14T16:00:00.000Z</updated>
<summary type="html">
<![CDATA[ github actions工作流有输入。当工作流由 cron 触发时,我需要它使用一些默认变量运行。 为了支持手动触发,添加了 workflow_dispatch,并提供了用户输入选项 text_to_print,可以覆盖默认值。 ]]>
</summary>
<content type="html">
<![CDATA[ <main class="notion light-mode notion-page notion-block-1b8e3f3674f980ad9705f069ac0bcfbc"><div class="notion-viewport"></div><div class="notion-collection-page-properties"></div><div class="notion-text notion-block-1b8e3f3674f9800d868ad1f191125556">最近编写了一个项目,需要每天定时从 producthunt 抓取数据并生成阅读良好的 markdown 文档,项目已经上线,<code class="notion-inline-code"><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://indiehack.org/">参考地址</a></code>。</div><div class="notion-text notion-block-1b8e3f3674f980a78c12d47235f01b97">除此之外,还希望能够输入日期,手动触发抓取这一天的数据。</div><div class="notion-text notion-block-1b8e3f3674f980399c88c37988c540bb">也就是,工作流有输入。当工作流由 cron 触发时,我需要它使用一些默认变量运行。当手动触发时,我想允许用户覆盖一些默认值。</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1b8e3f3674f9803fa97ceb5d135992b5"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:100%"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3A9ce271cf-1eca-45c6-94e9-b2968b5ec0ba%3Aimage.png?table=block&amp;id=1b8e3f36-74f9-803f-a97c-eb5d135992b5&amp;cache=v2" alt="notion image" loading="lazy" decoding="async"/></div></figure><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1c1e3f3674f9803c8cddcffe96ca9707" data-id="1c1e3f3674f9803c8cddcffe96ca9707"><span><div id="1c1e3f3674f9803c8cddcffe96ca9707" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1c1e3f3674f9803c8cddcffe96ca9707" title="Github Actions 工作流示例"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">Github Actions 工作流示例</span></span></h2><div class="notion-text notion-block-1b8e3f3674f980ad90f7e8cfdc7a82bc">比如:有如下 github actions 工作流:</div><div class="notion-text notion-block-1b8e3f3674f9802897a5e6e83384e900">每隔一段时间,输出一段文字<code class="notion-inline-code">Periodically printing passages</code></div><div class="notion-text notion-block-1b8e3f3674f980549040f21a7ebe2e56">如果手动触发时,允许输入参数覆盖这一段文字,可以在定义工作流中,使用 inputs 来定义可以接收的输入,参考如下:</div><div class="notion-text notion-block-1b8e3f3674f9808e9318e16f20736d6c">我可以在 GitHub 中的 Actions 标签中触发此操作:</div><figure class="notion-asset-wrapper notion-asset-wrapper-image notion-block-1b8e3f3674f980678797d0e248eb448f"><div style="position:relative;display:flex;justify-content:center;align-self:center;width:100%;max-width:100%;flex-direction:column;height:100%"><img style="object-fit:cover" src="https://www.notion.so/image/attachment%3A0a08b5bd-9359-410f-993c-3abf298d421e%3Aimage.png?table=block&amp;id=1b8e3f36-74f9-8067-8797-d0e248eb448f&amp;cache=v2" alt="notion image" loading="lazy" decoding="async"/></div></figure><div class="notion-text notion-block-1b8e3f3674f9808c87c3d739f611df1b">让这个工作发挥作用的关键是:</div><div class="notion-text notion-block-1b8e3f3674f9802980fbedaba4e0c021"><code class="notion-inline-code">echo &quot;MESSAGE=${{ github.event.inputs.text_to_print || env.DEFAULT_MESSAGE }}&quot; &gt;&gt; $GITHUB_ENV</code></div><div class="notion-text notion-block-1b8e3f3674f980a6b497efc1a29dbdee">上面一行选择将定义的变量赋值给变量,<code class="notion-inline-code">MESSAGE</code>然后将其注入到变量中<code class="notion-inline-code">$GITHUB_ENV</code>。我们可以在<code class="notion-inline-code">Print some text</code>步骤中引用它。</div><h2 class="notion-h notion-h1 notion-h-indent-0 notion-block-1b8e3f3674f980f0b7cdc46aa9d8cd10" data-id="1b8e3f3674f980f0b7cdc46aa9d8cd10"><span><div id="1b8e3f3674f980f0b7cdc46aa9d8cd10" class="notion-header-anchor"></div><a class="notion-hash-link" href="#1b8e3f3674f980f0b7cdc46aa9d8cd10" title="参考资料"><svg viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z"></path></svg></a><span class="notion-h-title">参考资料</span></span></h2><div class="notion-text notion-block-1b8e3f3674f980398c84ce107e08419f"><b><a target="_blank" rel="noopener noreferrer" class="notion-link" href="https://codexun.com/posts/automating-netlify-deployment-every-24-hours-with-github-actions">使用 Github Action自动执行 Netlify 部署</a></b></div><div class="notion-blank notion-block-1b8e3f3674f980f9bdc4c716cbd35c19"> </div></main> ]]>
</content>
</entry>
</feed>