文章 · 2024-01-01

从 404 到 200:记一次 Astro + GitHub Pages 样式丢失问题的深度排查

这些 CSS 文件的路径看起来像这样:

https://geyuxu.com/_astro/_slug_.BvCO7WHQ.css

服务器找不到 Astro 构建出来的 CSS 文件。问题在哪里?

排查:两条死路

假设 1:Jekyll 的锅?

GitHub Pages 默认使用 Jekyll 构建站点。Jekyll 有一条众所周知的规则:忽略所有以下划线开头的目录和文件,例如 _posts_includes。Astro 的构建产物中,CSS 文件放在 _astro 目录下,看起来直指病因。

尝试:在仓库根目录添加空的 .nojekyll 文件,告诉 GitHub Pages 跳过 Jekyll、直接提供静态内容。

结果_astro 目录下的 CSS 仍然是 404。

.nojekyll 应该已完全禁用 Jekyll,但问题依旧。显然另有原因。

假设 2:目录访问问题?

也许 _astro 目录因为缺少 index.html 而无法访问?

尝试:在 dist/_astro/ 下手动创建空的 index.html,重新部署。

结果:无效。我们请求的是具体文件,不是浏览目录列表。

真正的原因

禁用 Jekyll 是必要条件,但不是充分条件。进一步搜索之后,发现了一个更底层的约束:

GitHub Pages 会屏蔽所有文件名以下划线开头的文件的直接访问。这条规则似乎在服务器层面生效,与 Jekyll 无关。

Astro 生成的 CSS 文件名,例如 _slug_.BvCO7WHQ.css,同样以下划线开头。_astro 目录名是一个问题,文件名本身是另一个问题。.nojekyll 两者都没有解决。

修改构建产物命名

既然平台规则无法改变,就让构建输出主动规避:配置 Astro 不生成以下划线开头的文件名。

Astro 底层使用 Vite,并通过 astro.config.mjs 暴露了 Vite 的配置接口。关键配置项是 vite.build.rollupOptions.output.assetFileNames,它控制 CSS、图片等资源文件的输出路径和命名规则。

配置方案

打开项目根目录下的 astro.config.mjs,添加 vite 配置:

// astro.config.mjs
import { defineConfig } from 'astro/config';

export default defineConfig({
  site: 'https://geyuxu.com',
  // ... 其他配置
  vite: {
    build: {
      rollupOptions: {
        output: {
          // 修改资产文件命名规则,避免下划线开头
          assetFileNames: (assetInfo) => {
            const info = assetInfo.name.split('.');
            const ext = info[info.length - 1];
            const name = info.slice(0, -1).join('.');
            // 如果文件名以下划线开头,替换为 'assets-'
            const finalName = name.startsWith('_') ? name.replace(/^_/, 'assets-') : name;
            return `_astro/${finalName}.[hash].${ext}`;
          }
        }
      }
    }
  },
  // ... 其他配置如 markdown 等
});

验证

重新构建并部署:

npm run build
npm run deploy

CSS 现在从 assets-slug_.BvCO7WHQ.css 这样的路径加载,HTTP 状态码变为 200。通过以下命令确认:

curl -I https://geyuxu.com/_astro/assets-slug_.BvCO7WHQ.css

返回:

HTTP/2 200 
content-type: text/css; charset=utf-8

经验总结

平台的限制比表面工具更深。 .nojekyll 禁用的是 Jekyll 的构建步骤,并不覆盖服务器的文件服务规则。理解每一层平台究竟控制什么,比套用常规解法更重要。

从源头解决问题。 配置构建工具生成符合平台要求的产物,比在部署环境中打补丁更干净。Vite 的 assetFileNames 选项提供了完整控制,不需要改动任何平台配置。

下划线有隐含含义。 在 Jekyll、Node.js 约定以及 GitHub Pages 的文件服务规则中,以下划线开头的文件名都具有特殊或私有的含义。使用有主张的平台部署时,构建工具中的命名选择会产生实际影响。

© 2026 Yuxu Ge ·