You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在SvelteKit应用中挂载Docusaurus静态子站点

在SvelteKit中通过命名路由托管Docusaurus静态文档

可行方案:利用SvelteKit的handle钩子处理静态资源

无需额外Express服务器,SvelteKit的钩子系统可以优雅拦截/doc路径下的所有请求,直接返回Docusaurus构建后的静态文件。

步骤1:配置Docusaurus基础路径

先修改Docusaurus的docusaurus.config.js,指定构建后的资源基础路径,避免和主应用路由冲突:

module.exports = {
  baseUrl: '/doc/',
  // 其他原有配置...
};

步骤2:编写SvelteKit服务器钩子

在src/hooks.server.js中添加以下代码,拦截并处理/doc开头的请求:

import { resolve } from 'path';
import { readFileSync } from 'fs';
import { fileURLToPath } from 'url';

const __dirname = fileURLToPath(new URL('.', import.meta.url));
// 指向Docusaurus的静态构建目录
const docsBuildDir = resolve(__dirname, '../src/docs/build');

export async function handle({ event, resolve }) {
  if (event.url.pathname.startsWith('/doc')) {
    let filePath = event.url.pathname.replace('/doc', '');
    // 处理/doc根路径,返回首页index.html
    if (filePath === '') filePath = '/index.html';
    const fullPath = resolve(docsBuildDir, filePath.slice(1));

    try {
      const content = readFileSync(fullPath);
      // 根据文件后缀设置正确的Content-Type
      let contentType = 'text/html';
      if (fullPath.endsWith('.css')) contentType = 'text/css';
      if (fullPath.endsWith('.js')) contentType = 'application/javascript';
      if (fullPath.endsWith('.png') || fullPath.endsWith('.jpg')) contentType = `image/${fullPath.split('.').pop()}`;
      // 可根据需要补充其他文件类型

      return new Response(content, {
        headers: { 'Content-Type': contentType }
      });
    } catch (err) {
      return new Response('Not Found', { status: 404 });
    }
  }

  // 非/doc路径按SvelteKit原有逻辑处理
  return resolve(event);
}

步骤3:开发模式下的便捷处理

如果开发时不想频繁构建Docusaurus,可以通过代理转发请求到Docusaurus的开发服务器。修改钩子代码,添加开发环境代理逻辑:

import { createProxyMiddleware } from 'http-proxy-middleware';
import { resolve } from 'path';
import { readFileSync } from 'fs';
import { fileURLToPath } from 'url';

const __dirname = fileURLToPath(new URL('.', import.meta.url));
const docsBuildDir = resolve(__dirname, '../src/docs/build');
const isDev = process.env.NODE_ENV === 'development';
// 代理到Docusaurus开发服务器(默认端口3001,可根据实际修改)
const proxy = isDev ? createProxyMiddleware({
  target: 'http://localhost:3001',
  changeOrigin: true,
  pathRewrite: { '^/doc': '' }
}) : null;

export async function handle({ event, resolve }) {
  if (isDev && event.url.pathname.startsWith('/doc')) {
    return new Promise((resolveProxy) => {
      proxy(event.request, event.response, (err) => {
        if (err) console.error(err);
        resolveProxy(new Response(null, { status: event.response.statusCode }));
      });
    });
  }

  // 生产环境静态文件处理逻辑(同步骤2的代码)
  if (event.url.pathname.startsWith('/doc')) {
    let filePath = event.url.pathname.replace('/doc', '');
    if (filePath === '') filePath = '/index.html';
    const fullPath = resolve(docsBuildDir, filePath.slice(1));

    try {
      const content = readFileSync(fullPath);
      let contentType = 'text/html';
      if (fullPath.endsWith('.css')) contentType = 'text/css';
      if (fullPath.endsWith('.js')) contentType = 'application/javascript';
      if (fullPath.endsWith('.png') || fullPath.endsWith('.jpg')) contentType = `image/${fullPath.split('.').pop()}`;

      return new Response(content, {
        headers: { 'Content-Type': contentType }
      });
    } catch (err) {
      return new Response('Not Found', { status: 404 });
    }
  }

  return resolve(event);
}

注意需要安装依赖:npm install http-proxy-middleware --save-dev

为什么之前的方法无效?

  • 放入static目录:Docusaurus构建后的资源依赖相对路径引用,放入static后路径会混乱,且该目录设计初衷是存放独立静态资源,而非完整单页应用。
  • 别名引入index.html:仅能加载首页,但Docusaurus的客户端路由会被SvelteKit的路由系统拦截,导致文档内部跳转失效。

项目文档管理常见方式

  • 独立部署:多数项目会将Docusaurus文档单独部署到Vercel、Netlify等平台,通过子域名(如docs.your-app.com)访问,避免和主应用耦合。
  • Monorepo结构:将主应用和文档放在同一个Monorepo中,分别构建部署,便于团队协作管理。
  • 内嵌静态资源:即上述钩子方案,适合需要和主应用共享域名、权限体系的场景。

内容的提问来源于stack exchange,提问作者antoine david

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 09:47:29