当前位置: 首页 > news >正文

基于Next.js与GitHub Pages构建个人开发者门户:从SSG到CI/CD全流程实践

1. 项目概述:一个开发者个人门户的诞生

在技术社区里,一个以自己名字命名的.github.io仓库,往往不仅仅是一个静态网站,它更像是一个开发者的数字名片、技术博客、项目集散地,甚至是一个个人品牌的线上总部。今天要聊的这个项目kerogrammer/kerogrammer.github.io,就是一个非常典型的案例。从仓库命名就能一眼看出,这是一个托管在 GitHub Pages 上的个人站点,其所有者是一位名为 “kerogrammer” 的开发者。

对于很多程序员,尤其是全栈或前端开发者来说,拥有一个自定义的、内容完全由自己掌控的个人网站,其意义远超一个简单的在线简历。它不仅是展示你技术栈(比如 React, Vue, Next.js 等)和过往项目的最佳画布,更是你系统化输出技术思考、记录学习轨迹、构建个人影响力的核心阵地。与在第三方平台写博客不同,这里的每一行代码、每一个交互细节、乃至整体的部署流程,都完全由你定义。你可以把它做得极简,专注于内容;也可以把它打造成一个复杂的技术试验场,集成各种前沿的 Web 技术。

这个项目标题本身,就隐含了几个关键的技术点:GitHub Pages 的自动化部署、静态站点生成器的选型(或纯手写 HTML/CSS/JS)、版本控制与持续集成/持续部署(CI/CD)的实践,以及如何将代码仓库与个人域名(如果有的话)进行绑定。接下来,我们就深入拆解一下,要构建并维护好这样一个站点,背后需要理清的思路、踩过的坑以及可以分享的经验。

2. 核心思路与架构选型

2.1 为什么选择 GitHub Pages 作为托管平台?

首先,最直接的问题是:为什么是github.io?市面上有 Vercel, Netlify, Cloudflare Pages 等众多优秀的静态站点托管服务,它们通常提供更快的全球 CDN、更丰富的构建环境以及 Serverless 函数等高级功能。

选择 GitHub Pages 的核心理由,我总结为三点:无缝集成、完全免费、极简运维

  1. 无缝集成:如果你的代码本身就托管在 GitHub,那么 GitHub Pages 是“开箱即用”的。创建一个名为<username>.github.io的仓库,将静态文件推送到指定分支(通常是maingh-pages),网站几乎瞬间就能通过https://<username>.github.io访问。这种与源码仓库的深度绑定,使得内容更新变成了单纯的git push操作,极大地简化了工作流。
  2. 完全免费:对于个人项目、开源文档或技术博客来说,GitHub Pages 提供的流量和存储额度完全够用,没有任何费用。这对于学生和独立开发者尤其友好。
  3. 极简运维:你不需要关心服务器配置、SSL 证书(GitHub 自动提供并续签 HTTPS)、负载均衡或安全补丁。这些底层运维工作全部由 GitHub 承担,你可以专注于内容创作和前端开发。

当然,它也有局限性,比如不支持服务端运行时(如 Node.js, PHP)、构建环境有一定限制、自定义域名配置的 HTTPS 有时需要手动触发等。但对于一个以展示和内容为主的个人站点,这些限制大多在可接受范围内。

2.2 静态站点生成器(SSG)还是手动构建?

确定了托管平台,接下来就要决定站点的生成方式。这里主要有两条路径:

路径一:使用静态站点生成器(SSG)这是目前最主流、效率最高的方式。SSG 允许你使用 Markdown 书写内容,通过模板和主题生成最终的 HTML、CSS、JavaScript 文件。常见的选型有:

  • Jekyll:GitHub Pages 原生支持,集成度最高。如果你希望部署流程最简单,Jekyll 是首选。它的生态成熟,有大量主题可供选择。
  • Hugo:以编译速度极快著称,适合内容较多的博客。使用 Go 语言编写,单二进制文件,部署方便。
  • Next.js:虽然通常被认为是 React 框架,但其静态导出(next export)功能让它成为一个强大的 SSG。如果你本身就在 React 生态中,并且希望站点拥有高度交互性,Next.js 是非常好的选择。Vercel 对其支持最好,但在 GitHub Pages 上也能良好运行。
  • VuePress / VitePress:Vue 生态的文档/博客生成器,体验流畅,尤其适合技术文档类站点。

路径二:手动编写 HTML/CSS/JS这种方式给予开发者最大的控制权,但开发效率较低。它适合以下几种情况:

  • 站点结构极其简单,只有几个页面。
  • 你希望深入练习和展示原生前端技术,不依赖任何框架。
  • 你需要实现一些非常定制化、框架难以满足的交互效果。

对于kerogrammer这样的项目,如果开发者希望快速搭建一个内容丰富的博客,我通常会推荐从 Jekyll 或 Hugo 开始。如果开发者更熟悉现代前端框架,并计划在站点中加入更多动态功能(如项目搜索、暗色模式切换、交互式组件),那么 Next.js 或基于 Vite 的静态方案会是更面向未来的选择。

注意:如果你选择非 Jekyll 的 SSG,需要在仓库中配置 GitHub Actions 来实现自动构建和部署。因为 GitHub Pages 默认只认识 Jekyll 或纯静态文件。这是一个关键的技术决策点。

3. 项目初始化与核心配置实战

假设我们为kerogrammer选择使用Next.js框架来构建站点,并将其部署到 GitHub Pages。这是一个兼顾现代开发体验和灵活性的方案。下面我们来一步步拆解实操过程。

3.1 仓库创建与本地开发环境搭建

首先,在 GitHub 上创建仓库,名称必须为kerogrammer.github.io(注意用户名要完全匹配)。这将自动保留你的*.github.io域名。

接着,在本地进行开发:

# 使用 Next.js 官方脚手架创建项目 npx create-next-app@latest kerogrammer.github.io # 根据提示选择:TypeScript? Yes, ESLint? Yes, Tailwind CSS? 按需选择,App Router? 推荐。 cd kerogrammer.github.io

初始化完成后,一个基础的 Next.js 项目就准备好了。Next.js 13+ 的 App Router 提供了基于文件系统的路由,非常直观。你可以开始规划你的站点结构:

  • app/page.tsx-> 首页 (/)
  • app/blog/page.tsx-> 博客列表页 (/blog)
  • app/blog/[slug]/page.tsx-> 博客详情页 (/blog/my-first-post)
  • app/projects/page.tsx-> 项目展示页 (/projects)
  • app/about/page.tsx-> 关于页面 (/about)

3.2 针对 GitHub Pages 的关键配置

要让 Next.js 项目在 GitHub Pages 上正确运行,需要进行几项关键配置。

1. 修改next.config.jsGitHub Pages 默认将站点部署在子路径下(如https://kerogrammer.github.io/),但如果你配置了自定义域名并解析到根目录,则可能不需要。为了兼容性,通常需要配置basePath

// next.config.js /** @type {import('next').NextConfig} */ const nextConfig = { // 如果你的仓库名就是 <username>.github.io,且部署在根目录,通常不需要 basePath。 // 但如果你部署在非根目录(如项目站点),则需要设置 basePath: '/your-repo-name'。 // 这里我们假设部署在根目录,所以先注释掉。 // basePath: '/kerogrammer.github.io', // 输出为静态站点(对于纯内容站,推荐开启) output: 'export', // 关键!这告诉 Next.js 生成静态 HTML 文件 // 可选:配置图片优化(静态导出时,需要指定未优化模式或配置外部loader) images: { unoptimized: true, // 静态导出时,简单处理图片,避免复杂优化依赖 }, }; module.exports = nextConfig;

设置output: 'export'后,运行next build将生成一个out文件夹,里面是所有静态文件。这就是将要部署到 GitHub Pages 的内容。

2. 创建 GitHub Actions 工作流文件由于我们不是用 Jekyll,GitHub Pages 不会自动构建 Next.js 项目。我们需要通过 GitHub Actions 来实现自动化构建和部署。

在项目根目录创建.github/workflows/deploy.yml文件:

name: Deploy to GitHub Pages on: push: branches: ['main'] # 当推送到 main 分支时触发 workflow_dispatch: # 允许手动触发 permissions: contents: read pages: write id-token: write concurrency: group: 'pages' cancel-in-progress: false jobs: build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' # 使用 LTS 版本 cache: 'npm' - name: Install dependencies run: npm ci # 使用 ci 命令确保依赖锁一致 - name: Build with Next.js run: npm run build # 这会执行 next build,生成 out 目录 - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: path: ./out # 上传构建产物 deploy: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest needs: build steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4

这个工作流定义了:在代码推送到main分支后,自动在一个 Ubuntu 环境中安装 Node.js、项目依赖,执行构建,并将生成的out文件夹内容部署到 GitHub Pages。

3. 在 GitHub 仓库中启用 Pages 并选择源完成以上步骤后,你需要到 GitHub 仓库的Settings->Pages页面:

  • Source:选择GitHub Actions。这样 GitHub 就会使用我们上面编写的 Action 工作流来部署,而不是尝试用 Jekyll 构建。
  • 稍等片刻,Action 运行成功后,你的站点就会在线了。

4. 内容规划与核心功能实现

一个技术个人站点的内容骨架通常包括:首页(简介、最新动态)、博客、项目展示、关于页面。我们以博客系统为例,看看如何用 Next.js 实现一个简单但实用的方案。

4.1 基于文件系统的博客系统

一种简单高效的方式是将每篇博客写成一个 Markdown 文件,存放在content/blog/目录下。例如:

content/blog/ ├── my-first-post.md ├── nextjs-deploy-guide.md └── ...

每篇 Markdown 文件可以包含 Front Matter(元数据)和正文:

--- title: '在 GitHub Pages 上部署 Next.js 全指南' date: '2024-05-15' description: '详细讲解如何配置 Next.js 项目并通过 GitHub Actions 自动部署到 GitHub Pages。' tags: ['Next.js', 'GitHub Pages', 'CI/CD'] --- 这里是博客正文,支持 **Markdown** 语法。 ## 章节标题 可以写代码示例: ```javascript console.log('Hello, kerogrammer!');
### 4.2 使用 `gray-matter` 和 `remark` 解析 Markdown 我们需要在 Next.js 中读取并解析这些 Markdown 文件。首先安装必要的库: ```bash npm install gray-matter remark remark-html

然后,可以创建一个工具函数lib/posts.ts来获取所有博客文章:

import fs from 'fs'; import path from 'path'; import matter from 'gray-matter'; import { remark } from 'remark'; import html from 'remark-html'; const postsDirectory = path.join(process.cwd(), 'content/blog'); export interface PostData { id: string; // 文件名(不含扩展名) title: string; date: string; description: string; tags?: string[]; contentHtml?: string; } export async function getSortedPostsData(): Promise<PostData[]> { const fileNames = fs.readdirSync(postsDirectory); const allPostsData = await Promise.all( fileNames.map(async (fileName) => { const id = fileName.replace(/\.md$/, ''); const fullPath = path.join(postsDirectory, fileName); const fileContents = fs.readFileSync(fullPath, 'utf8'); const matterResult = matter(fileContents); // 使用 remark 将 Markdown 转换为 HTML(可选,列表页可能只需要元数据) const processedContent = await remark() .use(html) .process(matterResult.content); const contentHtml = processedContent.toString(); return { id, contentHtml, ...(matterResult.data as Omit<PostData, 'id' | 'contentHtml'>), }; }) ); // 按日期排序 return allPostsData.sort((a, b) => (a.date < b.date ? 1 : -1)); } export function getAllPostIds() { const fileNames = fs.readdirSync(postsDirectory); return fileNames.map((fileName) => ({ params: { id: fileName.replace(/\.md$/, ''), }, })); } export async function getPostData(id: string): Promise<PostData> { const fullPath = path.join(postsDirectory, `${id}.md`); const fileContents = fs.readFileSync(fullPath, 'utf8'); const matterResult = matter(fileContents); const processedContent = await remark() .use(html) .process(matterResult.content); const contentHtml = processedContent.toString(); return { id, contentHtml, ...(matterResult.data as Omit<PostData, 'id' | 'contentHtml'>), }; }

4.3 实现博客列表页与详情页

列表页 (app/blog/page.tsx)

import { getSortedPostsData } from '@/lib/posts'; import Link from 'next/link'; export default async function BlogPage() { const allPostsData = await getSortedPostsData(); return ( <div className="container mx-auto px-4 py-8"> <h1 className="text-3xl font-bold mb-8">技术博客</h1> <ul className="space-y-6"> {allPostsData.map(({ id, date, title, description, tags }) => ( <li key={id} className="border-b pb-6"> <Link href={`/blog/${id}`} className="group"> <h2 className="text-2xl font-semibold text-blue-600 group-hover:text-blue-800 transition-colors"> {title} </h2> </Link> <p className="text-gray-500 mt-1">{date}</p> <p className="text-gray-700 mt-2">{description}</p> {tags && ( <div className="mt-2 flex flex-wrap gap-2"> {tags.map((tag) => ( <span key={tag} className="px-2 py-1 bg-gray-100 text-gray-800 text-sm rounded"> #{tag} </span> ))} </div> )} </li> ))} </ul> </div> ); }

详情页 (app/blog/[slug]/page.tsx)

import { getPostData, getAllPostIds } from '@/lib/posts'; import { notFound } from 'next/navigation'; // 生成静态路径 export async function generateStaticParams() { const paths = getAllPostIds(); return paths; } export default async function PostPage({ params }: { params: { slug: string } }) { const postData = await getPostData(params.slug); if (!postData) { notFound(); } return ( <article className="container mx-auto px-4 py-8 max-w-3xl"> <header className="mb-8"> <h1 className="text-4xl font-bold mb-2">{postData.title}</h1> <p className="text-gray-500">{postData.date}</p> {postData.tags && ( <div className="mt-3 flex flex-wrap gap-2"> {postData.tags.map((tag) => ( <span key={tag} className="px-3 py-1 bg-blue-100 text-blue-800 text-sm rounded-full"> {tag} </span> ))} </div> )} </header> <div className="prose prose-lg max-w-none" // 使用 Tailwind Typography 插件美化内容 dangerouslySetInnerHTML={{ __html: postData.contentHtml || '' }} /> </article> ); }

通过这种方式,一个基于文件系统、支持 Markdown、可静态生成的博客系统就搭建完成了。每次新增.md文件,提交并推送后,GitHub Actions 会自动构建并更新网站。

5. 样式、性能与 SEO 优化

5.1 样式方案选择:Tailwind CSS

对于个人项目,我强烈推荐使用Tailwind CSS。它是一个实用优先的 CSS 框架,能极大提升开发效率。正如我们在初始化项目时可以选择,它与 Next.js 集成非常顺畅。

优势

  • 开发速度快:无需在 CSS 文件和 JSX 文件间来回切换,直接在 className 中编写样式。
  • 设计一致性:通过配置tailwind.config.js可以定义一套自己的设计令牌(颜色、间距、字体等),确保全站样式统一。
  • 生成的 CSS 体积小:通过 PurgeCSS(在 Tailwind 中内置)移除未使用的样式,最终生成的 CSS 文件非常精简。

实操技巧: 在app/globals.css中引入 Tailwind:

@tailwind base; @tailwind components; @tailwind utilities;

然后,你就可以在组件中这样使用:

<h1 className="text-3xl font-bold text-gray-900 hover:text-blue-600 transition-colors"> 这是一个标题 </h1>

5.2 图片优化与字体加载

图片优化: 由于我们设置了images: { unoptimized: true },Next.js 的 Image 组件将不会进行自动优化。对于 GitHub Pages 这种静态托管,一个替代方案是:

  1. 在构建前手动优化图片(使用工具如 Squoosh, ImageOptim)。
  2. 或者,使用第三方图片优化服务(如 Cloudinary)的 URL 参数进行优化。
  3. 如果图片不多,且均为静态资源,直接使用<img>标签并确保图片尺寸适当也是可接受的。

字体加载: 使用next/font可以自动优化谷歌字体或本地字体,将其内联或预加载,避免布局偏移和额外网络请求。

// app/layout.tsx import { Inter } from 'next/font/google'; const inter = Inter({ subsets: ['latin'] }); export default function RootLayout({ children }) { return ( <html lang="zh-CN" className={inter.className}> <body>{children}</body> </html> ); }

5.3 SEO 基础配置

一个个人站点同样需要关注搜索引擎优化(SEO),让更多人能找到你的内容。

  1. 元标签:在每个页面使用 Next.js 的MetadataAPI(App Router)或next/head(Pages Router)来设置标题、描述和关键词。

    // app/blog/[slug]/page.tsx import type { Metadata } from 'next'; export async function generateMetadata({ params }): Promise<Metadata> { const post = await getPostData(params.slug); return { title: `${post.title} | kerogrammer's Blog`, description: post.description, keywords: post.tags?.join(', '), }; }
  2. 语义化 HTML:合理使用<header>,<main>,<article>,<section>,<nav>等标签,有助于搜索引擎理解页面结构。

  3. sitemap.xmlrobots.txt:在app目录下创建sitemap.tsrobots.ts文件,Next.js 会在构建时自动生成对应的静态文件。

    // app/sitemap.ts import { MetadataRoute } from 'next'; import { getSortedPostsData } from '@/lib/posts'; export default async function sitemap(): Promise<MetadataRoute.Sitemap> { const posts = await getSortedPostsData(); const baseUrl = 'https://kerogrammer.github.io'; const postEntries: MetadataRoute.Sitemap = posts.map((post) => ({ url: `${baseUrl}/blog/${post.id}`, lastModified: new Date(post.date), changeFrequency: 'monthly', priority: 0.8, })); return [ { url: baseUrl, lastModified: new Date(), changeFrequency: 'weekly', priority: 1, }, { url: `${baseUrl}/blog`, lastModified: new Date(), changeFrequency: 'weekly', priority: 0.9, }, ...postEntries, ]; }
  4. Open Graph 标签:为社交媒体分享提供预览信息,可以使用next/og库动态生成或静态定义。

6. 自定义域名绑定与 HTTPS 配置

虽然username.github.io的域名已经很好,但绑定一个自定义域名(如kerogrammer.com)会让你的个人品牌更专业。

操作步骤

  1. 购买域名:在任意域名注册商处购买你心仪的域名。
  2. 配置 DNS 记录:在你的域名管理后台,添加以下记录:
    • 类型CNAME
    • 主机记录@www(如果你希望www也指向你的站点)
    • 记录值kerogrammer.github.io.(注意末尾的点)
    • 或者,你也可以使用A记录,指向 GitHub Pages 的 IP 地址(185.199.108.153,185.199.109.153,185.199.110.153,185.199.111.153)。CNAME 通常更灵活。
  3. 在 GitHub 仓库中设置:进入仓库的Settings -> Pages,在 “Custom domain” 栏中输入你的域名(如kerogrammer.com),然后点击 Save。
  4. 等待并检查:DNS 生效可能需要几分钟到几小时。生效后,GitHub 会自动为你的域名申请并配置 Let‘s Encrypt 的 SSL 证书,启用 HTTPS。你可以在仓库中看到一个CNAME文件被创建。

重要提示:启用自定义域名后,强烈建议同时勾选 “Enforce HTTPS” 选项,强制所有访问都通过安全的 HTTPS 连接。

7. 持续维护与内容更新策略

站点搭建完成只是开始,持续的维护和内容更新才是其价值所在。

7.1 内容更新工作流

建立一套流畅的本地写作和发布流程至关重要:

  1. 本地写作:在content/blog/下新建.md文件,使用你喜欢的 Markdown 编辑器(如 VS Code, Obsidian, Typora)进行写作。
  2. 本地预览:运行npm run dev,在http://localhost:3000实时预览效果。
  3. 提交与推送
    git add . git commit -m "发布新文章:《XXXXX》" git push origin main
  4. 自动部署:推送后,GitHub Actions 会自动触发构建和部署流程。大约 1-2 分钟后,新内容就会上线。

7.2 性能监控与数据分析

虽然 GitHub Pages 本身很稳定,但了解访客情况还是有必要的。

  • Google Analytics 4 (GA4):在app/layout.tsx中插入 GA4 的脚本,可以免费获得基本的流量来源、页面浏览量、用户设备等数据。
  • Vercel Analytics 或 Plausible:如果你追求更简洁、隐私友好的分析工具,可以考虑这些替代品。它们可能需要额外的配置或反向代理。

7.3 定期备份与版本控制

你的整个站点代码和内容都已经在 Git 仓库中,这本身就是最好的备份。但还需要注意:

  • 环境依赖:确保package.jsonpackage-lock.json(或yarn.lock)准确记录了所有依赖。
  • 重要数据:如果你有评论系统(如基于 GitHub Discussions 或 Utterances)、访客统计等动态数据,确保了解其备份或导出机制。

8. 常见问题与排查技巧实录

在构建和部署过程中,你几乎一定会遇到一些问题。下面是一些常见坑点及其解决方案。

8.1 构建失败:GitHub Actions 报错

问题:推送代码后,Actions 运行失败,网站没有更新。排查步骤

  1. 查看 Action 日志:在 GitHub 仓库的 “Actions” 标签页,点击失败的工作流,查看详细的错误日志。这是最重要的信息源。
  2. 常见原因
    • 依赖安装失败:网络问题或package-lock.json冲突。尝试在本地运行npm ci看是否成功。
    • 构建脚本错误:本地npm run build是否通过?确保本地构建成功再推送。
    • Node.js 版本不匹配:检查工作流文件中的node-version是否与项目兼容。Next.js 通常需要较新的 Node 版本。
    • 路径或配置错误:检查next.config.js中的output: 'export'basePath设置是否正确。如果使用了next/image但未配置unoptimized: true,静态导出也会失败。

8.2 页面显示 404 或样式丢失

问题:网站能打开,但部分页面 404,或者 CSS/JS 加载失败。排查步骤

  1. 检查basePath:这是最可能的原因。如果你的仓库名是kerogrammer.github.io且部署在根目录,next.config.js不应该设置basePath。如果设置了错误的basePath,所有资源路径都会错位。
  2. 检查文件路径:确保out目录下的文件结构正确。静态导出后,app/blog/[slug]/page.tsx会生成out/blog/[slug]/index.html。如果路由配置复杂,可能生成的文件位置不符合预期。
  3. 清除浏览器缓存:有时是旧的缓存文件在作祟。尝试使用无痕模式访问。

8.3 自定义域名 HTTPS 证书问题

问题:绑定自定义域名后,HTTPS 一直显示不安全或证书错误。排查步骤

  1. 等待:GitHub 申请证书可能需要最多 24 小时。请耐心等待。
  2. 检查 DNS 配置:确保 CNAME 或 A 记录已正确指向 GitHub Pages,并且已完全生效(可使用dig yourdomain.com或在线 DNS 查询工具检查)。
  3. 检查仓库设置:在仓库的 Pages 设置里,确认自定义域名已填写正确,并且 “Enforce HTTPS” 复选框已勾选。有时取消勾选再重新勾选可以触发证书重新申请。
  4. 检查CNAME文件:仓库根目录下应该有一个CNAME文件,里面只有一行你的域名。如果这个文件丢失或内容错误,HTTPS 会出问题。

8.4 图片等静态资源无法加载

问题:Markdown 中的图片或public文件夹下的静态资源在部署后显示为裂图。排查步骤

  1. 路径问题:在 Markdown 中引用图片,建议使用绝对路径(以/开头),并确保图片文件位于public目录下。例如,将图片放在public/images/,在 Markdown 中写![alt](/images/my-photo.jpg)
  2. next/image配置:如果你使用了next/image组件并设置了unoptimized: true,请确保图片路径正确,并且组件被正确使用。
  3. 检查构建产物:查看out目录,确认图片文件是否被正确复制进去。

8.5 网站更新有延迟

问题:推送代码后,网站内容没有立即更新。排查步骤

  1. GitHub Actions 状态:确认 Actions 工作流已成功完成。部署到 GitHub Pages 本身也有一个短暂的发布过程。
  2. CDN 缓存:GitHub Pages 背后有 CDN,可能存在缓存。通常几分钟内会更新,极端情况下可能需要清除浏览器缓存或等待 CDN 刷新。
  3. 自定义域名 DNS 缓存:如果你使用了自定义域名,DNS 变更和缓存时间可能更长。

构建和维护kerogrammer.github.io这样的个人站点,是一个将技术实践、内容创作和个人品牌建设相结合的过程。从技术选型、自动化部署到内容创作和 SEO 优化,每一个环节都值得深入琢磨。这个项目本身就是一个持续演进的作品,它记录着你的成长轨迹。最关键的其实不是一开始就做到完美,而是先让它跑起来,然后随着你的技能和需求的变化,不断地去迭代和优化它。每次解决一个部署问题,每添加一项新功能,每发布一篇有价值的文章,都是这个数字名片上闪亮的一笔。

http://www.jsqmd.com/news/771649/

相关文章:

  • 拆解特斯拉Autopilot与比亚迪DiPilot:主流车企的ADAS方案到底有何不同?
  • OR-Tools:如何用Google的运筹学引擎解决现实世界优化难题?
  • 【IEEE出版、高校联合主办、启动评优】第八届物联网、自动化和人工智能国际学术会议(IoTAAI 2026)
  • 别再只写累加和了!汽车CAN总线通信中,这几种Checksum算法你都知道吗?
  • 2026最新 海口代理记账公司排行:合规与服务能力实测盘点 - 奔跑123
  • 广东佛山心理机构怎么选?4家正规心理咨询中心测评对比 - 野榜数据排行
  • 5分钟快速指南:使用WeakAuras Companion告别繁琐的手动更新
  • Obsidian Tasks:5步掌握任务优先级管理,让重要事项不再遗漏
  • 康安倍泰抑菌粉:以标准为尺,以科研为基,守护女性健康 - 品牌排行榜
  • 基于Vue 3与FastAPI的ChatGPT Web应用脚手架:从流式对话到生产部署
  • PCL点云可视化神器pcl_viewer:从安装到常用快捷键的保姆级指南(附坐标查看技巧)
  • 别再乱用LDO了!实测对比MP2315、RT9193和ADR4550,教你根据电流和压差选对电源芯片
  • 长河、龙龙、欣荣——温州三家黄金回收实体店怎么选?附地址电话 - 李甜岚
  • 中小企业小程序制作服务商怎么选?3种模式成本_速度_功能全对比 - 维双云小凡
  • 串级 PID 在双轮足机器人中的应用:从理论到嵌入式调参
  • 广州本地商家GEO优化实战:从零搭建AI搜索可见度,如何选择广州本地GEO优化公司 - 品牌评测官
  • 7种粗细样式的思源宋体:彻底改变你的中文排版体验,完全免费商用!
  • 告别Optane后,国产SCM存储级内存Xlenstor2 X2900P实战评测:真能平替吗?
  • 使用 jQuery 实现鼠标滚轮事件:监听向上/向下滑动
  • 2026最新海口工商注册公司排行:合规与服务实力实测盘点 - 奔跑123
  • 初次使用Taotoken模型广场进行模型选型与测试的直观感受
  • 2026采购挤出型材选哪家?PMMA、ASA、TPU、HDPE厂家推荐 - 品牌2025
  • 潍坊悍龙机械设备:杭州液压钻床出售哪家口碑好 - LYL仔仔
  • 2026四川碳纤维加固服务商专业深度测评报告 - 深度智识库
  • 全栈开发技术栈解析:TypeScript、React、Prisma与Docker的现代化实践
  • AISMM实施失败率高达67%?一线审计师血泪复盘:4类组织架构陷阱与即刻自检清单
  • 重新定义物联网通信:PubSubClient如何为嵌入式设备带来企业级消息队列能力
  • AISMM 2.0核心算法迭代深度解析(SITS2026闭门报告首次公开)
  • MiroMind暂停大中华区服务,知识产权争议与合规风险成背后隐忧
  • 北京九鼎众合餐饮管理:口碑好的北京盒饭配送公司 - LYL仔仔