如何为@emotion/cache传递nonce参数?解决Storybook中Emotion样式引发的CSP错误
解决Storybook + Preact + Emotion的CSP Nonce问题
看起来你遇到的核心问题是Emotion默认缓存没有被自定义缓存覆盖,导致部分样式标签还是用了无nonce的默认配置插入到iframe头部。结合Preact环境和Storybook的iframe隔离特性,我们可以从以下几个方向调整解决:
1. 统一Emotion依赖并适配Preact
首先建议把旧版的@emotion/core升级到最新的@emotion/react,旧版本的缓存机制与Context Provider逻辑和新版存在差异。同时,为了让@emotion/react在Preact环境正常工作,需要在Storybook的Webpack配置中添加别名:
// .storybook/main.js export default { // ...其他配置 webpackFinal: async (config) => { config.resolve.alias = { ...config.resolve.alias, 'react': 'preact/compat', 'react-dom': 'preact/compat', 'react-dom/test-utils': 'preact/test-utils', }; return config; }, };
2. 强制覆盖Emotion的默认缓存
仅用CacheProvider包裹组件可能不够——如果你的某些依赖或组件直接调用了Emotion的默认全局缓存,会绕过Context。因此我们需要直接修改默认缓存的nonce,或者替换默认缓存:
// .storybook/preview.js import { CacheProvider, defaultCache } from '@emotion/react'; import createCache from '@emotion/cache'; import { h } from 'preact'; // 使用Preact的JSX入口替代React // 方法1:直接修改默认缓存的nonce defaultCache.nonce = '你的真实Nonce值'; // 注意不能用硬编码的'nonce-id',要与Storybook的CSP配置一致 // 方法2:创建新缓存并替换全局默认(推荐,避免与其他缓存冲突) const styleCache = createCache({ key: 'preact-emotion', nonce: '你的真实Nonce值', }); // 若你的Emotion版本支持setDefaultCache(v11+),可直接设置全局默认 // import { setDefaultCache } from '@emotion/react'; // setDefaultCache(styleCache); export const decorators = [ (Story) => h(CacheProvider, { value: styleCache }, h(Story)) ];
3. 配置Storybook的CSP规则
确保Storybook的CSP允许你设置的nonce,否则即使样式标签添加了nonce,浏览器仍会拦截:
// .storybook/main.js export default { // ...其他配置 framework: { name: '@storybook/preact-webpack5', // 对应你的Storybook框架类型 options: { csp: { directives: { 'style-src': ["'self'", "'nonce-你的真实Nonce值'"], 'script-src': ["'self'", "'nonce-你的真实Nonce值'"], }, }, }, }, };
4. 验证iframe环境的Nonce一致性
Storybook的组件渲染在独立iframe中,需要确保iframe的<head>也包含对应的nonce属性,且与Emotion使用的nonce值一致。开发环境可手动检查iframe DOM;生产环境可通过preview-head.html注入nonce:
<!-- .storybook/preview-head.html --> <head nonce="你的真实Nonce值"></head>
为什么之前的CacheProvider未生效?
你之前的代码中cache-block能渲染,但样式标签未带nonce,大概率是因为部分Emotion样式通过默认全局缓存插入,没有走Context提供的自定义缓存。直接修改默认缓存或替换全局默认缓存,就能覆盖所有Emotion的样式插入逻辑。
内容的提问来源于stack exchange,提问作者RS17
相关产品推荐
相关产品推荐

