尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Gatsby 路径前缀(pathPrefix)完整指南:从 gatsby-config 配置到构建、本地预览与链接处理

Gatsby 路径前缀(pathPrefix)完整指南:从 gatsby-config 配置到构建、本地预览与链接处理 Gatsby 路径前缀pathPrefix完整指南从 gatsby-config 配置到构建、本地预览与链接处理【免费下载链接】gatsbyReact-based framework with performance, scalability, and security built in.项目地址: https://gitcode.com/gh_mirrors/ga/gatsby导读很多站点并非部署在域名的根路径/下而是位于某个子目录例如博客部署在example.com/blog/或站点托管在 GitHub Pages 的username.github.io/my-gatsby-site/。此时页面内的所有链接/my-sweet-blog-post/都需要被改写为带前缀的形式/blog/my-sweet-blog-postJavaScript、CSS、图片等静态资源引用也必须同步加上前缀站点才能在子目录下正常工作。本指南基于 Gatsby 官方文档 path-prefix.md 展开结合当前仓库中gatsby-link、webpack.config.js、serve.ts等源码实现完整讲解如何通过pathPrefix配置、--prefix-paths构建标志、gatsby serve本地验证以及Link/navigate/withPrefix等 API 优雅地实现子目录部署并介绍它与assetPrefix的协同方式。读完本文你将能独立完成一个带路径前缀的 Gatsby 站点的配置、构建、预览与迁移全过程。什么是路径前缀为什么需要它许多应用并不托管在域名的根路径/上。常见的场景包括博客站点部署在example.com/blog/所有页面路径都应以/blog开头GitHub Pages 项目页托管在example.github.io/my-gatsby-site/仓库名即为路径前缀同一域名下多个应用共存的子目录部署。在这种场景下站点内每个内部链接都必须加上前缀链接/my-sweet-blog-post/应被改写为/blog/my-sweet-blog-post。与此同时JavaScript、CSS、图片及其他静态资源的引用也需要同样的前缀否则浏览器在子目录下请求资源时会 404站点功能将无法正常运行。Gatsby 的路径前缀特性解决的正是在非根路径托管下页面链接与静态资源引用同步改写的问题。开启该特性是两步式流程先在gatsby-config中声明pathPrefix再在构建/预览时显式传入--prefix-paths标志或PREFIX_PATHS环境变量。从源码结构看pathPrefix属于 gatsby-config.js 顶层配置项 之一完整的前置要求是先有一个可运行的 Gatsby 项目参见 快速开始。第一步在 gatsby-config 中添加 pathPrefix首先在项目根目录的gatsby-config.js中声明pathPrefix值。例如博客托管在/blog子目录module.exports { pathPrefix: /blog, }配置要点pathPrefix必须以/开头如/blog、/prefix这是约定俗成的写法它只是一个声明仅此配置并不会生效——还需要在构建时显式开启前缀处理见下一步仓库中的官方示例 examples/using-path-prefix/gatsby-config.js 即采用同样的写法module.exports { pathPrefix: /prefix, }该示例站点还配套了 examples/using-path-prefix/src/pages/index.js、a.js、b.js、c.js四个页面其中首页通过Link to/a/等组件链接到各子页面正是验证路径前缀行为的完整测试样例。第二步使用 --prefix-paths 标志构建在gatsby-config声明pathPrefix之后还需要用带--prefix-paths标志或PREFIX_PATHS环境变量的方式构建应用gatsby build --prefix-paths等价的环境变量方式PREFIX_PATHStrue gatsby build如果不传该标志Gatsby 会直接忽略pathPrefix按站点托管在根域名来构建——所有资源与链接都不会带前缀。这一点在 asset-prefix.md 中也有明确表述If this flag or env variable is not specified, the build will ignore this option。从源码层面看--prefix-paths标志最终被解析为程序参数program.prefixPaths其类型定义见 packages/gatsby/src/commands/types.ts属于IProgram的可选布尔字段export interface IProgram { ... prefixPaths?: boolean ... }前缀如何注入构建产物真正决定资源引用如何改写的核心逻辑位于 packages/gatsby/src/utils/get-public-path.tsexport const getPublicPath ({ assetPrefix, pathPrefix, prefixPaths, }: { assetPrefix?: string pathPrefix?: string prefixPaths?: boolean }): string { if (prefixPaths (assetPrefix || pathPrefix)) { const normalized [assetPrefix, pathPrefix] .filter((part): part is string (part ? part.length 0 : false)) .map(part trimSlashes(part)) .join(/) return isURL(normalized) ? normalized : /${normalized} } return }可以看到getPublicPath做了两件事串联assetPrefix与pathPrefix都去掉首尾斜杠后用/连接以及判断拼接结果是否为完整 URLhttp://、https://、//开头则原样返回。这一行为由单元测试 packages/gatsby/src/utils/tests/get-public-path.ts 覆盖包括返回 assetPrefix返回 pathPrefix连接两者处理相对 assetPrefix处理 CDN 型 URL assetPrefix处理双斜杠处理尾部斜杠等场景。随后在 packages/gatsby/src/utils/webpack.config.js 中webpack 配置从 Redux store 中读取assetPrefix与pathPrefix并调用getPublicPath计算构建公共路径const { assetPrefix, pathPrefix, trailingSlash } store.getState().config const publicPath getPublicPath({ assetPrefix, pathPrefix, ...program })同一文件中还向编译产物注入两个全局常量webpack.config.js__BASE_PATH__: JSON.stringify(program.prefixPaths ? pathPrefix : ), __PATH_PREFIX__: JSON.stringify(program.prefixPaths ? publicPath : ),__BASE_PATH__等于配置中的原始pathPrefix如/blog__PATH_PREFIX__等于getPublicPath的计算结果在同时使用assetPrefix时它是assetPrefix/pathPrefix的组合值。这两个全局常量正是运行时Link、withPrefix等 API 自动加前缀的数据来源。若未传--prefix-paths两者均为空字符串前缀逻辑自然失效——这与文档所述Gatsby 会忽略你的 pathPrefix完全吻合。第三步用 gatsby serve 本地验证构建完成后可以使用gatsby serve在本地验证带前缀的构建产物。服务时同样需要传--prefix-paths标志gatsby serve --prefix-paths与build一致如果不传该标志Gatsby 会忽略pathPrefix本地预览将无法正确模拟子目录部署。从源码看gatsby serve的实现在 packages/gatsby/src/commands/serve.ts 中。它从配置模块读取pathPrefix与trailingSlash并根据prefixPaths是否开启来决定挂载前缀const { pathPrefix: configPathPrefix, trailingSlash } config || {} const pathPrefix prefixPaths configPathPrefix ? configPathPrefix : /随后通过app.use(pathPrefix, router)将整个静态资源路由挂载到带前缀的路径上serve.ts。也就是说传了--prefix-paths时localhost:9000/blog/才能正确访问站点否则资源仍挂在根路径。官方示例 examples/using-path-prefix/README.md 给出了完整的本地验证流程gatsby build --prefix-paths cd public mkdir prefix mv * prefix # This will cause an error but you can ignore it cd .. gatsby serve # Open the served site at localhost:9000/prefix/即将public目录下所有构建产物移入prefix子目录以模拟子目录托管再通过gatsby serve访问localhost:9000/prefix/。注意在真实托管平台如 GitHub Pages、Nginx 等上部署时无需手动搬移文件平台本身就会把站点挂载在子目录下——上面的mkdir/mv只是为了本地模拟。对于 GitHub Pages 场景how-gatsby-works-with-github-pages.md 给出了与本文完全一致的组合仓库站点username.github.io/reponame/需要pathPrefix: /reponame加--prefix-paths构建并用gh-pages -d public发布而自定义域名或username.github.io形式的用户页不要添加pathPrefix否则会破坏站内导航。站内链接处理Link、navigate 与 withPrefix路径前缀最大的便利在于你不需要在自己的代码里硬编码前缀。Gatsby 提供了一系列开箱即用的 API 自动完成前缀拼接。Link 组件自动加前缀Link组件内置了路径前缀处理能力。假设你想链接到/page-2而实际链接将是带前缀的/blog/page-2——使用Link时无需硬编码前缀路径会自动被加上gatsby-config.js中声明的pathPrefix值。如果日后你迁移到不使用路径前缀的部署方式这些链接依然无缝工作。import React from react import { Link } from gatsby import Layout from ../components/layout function Index() { return ( Layout {/* highlight-next-line */} Link topage-2Page 2/Link /Layout ) }navigate 动态导航编程式/动态导航同样支持前缀。Gatsby 暴露的navigate辅助函数也会自动处理路径前缀import React from react import { navigate } from gatsby import Layout from ../components/layout export default function Index() { return ( Layout {/* Note: this is an intentionally contrived example, but you get the idea! */} {/* highlight-next-line */} button onClick{() navigate(/page-2)} Go to page 2, dynamically /button /Layout ) }源码实现前缀从何而来Link与navigate的前缀处理统一收敛在 packages/gatsby-link/src 中。Link组件渲染时调用rewriteLinkPath将to改写为带前缀的路径packages/gatsby-link/src/index.jsnavigate同样先改写路径再交给window.___navigateindex.js。前缀取值来自 packages/gatsby-link/src/prefix-helpers.jsexport const getGlobalBasePrefix () process.env.NODE_ENV ! production ? typeof __BASE_PATH__ ! undefined ? __BASE_PATH__ : undefined : __BASE_PATH__ export const getGlobalPathPrefix () process.env.NODE_ENV ! production ? typeof __PATH_PREFIX__ ! undefined ? __PATH_PREFIX__ : undefined : __PATH_PREFIX__ export function withPrefix(path, prefix getGlobalBasePrefix()) { if (!isLocalLink(path)) { return path } if (path.startsWith(./) || path.startsWith(../)) { return path } const base prefix ?? getGlobalPathPrefix() ?? / return ${base?.endsWith(/) ? base.slice(0, -1) : base}${ path.startsWith(/) ? path : /${path} } }要点非本地链接外部 URL与相对链接./、../开头不会被改写优先使用__BASE_PATH__即配置中的pathPrefix其次回退到__PATH_PREFIX__可能含assetPrefix组合最后回退到/拼接时正确处理首尾斜杠避免出现双斜杠。手动路径用 withPrefix对于你手动拼接的路径名例如判断当前是否首页、构造资源 URL 等有专门的辅助函数withPrefix它会在生产环境为路径加上前缀而在开发环境不加开发模式下路径本身无需前缀import { withPrefix } from gatsby const IndexLayout ({ children, location }) { const isHomepage location.pathname withPrefix(/) return ( div h1Welcome {isHomepage ? home : aboard}!/h1 {children} /div ) }withPrefix的实现同样位于 packages/gatsby-link/src/prefix-helpers.js其行为被单元测试覆盖于 packages/gatsby-link/src/tests/index.js当设置了global.__PATH_PREFIX__时withPrefix(to)返回${__PATH_PREFIX__}${to}。withPrefix还可与getGlobalPathPrefix()结合衍生出withAssetPrefix见 packages/gatsby-link/src/index.js用于为资源路径加前缀。与其他特性协同assetPrefix 与 basePath配合 assetPrefix 使用assetPrefix可以视为与pathPrefix半相关的特性它允许将非 HTML 资源图片、JavaScript 等托管到独立的域名例如 CDN。两者可以无缝协同用--prefix-paths构建站点就能实现核心功能位于路径前缀下静态资源托管在 CDN的部署形态。关键行为如果使用assetPrefix你的pathPrefix会变为assetPrefix/pathPrefix。这一点正是 get-public-path.ts 中join(/)拼接逻辑的体现也是__PATH_PREFIX__组合值与__BASE_PATH__原始pathPrefix分开存在的原因。需要原始 pathPrefix 时使用 basePath如果你在 Node API 钩子如onPostBuild中需要访问与gatsby-config中一致的、未经assetPrefix组合的pathPrefix请使用 basePath 参数exports.onPostBuild ({ reporter, basePath, pathPrefix }) { reporter.info( Site was built with basePath: ${basePath} pathPrefix: ${pathPrefix} ) }补充createRedirect 也会自动加前缀路径前缀不仅作用于链接与资源还作用于重定向。在 packages/gatsby/src/redux/actions/public.js 中createRedirect的fromPath与toPath会在store.getState().program.prefixPaths为真时自动调用maybeAddPathPrefix加上config.pathPrefixlet pathPrefix if (store.getState().program.prefixPaths) { pathPrefix store.getState().config.pathPrefix }其中maybeAddPathPrefixpublic.js会跳过已有协议或//开头的绝对链接只为本地路径补前缀const maybeAddPathPrefix (path, pathPrefix) { const parsed url.parse(path) const isRelativeProtocol path.startsWith(//) return ${ parsed.protocol ! null || isRelativeProtocol ? : pathPrefix }${path} }这意味着使用createRedirect时同样无需手动书写前缀Gatsby 会依据prefixPaths开关自动处理。完整操作流程回顾声明前缀在 gatsby-config.js 中添加pathPrefix: /blog以/开头带标志构建运行gatsby build --prefix-paths或PREFIX_PATHStrue gatsby build缺省时前缀被忽略本地验证运行gatsby serve --prefix-paths可结合官方示例 examples/using-path-prefix/README.md 的mkdir/mv流程模拟子目录托管站内导航统一使用Link、navigate手动拼接路径时使用withPrefix不要硬编码前缀上线部署将public产物部署到子目录如 GitHub Pages 仓库站点username.github.io/reponame/平台负责把站点挂在对应路径下。前提与限制说明以上行为均以当前仓库Gatsby 5.x 时代代码的实现为准pathPrefix仅在build/serve传入--prefix-paths时生效自定义域名部署站点在根路径时不要设置pathPrefix否则会导致导航与资源路径错乱本地开发gatsby develop通常不需要前缀withPrefix在开发环境也不会加前缀原因在于开发服务器直接以根路径服务无需模拟子目录。通过这套机制你可以放心地把 Gatsby 站点部署到任意子目录且日后即使迁移回根路径托管只需移除配置并重新构建即可所有通过官方 API 书写的链接无需任何改动。【免费下载链接】gatsbyReact-based framework with performance, scalability, and security built in.项目地址: https://gitcode.com/gh_mirrors/ga/gatsby创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表