Привет,
Я пытаюсь понять, почему у меня именно эта проблема. Я динамически загружаю такие истории:
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 ... загрузка каждой таблицы стилей:
Это нормальное поведение ...?
-
демо
https://github.com/moimikey/729-single-stories-pulling-all-stylesheets
Кроме того, веб-пакет излучает все эти истории, поэтому мне интересно, как я настроил веб-пакет?
Я также попытался использовать декоратор, и это оказалось наполовину сломанным, поскольку я смог хотя бы изолировать дополнительную таблицу стилей для истории, но по мере того, как я проходил через другие, эти стили ломались, если я не выполнял жесткое обновление.
.addDecorator((getStory) => {
require('./story.sass');
return getStory();
})
@arunoda @mnmtanish
Интересно! У вас есть репо, которое это демонстрирует?
@ndelangen скоро сделает его
Все еще пытаюсь найти время, чтобы это проверить ...
спасибо; D это странно. Я посмотрел, но не знаю, с чего начать.
Итак, я думаю, что все файлы CSS подхватываются загрузчиком стилей webpack и просто вводятся в голову. используются они или нет.
Но как исправить?
Для своего CSS я использовал CSS-модули. и импортировать сгенерированные имена классов в мой JS. Даже если весь CSS вводится вместе в голову, это не имеет значения, потому что это гарантированно будут уникальные классы / селекторы.
На самом деле это не решает точную проблему, которая у вас есть. Но я думаю, что это предполагаемое поведение загрузчика стилей.
это правда. Я (и моя компания) изучают css, но мы делаем огромную переработку кода, поэтому у нас есть общие стили, то есть комбинация styleName
и className
. Итак, что в конечном итоге влияет на сборник рассказов, так это «посторонние» файлы css.
Я снова загляну в код сборника рассказов сегодня вечером, после того как выпью пива, и выясню, как, возможно, решить эту проблему с точки зрения реализации.
@moimikey для вашей проблемы, я думаю, вам нужно пропустить загрузчик стилей и загрузить файлы css вручную с помощью декоратора. Возможно, что-то вроде этого:
.addDecorator(getStory => (
<div>
<link ... />
{getStory()}
</div>
))
Вау .... это никогда не приходило мне в голову ... Я попробую.
ick, но опять же, используя sass ... x_x. я даже пробовал inline require. но мне не повезло. это было бы отличным решением для прямого css :)
так что @mnmtanish. спасибо за ваше руководство. Я решил свою проблему с вашим вдохновением:
.addDecorator((getStory) => {
require('./story.sass');
return getStory();
})
ммм, так что единственная проблема сейчас в том, что когда вы переходите от истории к истории, стили складываются :(
Возможно, загрузчик стилей можно настроить так, чтобы он вставлял его куда-нибудь, кроме HEAD, чтобы его можно было удалить. Я этого не делал, поэтому не уверен, возможно ли это. Проверьте это .
Разве в обязанности React Storybook входит загрузка компонента в полной изоляции и, следовательно, запуск только JavaScript / CSS, связанных с текущей выбранной историей?
Связано ли это с https://github.com/storybooks/react-storybook/issues/686?
@ConneXNL да. хорошая точка зрения. это правда ...; X
@mnmtanish мой следующий ответ, конечно же, приводит к другой проблеме, insertAt
может быть полезным, но он доступен только в последней версии style-loader
, который нельзя использовать с сборником рассказов, потому что он использует [email protected]
. Сборник рассказов все еще использует 0.x
. последняя возможная версия, которую мы можем использовать, - это [email protected]
: (...
Привет, @moimikey, может, ты попробуешь последний подход, упомянутый в альфа-версии?
Разве не лучше / безопаснее создать новый элемент iframe при переключении историй?
Это было бы безопасно, а также плохо для производительности.
Новый iframe должен будет анализировать javascript, анализировать CSS, подключаться к каналу postmessage, повторно подключаться к веб-сокету и, возможно, многое другое.
Может быть, для решения этой проблемы достаточно удаления элементов <style>
при переключении истории?
Конечно, нет глобальных стилей и все правильно распределено по именам, это не будет проблемой. Принятие желаемого за действительное, я думаю. 😃
Если кто-то сможет доказать ложность приведенных выше утверждений или продемонстрировать отсутствие негативных последствий, я все слышу!
Я сделал несколько тестов сегодня. Шаблон декоратора работал хорошо, поэтому стили вводятся только после того, как вы переключаетесь на историю. Однако у меня была такая же проблема, когда стили не удалялись при переключении историй.
Я поигрался с удалением стилей в декораторе, но кажется, что требуемый стиль применяется только один раз. Можно ли повторно запустить require ()? Я пробовал использовать singleton: false, но это не устранило проблему.
Я почти не решаюсь даже предлагать это, но вы можете попробовать очистить кеш веб-пакетов:
https://webpack.github.io/docs/api-in-modules.html#advanced
Это документы webpack 1, но они могут работать.
Идея: вы могли бы написать декоратор, который удаляет все <style>...</style>
при переключении историй. Чтобы очистить стили, не относящиеся к текущей истории.
Я почти у цели. В конфигурации веб-пакета я использую
'style-loader/useable' instead of 'style-loader',
Это добавляет API, с которым вы можете работать. .use () для добавления стилей, unuse () для их удаления. В моем файле историй я использую декоратор, например:
.addDecorator((c) => <ReactStylesheet stylesheets={[require('./stories.scss')]}>{ c() }</ReactStylesheet> )
Использование следующего компонента React для добавления и удаления стилей.
import * как 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, чтобы закончить эту проблему, как вы думаете, могли бы вы помочь нам улучшить документацию в этом отношении?
Если вы не можете найти для него подходящего места, просто разместите его где-нибудь в формате уценки. Я позабочусь об этом.
🙇
Всем привет! Похоже, что в последнее время в этом вопросе особо ничего не происходит. Если все еще есть вопросы, комментарии или ошибки, пожалуйста, продолжайте обсуждение. К сожалению, у нас нет времени разбираться в каждой проблеме. Мы всегда открыты для участия, поэтому, если вы хотите помочь, отправьте нам запрос на включение. Неактивные вопросы будут закрыты через 60 дней. Благодаря!
Привет, это снова я! Я собираюсь закрыть эту проблему, чтобы помочь нашим сопровождающим сосредоточиться на текущей дорожной карте разработки. Если упомянутая проблема по-прежнему вызывает беспокойство, откройте новую заявку и укажите эту старую. Ура и спасибо за использование Storybook!
Та же проблема, сборник рассказов не изолирует каждую историю, что делает его непригодным для любого визуального тестирования / приемочного тестирования.
Создание теневого корня вокруг историй мгновенно решит эту проблему без проблем с производительностью
@bennypowers интересно! есть ли у вас пример кода, как этого добиться? 🙇
Возможно, это будет интересно и
Привет. У меня тоже возникла эта проблема
Было ли это исправлено или есть какое-то решение?
@ndelangen
Самый быстрый путь к удовлетворению здесь, вероятно , @moimikey «s предложение использовать ReactShadow
Стратегия, которую следует предпринять, может заключаться в том, чтобы обернуть корень в компоненте ReactShadow, а затем добавить стили с помощью adoptedStyleSheets
(или элемента <style>
для не поддерживающих браузеров)
Пожалуйста, откройте это еще раз, эта проблема делает добавление пользовательских стилей для каждой истории чрезвычайно трудным. У меня есть полностью отдельные истории многомерных выражений, которые реализуют индивидуальный стиль для своих примеров, и глобальное включение всех стилей из каждой истории делает этот вариант использования неприемлемым.
редактировать: Спасибо !!!
Надеюсь, что это будет решено к 21 марта 2020 года.
@moimikey Есть интерес в этом? Лучший способ сделать это к определенной дате ... 😉
ИМО, мы должны добавить параметры или надстройку для обработки этой функции вместо добавления специальных функций только для таблиц стилей. Это приведет к несогласованному поведению таблиц стилей и скриптов. Но, может быть, пора задуматься, какой должна быть «изоляция»?
Я написал быстрый PoC для подхода к аддону, и кому интересно, что это возможно.
https://github.com/pocka/storybook-addon-css
@pocka Ты УДИВИТЕЛЬНЫЙ! 💯
yazzzzz. ура @pocka
Стоит отметить, что решение выражений из-за mdx-js / mdx # 894.
Изменить: Плохо, это определенно! Вам нужно иметь style-loader 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.css
и bar.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 по умолчанию, поэтому пользователи могут использовать macro-preval для вставки содержимого файла в пакет?
Я этого не знала, скоро посмотрю!
Привет, у меня та же проблема.
Для тех, кто сталкивается с проблемой, попробуйте этот обходной путь . (Однако для этого нужно немного глубоких знаний о веб-пакете).
@ndelangen Я взглянул на макрос, но он позволяет «загружать файлы CSS из файловой системы», верно? Я думаю, что многие пользователи хотят импортировать файлы SASS, Less, Stylus, CSS с PostCSS и т. Д., Чтобы такой подход не удовлетворял потребности. Моя текущая идея - надстройка CSSResource, добавляющая правило, которое импортирует файл CSS с to-string-loader
(или file-loader
), чтобы пользователь мог импортировать файл CSS, а затем использовать его для надстройки.
// adding a rule like this
{
test: /\.css$/,
resourceQuery: /cssresources/,
use: ['to-string-loader', 'css-loader', 'postcss-loader']
}
Для препроцессоров также необходима возможность настройки test
и use
. Можно выбрать правило для файла стиля, а затем изменить его с помощью oneOf
но это будет так сложно ...
Что вы думаете?
@pocka да, это звучит как интересная концепция!
Привет, интересно, над этим все еще работают? У меня также возникла проблема, я знаю, что можно обойтись, но хотел бы знать, будет ли исправление доступно в ближайшее время.
Привет, не могли бы вы привести пример обходного пути с помощью Vue Story?
Насколько я могу судить, обходной путь по- прежнему приводит к складыванию таблиц стилей после первоначального просмотра, по крайней мере, если вы используете надстройку Docs. 😕
Не проявляя неуважения, я считаю, что @pocka довольно недостаточен, поскольку он не изолирует стили, которые были импортированы в файлы компонентов, а не в файлы историй, что, на мой взгляд, является более распространенным шаблоном. Мое личное желание - я подозреваю, что это может разделяться и другими в этой теме - иметь возможность иметь import './Button.css'
внутри Button.jsx
которое используется только в файлах историй, где Button.jsx
импортирован. Построение для каждой истории, как это предусмотрено Button
(прямо или косвенно), не подвергался воздействию любые правила CSS из Button.css
. (Здесь проблема состоит в том, чтобы убедиться, что, скажем, в OtherWidget.css
отсутствуют некоторые правила, которые случайно оказались в Button.css
- может быть, они были упущены из виду при рефакторинге или чем-то еще - и отсутствуют это потому, что истории для OtherWidget получают весь статически импортированный CSS всего приложения, поэтому OtherWidget по-прежнему отлично выглядит в Storybook.)
Вместо этого, я думаю, я бы изменил все загрузчики CSS на инъекцию с помощью lazyStyleTag
, а затем использовал API веб-пакетов для создания нового модуля, который группирует модули CSS по файлам историй, которые в конечном итоге их требуют, и прослушивает изменение истории. события для включения и выключения соответствующих модулей.
Был ли этот подход уже рассмотрен и отвергнут, или есть какие-то проблемы, которые вы видите сейчас? Я думаю, что могу сделать все это в надстройке Storybook, но он мог бы быть чище, если бы он был интегрирован в Storybook в качестве основной функции.
Если вам нужна строгая инкапсуляция стиля, браузеры поставляются с ней. Рискуя раскрыть здесь свое собственное невежество, я все еще не уверен, почему весь этот пользовательский 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 вставляет стили непосредственно в заголовок документа. Чтобы это изменить, вам нужно каким-то образом изменить конфигурацию веб-пакета.
Использование теневой модели DOM для полной изоляции каждой истории также означало бы репликацию тегов стиля, общих для многих историй, в каждую из них; использование общего стиля, связанного с webpack, будет более эффективным. Может быть, недостаточно, чтобы иметь огромное значение, но, возможно, достаточно, чтобы компенсировать преимущества, если таковые имеются, от использования теневого DOM вместо использования lazyStyleTag
(что, я думаю, является единственной частью сложности, которую теневые корни могли бы спасти тебя).
Мне также интересно увидеть, как это исправят рано или поздно.
Это было бы безопасно, а также плохо для производительности.
Новый iframe должен будет анализировать javascript, анализировать CSS, подключаться к каналу postmessage, повторно подключаться к веб-сокету и, возможно, многое другое.
@ndelangen, извините, что цитирую вас из 2017 года, но вы все еще думаете, что перезагрузка iframe слишком дорога? Браузеры делают такие вещи постоянно; они, вероятно, очень оптимизированы для этого. В этом случае это будет даже быстрее, чем обычная загрузка страницы, поскольку нет сетевых запросов.
Для меня выгода перевешивает стоимость, потому что я бы предпочел свежий iframe для каждой истории. Я бы допустил задержку в 600 мс за такую роскошь.
(Мой вариант использования заключается в том, что я пытаюсь отобразить некоторые устаревшие компоненты angularjs в сборнике рассказов, и позвольте просто сказать, что компоненты не очень чистые. Они очень сохраняют состояние; они имеют побочные эффекты и используют службы angularjs, которые также очень запоминающийся. Вещи ломаются неожиданным образом.)
Одна из идей для поверхности API - настроить сборник рассказов в .storybook/manager.js
.
addons.setConfig({
refreshBetweenStories: true,
})
Это можно рассматривать как настройку пользовательского интерфейса, если вы правильно наклоните голову.
Для людей, которые не включают этот флаг, не будет никаких затрат времени выполнения, а для тех, кто его действительно включит, он _ действительно_ нужен, поэтому любая такая задержка будет терпимой.
Если вы хотите, чтобы это было исправлено, проголосуйте за, добавив 👍 к описанию проблемы. Мы используем это для расстановки приоритетов!
.addDecorator ((getStory) => {
требуется ('./ story.sass');
return getStory ();
})
ПРИВЕТ!!!!
где я могу поставить это? !!!
Самый полезный комментарий
Создание теневого корня вокруг историй мгновенно решит эту проблему без проблем с производительностью