Storybook: 单个故事正在吸引其他所有故事的样式表吗?

创建于 2017-03-21  ·  67评论  ·  资料来源: storybookjs/storybook

你好

我试图弄清楚为什么我遇到这个特殊问题。 我正在动态加载这样的故事:

function loadStories() {
    const req = require.context('../components', true, /story.js$/);
    req.keys().forEach(filename => req(filename));
}
configure(loadStories, module);

并且每个story.js文件都有一个各自导入的sass或css文件(出于story.js将要导入的组件外部故事的特定样式的目的,它显示:

import './story.sass';

我现在大约有4个故事,这是每个故事iframe的来源...加载每个样式表:

screen shot 2017-03-21 at 9 56 22 am

这是正常行为吗?

-

演示

https://github.com/moimikey/729-single-stories-pulling-all-stylesheets

bug todo

最有用的评论

在故事中打上阴影,可以立即解决此问题,而无需

所有67条评论

另外,webpack发出了所有这些故事,所以我想知道是否是我配置webpack的方式?

screen shot 2017-03-21 at 11 27 10 am

我也尝试使用一个装饰器,由于我至少能够隔离故事中的其他样式表,所以最终导致了一半破损,但是当我遍历其他样式表时,除非我进行了认真的刷新,否则这些样式将被破坏。

.addDecorator((getStory) => {
  require('./story.sass');
  return getStory();
})

@arunoda @mnmtanish

有趣!您是否有一个可以显示此信息的仓库?

@ndelangen将很快成为一名

仍在尝试寻找时间进行检查。

谢谢; D这很奇怪。 我看了一下,但我不确定从哪里开始。

因此,我认为正在发生的事情是,所有webpack样式加载器拾取了所有CSS文件,并将它们注入了头部。 是否使用它们。

但是如何解决?

我为CSS完成的工作是使用CSS模块。 并将生成的类名导入到我的JS中。 即使所有CSS一起注入头部,也没关系,因为可以保证它是唯一的类/选择器。

它并不能真正解决您遇到的确切问题。 但是我认为这是样式加载器的预期行为。

这是真的。 我(和我的公司)正在使用css进行搜索,但是我们正在进行大量的代码重新开发,因此我们共享了样式,因此将styleNameclassName组合在一起。 因此最终影响故事书的是那些“外部” css文件。

今晚喝完啤酒后,我将在今晚再次研究故事书的代码,并弄清楚如何解决该问题,实现明智的选择。

@moimikey针对您的问题,我想您必须跳过样式加载器,并使用装饰器手动加载css文件。 大概是这样的:

.addDecorator(getStory => (
  <div>
    <link ... />
    {getStory()}
  </div>
))

哇....我从未想过...我会尝试的。

but,然后再次使用sass ... x_x。 我什至尝试了内联需求。 但是我运气不好。 但这对于直接使用CSS是一个极好的解决方案:)

所以@mnmtanish。 感谢您的指导。 我已经用您的灵感解决了我的问题:

.addDecorator((getStory) => {
  require('./story.sass');
  return getStory();
})

嗯,所以现在唯一的问题是,当您从一个故事导航到另一个故事时,它会堆积样式:(

也许可以将样式加载器配置为将其插入到HEAD以外的其他位置,以便将其删除。 我还没有这样做,所以不确定是否可能。 检查这些

反应故事书的职责不是完全隔离地加载组件,从而只运行与当前所选故事相关的JavaScript / CSS吗?

这与https://github.com/storybooks/react-storybook/issues/686有关

@ConneXNL是的。 好点子。 这是真的...; X

@mnmtanish我的下一个响应当然会导致另一个问题, insertAt可能有用,但是它仅在style-loader的最新版本中可用,因为它使用了Storybook,所以无法使用[email protected] 。 故事书仍在使用0.x 。 我们可以使用的最新版本是[email protected] :(...

@moimikey也许您可以尝试使用alpha版本中最后提到的方法?

切换故事时创建新的iframe元素不是更好/更安全吗?

这样既安全又不利于性能。

新的iframe必须解析javascript,解析CSS,连接到postmessage-channel,重新连接到websocket,以及可能更多的东西。

也许删除故事切换上的<style>元素足以解决此问题?

当然,没有全局样式,并且所有内容都已正确命名,这不是一个直接的问题。 我猜是如意算盘。 😃

如果有人可以证明上述说法是错误的,或者可以证明没有负面后果,那么我无不为之!

我今天做了一些测试。 装饰器模式效果很好,因此仅在切换到故事后才注入样式。 但是,我有一个相同的问题,即切换故事时不删除样式。

我试过在装饰器中删除样式,但似乎所需的样式仅应用了一次。 是否可以重新触发require()? 我尝试使用singleton:false,但这不能解决问题。

我什至不愿提出这个建议,但您可以尝试破坏Webpack缓存:
https://webpack.github.io/docs/api-in-modules.html#advanced

这是webpack 1文档,但可能仍然有效。

想法:您可以编写一个装饰器,以在切换故事时删除所有<style>...</style> 。 清理与当前故事无关的样式。

我快到了在webpack配置中,我使用
'style-loader/useable' instead of 'style-loader',

这会添加一个供您使用的API。 .use()添加样式,unuse()删除样式。 在我的故事文件中,我使用如下装饰器:

.addDecorator((c) => <ReactStylesheet stylesheets={[require('./stories.scss')]}>{ c() }</ReactStylesheet> )

使用以下React组件添加和删除样式。

从'react'导入*作为React;

export class ReactStylesheet extends React.Component{

    componentWillUnmount(){
        let stylesheets = Array.isArray(this.props.stylesheets) ? this.props.stylesheets : [this.props.stylesheets];
        stylesheets.forEach((stylesheet) => {
            console.log("Unmounting....");
            stylesheet.unuse();
        });

    }

    componentDidMount(){
         let stylesheets = Array.isArray(this.props.stylesheets) ? this.props.stylesheets : [this.props.stylesheets];
        stylesheets.forEach((stylesheet) => {
            console.log("Mounting....");
            stylesheet.use();
        });
    }

    render(){
        return this.props.children;
    }
}

正确更改样式表会热重新加载样式。 切换到另一个故事,将调用unuse()并清理样式表。 但是,该方法在重新添加样式时会中断,因为它会在样式表的非人力资源更新版本中投放广告。 之后进行任何更改也会引发此错误:

Uncaught (in promise) TypeError: Cannot read property 'refs' of undefined
    at update (webpack:///./~/style-loader/addStyles.js?:63:4)
    at eval (webpack:///./src/Component/stories.scss?:32:4)
    at Object.hotApply [as apply] (http://dev.test:6006/static/preview.bundle.js:499:14)
    at cb (webpack:///(webpack)-hot-middleware/process-update.js?:52:36)
    at eval (webpack:///(webpack)-hot-middleware/process-update.js?:68:13)
    at <anonymous>

我不确定如何更新require语句以指向最新的HRM版本。

出色的调查工作! 我之前四处寻找类似的东西,但找不到。

我们可以在这方面为@ConneXNL提供任何帮助吗?

解决方案正在接近。 stylesheet.use()unuse的想法对我来说很陌生,但这似乎步入了正确的轨道。

这对于沙盒故事书https://github.com/Wildhoney/ReactShadow来说也是另一件有趣的事情

嗨,大家好! 似乎最近在这个问题上没有发生太多事情。 如果仍有问题,意见或错误,请随时继续讨论。 不幸的是,我们没有时间解决每个问题。 我们随时欢迎捐款,因此,如果您想提供帮助,请向我们发送请求请求。 不活跃的问题将在60天后关闭。 谢谢!

@ConneXNL可以解决此问题,您认为您可以在这方面帮助我们改进文档吗?

如果找不到合适的位置,只需以markdown格式将其朋克一下。 我会把它放进去的。

🙇

嗨,大家好! 似乎最近在这个问题上没有发生太多事情。 如果仍有问题,意见或错误,请随时继续讨论。 不幸的是,我们没有时间解决每个问题。 我们随时欢迎捐款,因此,如果您想提供帮助,请向我们发送请求请求。 不活跃的问题将在60天后关闭。 谢谢!

嘿,又是我! 我将解决此问题,以帮助我们的维护人员专注于当前的开发路线图。 如果仍然提到上述问题,请打开一张新票并提及这张旧票。 干杯,感谢您使用Storybook!

同样的问题,故事书不会隔离每个故事,因此无法用于任何视觉测试/验收测试。

在故事中打上阴影,可以立即解决此问题,而无需

@bennypowers有趣! 您将获得有关如何实现该目标的代码示例吗? 🙇

@shilman可能也会很有趣。

你好我也遇到这个问题
这是固定的还是有任何解决方法?

@ndelangen

达到满意度的最快途径可能是@moimikey建议使用ReactShadow

采取的策略可能是将根包装在ReactShadow组件中,然后使用adoptedStyleSheets引入样式(对于不支持的浏览器,则使用<style>元素)

https://github.com/storybookjs/storybook/blob/ba74d889fcfd87849a6ae9369f5e4176e8149d33/lib/core/src/client/preview/start.js#L253

请重新打开,此问题使按故事添加自定义样式变得异常困难。 我有完全独立的MDX故事,这些故事为其示例实现了自定义样式,并且在全球范围内包括每个故事的所有样式都使该用例变得站不住脚。

编辑:谢谢!!!

我希望在2020年3月21日之前解决此问题。

@moimikey是否有兴趣进行此操作? 确保在特定日期之前完成的最佳方法... ...

IMO我们应该添加参数或插件来处理此功能,而不是仅为样式表添加特殊功能。 这会导致样式表和脚本之间的行为不一致。 但是也许现在正是考虑应该如何“隔离”的好时机?

我为插件方法编写了一个快速PoC,谁知道这是可行的。
https://github.com/pocka/storybook-addon-css

@pocka您太棒了! 💯

yazzzzz。 欢呼@pocka

值得注意的是,如果由于mdx-js / mdx#894而使用MDX故事, @ pocka的解决方案将不起作用。

编辑:我不好,它的确可以! 您需要具有样式加载器1.x +,然后执行以下操作:

--- a/components/grid/GridChild.stories.mdx
+++ b/components/grid/GridChild.stories.mdx
@@ -1,7 +1,9 @@
 import { Meta, Story, Preview } from '@storybook/addon-docs/blocks';
 import { GridContainer, GridRow, GridChild } from './';
 import '../../shared/critical-path.scss';
-import 'o-grid/demos/src/scss/_demos.scss';
+import demoStylesModule from '!!style-loader?injectType=lazyStyleTag!css-loader!sass-loader!o-grid/demos/src/scss/_demos.scss?story';
+
+export const demoStyles = Promise.resolve(demoStylesModule);

 <Meta title="Core|Grid/GridChild" component={GridChild} />

@@ -37,7 +39,12 @@ You supply it a `colspan` prop in one of the following formats:
     ```

 <Preview>
-  <Story name="Default unresponsive columns">
+  <Story
+    name="Default unresponsive columns"
+    parameters={{
+      styles: [demoStyles],
+    }}
+  >
     <GridContainer>
       <GridRow>
         <GridChild colspan="1">

@aendrew
感谢您指出,我完全忘记了MDX:no_mouth:
我更新了PoC并添加了MDX示例

与文件范围界定方法(每个文件样式)相比,使用插件方法(每个故事样式),“文档”标签将获取每个故事的所有样式表。 在我的示例中,“ foo”和“ baz”故事导入foo.css而“ bar”故事导入bar.css ,然后“文档”标签同时获得foo.cssbar.css 。 我认为这是不可避免的,我不知道这是否可以接受。

@pocka我认为该方法可能与https://github.com/storybookjs/storybook/tree/next/addons/cssresources WDYT很好地配合?

@ndelangen
啊,是的!

foo.story = {
  parameters: {
    cssresources: [
      {
        id: 'foo',
        code: `<style>${require('!to-string-loader!css-loader!./foo.css')}</style>`,
        picked: true
      }
    ]
  }
}

一个需要关注的问题:如果用户导入非常大的样式表,则“ CSS资源”选项卡将变得凌乱。

@pocka对,我认为该部门的cssresources插件可以大大改善。 你想接受吗?

@ndelangen
是:笑脸:

顺便说一句,您如何看待让用户编写raw-webpack-query? (例如!to-string-loader!... )我想如果要摆脱这种情况,我们需要在插件代码中使用很多黑魔法...

我认为默认情况下我们支持babel-macros,因此用户是否也可以使用macro-preval来将文件内容注入捆绑中?

我不知道,我会尽快查看!

嗨,我遇到了同样的问题。

对于遇到问题的任何人,请尝试此解决方法。 (尽管它需要一点点的webpack知识)。


@ndelangen我看了一下宏,但是它启用的是“从文件系统加载CSS文件”,对吗? 我认为许多用户想要使用PostCSS导入SASS,Less,Stylus,CSS文件等,因此这种方法无法满足需求。 我当前的想法是CSSResource插件,添加了一条规则,该规则使用to-string-loader (或file-loader )导入CSS文件,以便用户可以导入CSS文件,然后将其用于插件。

// adding a rule like this
{
  test: /\.css$/,
  resourceQuery: /cssresources/,
  use: ['to-string-loader', 'css-loader', 'postcss-loader']
}

对于预处理程序,还需要自定义testuse 。 可以为样式文件选择一个规则,然后用oneOf对其进行修改,但这会非常复杂...

你怎么看?

@pocka是的,听起来像是一个有趣的概念!

嗨,想知道这还在继续吗? 我也遇到了这个问题,我知道可以解决此问题,但是想知道是否可以在不久的将来提供修复程序。

嗨,您能提供Vue Story的变通方法示例吗?

据我所知,该解决方法仍然会导致在初始视图后堆叠样式表,至少在使用Docs加载项的情况下。 😕

毫不客气,我发现import './Button.css'内的Button.jsx ,只有被故事中的文件用在Button.jsx已导入。 按@pocka提供的方式,每个故事的样式对我而言并不像确保没有一个本身不会导入Button组件不受(直接或间接)导入的影响那样重要。 Button.css所有CSS规则。 (这里所关心的是要确保OtherWidget.css不缺少一些规则,这些规则无意中以Button.css结尾,也许它们在重构中被忽视了,或者丢失了。这是因为OtherWidget的故事获得了整个应用程序的所有静态导入的CSS,因此OtherWidget在Storybook中看起来仍然不错。)

我想我要做的是更改所有CSS加载器以注入lazyStyleTag ,然后使用webpack API生成一个新模块,该模块将CSS模块按最终需要它们的故事文件进行分组,并听取故事更改事件以打开和关闭相应的模块。
是否已经考虑并放弃了这种方法,或者您现在看到任何问题? 我认为我可以在Storybook插件中完成所有操作,但如果将它作为Story Story的核心功能集成进来,则可能会更干净。

如果您想要强壮的样式封装,浏览器将附带它。 冒着暴露我自己的无知的风险,我仍然不确定为什么要使用所有用户级JavaScript(及其相关的复杂性成本)来完成内置的和随时可用的东西。

为什么不只将每个故事的DOM渲染成具有这样的影子根

customElements.define('encapsulated-story', class EncapsulatedStory extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
  }

  /* not sure why we'd need this getter, but let's say */
  get storyHTML() {
    return this.shadowRoot.innerHTML;
  }

  set storyHTML(string) {
    this.shadowRoot.innerHTML = storyHTML;
  }
});

每当故事改变

encapsulatedStory.storyHTML = theStoryDOMStringWithAllStyleTags;

并做了? 在这里, theStoryDOMStringWithAllStyleTags只是故事HTML的串联,所有相关样式都隐藏为内联<style>标签。 Story可以正常使用:host选择器来设置宿主元素的样式。

这是一个最低限度的起点,可以稍后在其中添加一些库代码来构建,但是至少它将实现强样式封装的目标,而无需所有这些新提议的API。

但是,它如何与webpack一起使用? Webpack将所有内容打包到一个JavaScript包中,而不是DOM字符串; 以及当前配置webpack的方式,它将所有故事打包为一个捆绑包。 我认为,在(热重新加载)JavaScript的情况下,将阴影样式直接插入文档的头部时,影子根无济于事。 您需要以一种或另一种方式进行一些繁琐的Webpack配置,以进行更改。

使用影子DOM完全隔离每个故事还意味着将许多故事共享的样式标签复制到每个故事中。 使用webpack捆绑的共享样式会更高效。 也许不足以产生巨大的变化,但可能足以抵消使用影子DOM而不是使用lazyStyleTag (如果有的话)的好处(我认为这是影子根唯一会带来的复杂性)拯救你)。

我也有兴趣迟早查看此修复程序。

这样既安全又不利于性能。

新的iframe必须解析javascript,解析CSS,连接到postmessage-channel,重新连接到websocket,以及可能更多的东西。

@ndelangen很抱歉在2017年引用您的

对我而言,收益超过成本,因为我非常希望每个故事都使用新鲜的iframe。 对于这样的奢侈,我可以忍受长达600毫秒的延迟。

(我的用例是,我试图在故事书中渲染一些旧的angularjs组件,而我们只说这些组件不是很纯。它们是非常有状态的;它们有副作用,并且使用了也非常有状态。事情以意想不到的方式破裂。)

API表面的一种想法是在.storybook/manager.js配置故事书。

addons.setConfig({
  refreshBetweenStories: true,
})

如果您以正确的方式倾斜头部,则可以将其视为UI设置。

对于未启用此标志的人员,将没有运行时成本,对于确实启用此标志的人员,他们确实需要它,因此任何此类延迟都是可以容忍的。

如果您想解决此问题,请在问题描述中添加👍以表示赞成。 我们用它来帮助确定优先级!

.addDecorator((getStory)=> {
require('./ story.sass');
返回getStory();
})

嗨!!!
我可以把它放在哪里?

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

ZigGreen picture ZigGreen  ·  3评论

arunoda picture arunoda  ·  3评论

tlrobinson picture tlrobinson  ·  3评论

zvictor picture zvictor  ·  3评论

MrOrz picture MrOrz  ·  3评论