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

Monorepo中Storybook全局装饰器引发依赖错误排查

Storybook中@ngrok/ngrok依赖报错排查

技术栈

  • Vite:模块打包器与运行器
  • pnpm:包管理器,通过npx运行Storybook命令(Storybook暂不支持pnpx)
  • nx:Monorepo项目管理工具

全局装饰器实现(Preview.tsx)

import type { Preview } from "@storybook/react";
import { EtechUiProvider } from "etech-ui-utils";
import React from "react";

// Generated by Storybook
const preview: Preview = {
  parameters: {
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/i,
      },
    },
  },
}

export const decorators = [
  (Story) => (
    <EtechUiProvider configPath="./etech.config.ts" options={{ filter: "etech-ui-utils-tests" }}>
      <Story />
    </EtechUiProvider>
  )]

export default preview;

测试Story代码

import type { Meta, StoryObj } from "@storybook/react";
import Example from "../Example";
import React from "react";
import { EtechUiProvider } from "etech-ui-utils";

const meta: Meta<typeof Example> = {
  component: Example,
};

export default meta;
type Story = StoryObj<typeof Example>;

export const Primary: Story = {
  args: {
    primary: true
  }
};

测试组件代码

import React from "react";

export default function Example() {
  return <h1>Example</h1>;
}

问题描述

运行Storybook后UI出现报错,根源是Monorepo中etech-ui-utils包依赖的universal-fs包含子依赖@ngrok/ngrok,该依赖在浏览器环境中无法正常运行。

已尝试两种无效方案:

  1. 使用pnpm patch移除universal-fs中对@ngrok/ngrok的引用,但pnpm-lock.yaml中仍存在该依赖。
  2. 在Storybook的main.ts中配置Vite的optimizeDeps.exclude,将相关依赖标记为外部依赖,无效。

可能的问题点与解决方案

1. pnpm patch未正确生效

  • 确认patch流程完整:执行pnpm patch universal-fs后,修改文件必须运行pnpm patch-commit <patch临时文件夹路径>才能将补丁持久化,否则修改不会被应用。
  • 检查pnpm-lock.yaml中universal-fs条目是否包含patched字段,确认补丁已被记录。
  • 执行pnpm ls @ngrok/ngrok查看完整依赖链,确认是否有其他包间接引入了未打补丁的universal-fs版本。

2. Vite外部依赖配置未覆盖场景

optimizeDeps.exclude仅控制预构建行为,若@ngrok/ngrok被etech-ui-utils直接导入,该配置无法阻止其被打包。可尝试用resolve.alias将其指向空模块:

import type { StorybookConfig } from "@storybook/react-vite";
import { UserConfig } from "vite";
import { mergeConfig } from "vite";
import path from "path";

const config: StorybookConfig = {
  // 原有配置...
  viteFinal: (config: UserConfig) => {
    return mergeConfig(config, {
      resolve: {
        alias: {
          '@ngrok/ngrok': path.resolve(__dirname, './empty-module.js')
        }
      },
      optimizeDeps: {
        exclude: ["aws-sdk", "nock", "mock-aws-s3", "@ngrok/ngrok", "*.html"],
      }
    });
  }
};
export default config;

新建empty-module.js文件,内容为:

export default {};

3. Monorepo依赖链路问题

  • 检查etech-ui-utils的package.json,确认universal-fs是dependencies还是devDependencies。若为开发依赖但被Storybook环境加载,可调整依赖类型,或在nx项目配置中排除该依赖在Storybook构建中的加载。
  • 运行nx graph查看项目依赖关系,排查是否有其他包间接引入@ngrok/ngrok。

4. Storybook环境的Rollup配置补充

尝试在Vite配置中添加Rollup的外部依赖排除,强化阻止打包的逻辑:

viteFinal: (config: UserConfig) => {
  return mergeConfig(config, {
    build: {
      rollupOptions: {
        external: ['@ngrok/ngrok']
      }
    },
    // 其他配置...
  });
}

若@ngrok/ngrok仅用于Node.js环境,可在etech-ui-utils中添加环境判断,避免在浏览器环境加载该依赖:

// etech-ui-utils中的相关代码
if (typeof window === 'undefined') {
  // 仅在Node.js环境加载@ngrok/ngrok相关逻辑
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 18:50:18