Как стать автором
Обновить
61.05
Skyeng
Крутой edtech с удаленкой для айтишников

Решаем ошибку при миграции на Storybook 7

Уровень сложностиСредний
Время на прочтение3 мин
Количество просмотров1K

Привет, я фронтенд-разработчик в Skyeng. При переходе с шестой версии Storybook на седьмую встретилась ошибка «Providers from the BrowserModule have already been loaded. If you need access to common directives such as NgIf and NgFor, import the CommonModule instead».

В этой небольшой статье объясняю, почему возникает баг и как его исправить.

Почему возникает ошибка

BrowserModule экспортирует инфраструктуру для всего Angular-приложения, и его стоит импортировать только один раз. Если повторно импортировать такой модуль, например, в lazy-loaded feature-модуль, то получим ошибку о необходимости использования CommonModule вместе целого BrowserModule.

По такому же принципу должны импортироваться и другие application-wide провайдеры в приложении.

Пример с ошибкой:

// feature.module.ts

@NgModule({
  imports: [BrowserModule], // здесь импортировать модуль не нужно
  …
})
export class FeatureModule {
…

// app.module.ts

@NgModule({
  imports: [BrowserModule], // AppModule уже импортирует BrowserModule
  …
})
export class AppModule {
…

Так как FeatureModule содержит повторный импорт BrowserModule, то получим ошибку: «Providers from the BrowserModule have already been loaded. If you need access to common directives such as NgIf and NgFor, import the CommonModule instead».

Что касается Storybook, то при аналогичном импорте модуля в метаданных так же возникнет ошибка:

// storybook-helper.module.ts

@NgModule({
  imports: [BrowserModule], // первая ошибка: StorybookHelperModule не должен импортировать BrowserModule
  …
})
export class StorybookHelperModule {
…

// test.stories.ts

export default {
  title: 'TestComponent',
  component: TestComponent,
  decorators: [
    moduleMetadata({
      imports: [StorybookHelperModule], // вторая ошибка: импортируем BrowserModule, находящийся в StorybookHelperModule
    }),
  ],

Даже если компонент в Storybook зависит от BrowserAnimationsModule / BrowserModule, такой модуль не стоит импортировать с помощью других модулей или напрямую при настройке Storybook.

В моём случае была ошибка именно в наличии импорта BrowserModule во вспомогательном модуле для сторибука. Но даже если BrowserModule импортирован напрямую в метаданных стори, то в консоли тоже будет сообщение о некорректном импорте BrowserModule, но в виде предупреждения.

Как исправить ошибку

Начиная с 7-й версии, Storybook использует новый bootstrapApplication API

Все application-wide провайдеры, включая BrowserModule и BrowserAnimationsModule, теперь настраиваются с помощью applicationConfig декоратора:

// test.stories.ts

export default {
  title: 'TestComponent',
  component: TestComponent,
  decorators: [
    applicationConfig({  // новый декоратор
      providers: [importProvidersFrom(BrowserAnimationsModule)],
    }),
  ],

То же самое касается конфигурируемых модулей (знакомый всем паттерн forRoot). Их тоже теперь указываем через applicationConfig декоратор.

Было:

export default {
  title: 'TestComponent',
  component: TestComponent,
  decorators: [
    moduleMetadata({
      imports: [SomeModule.forRoot()],
    }),
  ],

Стало:

export default {
  title: 'TestComponent',
  component: TestComponent,
  decorators: [
    applicationConfig({ // теперь используем новый декоратор
      providers: [importProvidersFrom(SomeModule.forRoot())],
    }),
  ]

Вывод

Стоит помнить про то, что содержит в себе модуль, для чего он нужен и как его правильно импортировать. Теперь с 7-й версии Storybook нужно использовать applicationConfig декоратор, если требуется использовать application-wide провайдеры или конфигурируемые модули.

Если остались вопросы — пишите, разберемся вместе!

Теги:
Хабы:
Всего голосов 13: ↑13 и ↓0+13
Комментарии0

Публикации

Информация

Сайт
job.skyeng.ru
Дата регистрации
Дата основания
Численность
1 001–5 000 человек
Местоположение
Россия