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

GitLab Pages部署Storybook遇脚本URL错误导致CORS问题

GitLab CI托管Storybook资源路径错误导致CORS问题修复方案

背景

通过GitLab CI推送代码至任意分支时构建并托管Storybook页面,当前CI脚本如下:

image: node:16

stages:
  - setup
  - build-and-test
  - deployment
  - pages

setup:
  stage: setup
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - node_modules/
  artifacts:
    paths:
      - node_modules/
  script:
    - yarn

build:
  stage: build-and-test
  artifacts:
    paths:
      - dist/
  script:
    - yarn build

storybook:
  stage: build-and-test
  artifacts:
    expire_in: 2 weeks
    when: always
    paths:
      - storybook/
  script:
    - yarn build-storybook --output-dir storybook

deploy-storybook:
  stage: deployment
  script:
    - echo "Enjoy the day. 🥳 Every job needs a script, but this job was just created to configure an environment."
  environment:
    name: storybook/$CI_COMMIT_REF_SLUG
    url: https://<my_username>.gitlab.io/<my_project>/$CI_COMMIT_REF_SLUG/storybook/
    on_stop: remove-storybook
  only:
    - branches

remove-storybook:
  stage: deployment
  cache:
    key: 'my-storybook'
    paths:
      - public
  script:
    - rm -rf "public/$CI_COMMIT_REF_SLUG/storybook"
  when: manual
  variables:
    GIT_STRATEGY: none # needed to prevent "Couldn't find remote ref" error
  environment:
    name: storybook/$CI_COMMIT_REF_SLUG
    action: stop

pages:
  stage: pages
  cache:
    key: 'my-storybook'
    paths:
      - public
  script:
    - if [ "$CI_COMMIT_REF_NAME" = "main" ]; then
      mkdir -p public;
      touch public/index.html;
      echo "<!DOCTYPE HTML><script>window.location.href = 'https://<my_username>.gitlab.io/<my_project>/main/storybook'</script>" > public/index.html;
      fi;
    - rm -rf "public/$CI_COMMIT_REF_SLUG"
    - mkdir -p "public/$CI_COMMIT_REF_SLUG";
    - mv storybook "public/$CI_COMMIT_REF_SLUG"
  artifacts:
    paths:
      - public

错误现象

构建正常,但访问时控制台触发CORS拦截错误:

iframe.html:1 Access to script at 'https://gitlab.com/oauth/authorize?client_id=<my_client_id>&redirect_uri=https://projects.gitlab.io/auth&response_type=code&state=AFyDa1QTpsd9qXqSzdoy4w==&scope=api' (redirected from 'https://<my_username>.gitlab.io/assets/iframe.8696a5de.js') from origin 'https://<my_username>.gitlab.io' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
iframe.html:374          GET https://gitlab.com/oauth/authorize?client_id=<my_client_id>&redirect_uri=https://projects.gitlab.io/auth&response_type=code&state=AFyDa1QTpsd9qXqSzdoy4w==&scope=api net::ERR_FAILED 302

关键代码片段

iframe.html路径错误示例

<head>
  ...
  <script defer src="/node_modules/@fortawesome/fontawesome-free/js/all.min.js"></script>

  <!-- iframe.html:374 -->
  <script type="module" crossorigin src="/assets/iframe.8696a5de.js"></script>

  <link rel="stylesheet" href="/assets/iframe.0f83afa4.css">
  ...
</head>

资源路径使用根路径/assets,但正确路径应为/<project_name>/<branch>/storybook/assets。

.storybook/main.cjs配置

const { resolve } = require("path");
const { typescript: preprocessTS } = require("svelte-preprocess");
const { loadConfigFromFile, mergeConfig } = require("vite");

module.exports = {
  "stories": [
    "../src/**/*.stories.mdx",
    "../src/**/*.stories.@(js|jsx|ts|tsx|svelte)"
  ],
  "addons": [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/addon-interactions",
    "@storybook/addon-svelte-csf"
  ],
  "framework": "@storybook/svelte",
  "core": {
    "builder": "@storybook/builder-vite"
  },
  "svelteOptions": {
    "preprocess": import("../svelte.config.js").preprocess
  },
  svelteOptions: {
    preprocess: [
      preprocessTS(),
    ],
  },
  async viteFinal(config, { configType }) {
    const { config: userConfig } = await loadConfigFromFile(
      resolve(__dirname, "../vite.config.ts")
    );

    return mergeConfig(config, {
      ...userConfig,
      // manually specify plugins to avoid conflict
      plugins: []
    });
  }
}

核心问题

Storybook构建时未指定正确的基础路径,导致生成的资源URL使用根路径/,而实际托管路径是/<project_name>/<branch>/storybook/,资源请求跳转到GitLab根域名下,触发CORS拦截。

解决方案

方案1:构建时指定基础路径(推荐)

修改CI的storybook任务,在build-storybook命令中添加--base-path参数,指定相对于GitLab Pages根目录的完整路径:

storybook:
  stage: build-and-test
  artifacts:
    expire_in: 2 weeks
    when: always
    paths:
      - storybook/
  script:
    - yarn build-storybook --output-dir storybook --base-path "/<my_project>/$CI_COMMIT_REF_SLUG/storybook"

构建后所有资源路径会自动带上前缀,无需后续修改。

方案2:通过Vite配置指定base路径

在.storybook/main.cjs的viteFinal函数中设置Vite的base选项,利用GitLab CI内置变量动态生成路径:

async viteFinal(config, { configType }) {
  const { config: userConfig } = await loadConfigFromFile(
    resolve(__dirname, "../vite.config.ts")
  );

  // 动态生成基础路径,GitLab CI自动提供CI_PROJECT_NAME和CI_COMMIT_REF_SLUG变量
  const basePath = `/${process.env.CI_PROJECT_NAME}/${process.env.CI_COMMIT_REF_SLUG}/storybook/`;

  return mergeConfig(config, {
    ...userConfig,
    base: basePath,
    plugins: []
  });
}

方案3:CI脚本批量替换资源路径(兜底)

如果前两种方案无法实施,在pages任务中添加文本替换脚本,修正所有文件中的路径引用:

pages:
  stage: pages
  cache:
    key: 'my-storybook'
    paths:
      - public
  script:
    - if [ "$CI_COMMIT_REF_NAME" = "main" ]; then
      mkdir -p public;
      touch public/index.html;
      echo "<!DOCTYPE HTML><script>window.location.href = 'https://<my_username>.gitlab.io/<my_project>/main/storybook'</script>" > public/index.html;
      fi;
    - rm -rf "public/$CI_COMMIT_REF_SLUG"
    - mkdir -p "public/$CI_COMMIT_REF_SLUG";
    # 替换资源路径前缀
    - find storybook -type f \( -name "*.html" -o -name "*.js" -o -name "*.css" \) -exec sed -i "s|/assets|/<my_project>/$CI_COMMIT_REF_SLUG/storybook/assets|g" {} \;
    - find storybook -type f \( -name "*.html" -o -name "*.js" -o -name "*.css" \) -exec sed -i "s|/node_modules|/<my_project>/$CI_COMMIT_REF_SLUG/storybook/node_modules|g" {} \;
    - mv storybook "public/$CI_COMMIT_REF_SLUG"
  artifacts:
    paths:
      - public

为什么直接修改CI脚本调整根URL不可行?

Storybook构建过程中会将资源路径硬编码到生成的HTML、JS和CSS文件中,CI脚本仅移动文件位置,无法修改文件内部的路径引用。必须在构建阶段指定正确的基础路径,或者事后批量替换文件内容才能修正路径。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 20:30:32