Storybook и его внутренний Webpack

Storybook использует отдельный процесс сборки, в котором Webpack выступает центральным инструментом компиляции и связывания модулей. Архитектура построена вокруг разделения окружений: preview (рендер компонентов) и manager (интерфейс Storybook). Оба окружения имеют собственные конфигурации Webpack, которые частично пересекаются, но решают разные задачи.

Preview-часть отвечает за выполнение компонентов, их зависимостей, стилей, ассетов и всего, что необходимо для изоляции stories. Manager-часть формирует UI панели, навигацию, тулбары и интеграции аддонов.


Разделение Webpack-контекста: manager и preview

Внутренняя сборка Storybook фактически представляет собой два независимых Webpack-проекта.

Preview Webpack:

  • обработка React/Vue/Angular/Svelte компонентов
  • трансформация TypeScript и JSX
  • работа со стилями (CSS/SCSS/PostCSS)
  • загрузка ассетов (images, fonts, svgs)
  • поддержка story-файлов (.stories.)

Manager Webpack:

  • сборка интерфейса Storybook
  • интеграция аддонов (Controls, Actions, Docs)
  • работа с React runtime
  • минимальная работа с пользовательским кодом проекта

Разделение снижает связанность и позволяет оптимизировать каждую сборку отдельно. Manager часто собирается быстрее и имеет более стабильную конфигурацию, в то время как preview адаптируется под проект.


Генерация Webpack-конфигурации Storybook

Конфигурация Webpack в Storybook не статична. Она формируется динамически через набор пресетов и функций, определяемых в .storybook/main.js (или .storybook/main.ts).

Основная структура:

module.exports = {
  stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],
  addons: [
    '@storybook/addon-essentials',
  ],
  webpackFinal: async (config) => {
    return config;
  },
};

На этапе запуска Storybook:

  1. загружаются пресеты framework (React/Vue/etc)
  2. добавляются встроенные loader’ы
  3. подключаются аддоны
  4. применяется пользовательская функция webpackFinal
  5. формируется финальный Webpack config

Базовые компоненты Webpack-конфига Storybook

Конфигурация, генерируемая Storybook, включает несколько ключевых блоков:

Entry points

Entry зависит от режима:

  • preview:

    • runtime Storybook
    • регистратор stories
    • client API
  • manager:

    • UI shell
    • аддоны
    • состояние приложения

Output

Output настроен как SPA-бандл, обычно в memory filesystem при dev-режиме:

  • filename hashing
  • chunk splitting
  • runtime chunk separation

Resolve

Storybook расширяет resolution:

  • алиасы (@storybook/*)
  • поддержка TS paths (при наличии tsconfig)
  • расширения файлов .ts, .tsx, .js, .jsx, .mjs

Loader pipeline и обработка модулей

Webpack loader pipeline в Storybook является одной из самых сложных частей системы, поскольку он объединяет пользовательский код и инфраструктурный код Storybook.

JavaScript и TypeScript

Основной слой обработки:

  • Babel-loader (React, JSX, modern JS)
  • ts-loader или Babel preset TS
  • optional SWC (в некоторых конфигурациях)

Типичный пайплайн:

TS/JS → Babel/TS loader → Webpack AST → bundle

Storybook автоматически добавляет presets:

  • @babel/preset-react
  • @babel/preset-typescript
  • @babel/preset-env

CSS и препроцессоры

CSS-цепочка зависит от проекта:

  • style-loader (инжект в DOM)
  • css-loader (resolve imports)
  • postcss-loader (autoprefixer, plugins)
  • sass-loader (если SCSS)

Особенность Storybook — разделение CSS между preview и manager, что исключает конфликты глобальных стилей.


Ассеты (images, fonts, svgs)

Webpack 5 asset modules используются по умолчанию:

  • asset/resource для файлов
  • asset/inline для мелких ресурсов
  • asset для автоматического выбора

SVG может обрабатываться двумя режимами:

  • как React component (svgr)
  • как static asset

Storybook часто добавляет @svgr/webpack в pipeline для поддержки иконок.


Аддоны как расширение Webpack

Аддоны Storybook являются не только UI расширениями, но и участниками Webpack pipeline.

Некоторые аддоны:

  • добавляют loader’ы
  • модифицируют config через webpackFinal
  • внедряют runtime-плагины

Пример поведения:

  • Docs addon добавляет MDX loader
  • Controls добавляет runtime обработчики аргументов
  • Actions внедряет instrumentation в события

MDX pipeline:

MDX → mdx-loader → Babel → Webpack bundle

Механизм webpackFinal и модификация конфигурации

Ключевой точкой кастомизации выступает webpackFinal.

Конфигурация передается как объект Webpack и может быть изменена:

  • добавление loader’ов
  • расширение resolve.alias
  • подключение plugins
  • настройка optimization

Пример расширения:

webpackFinal: async (config) => {
  config.resolve.alias['@'] = path.resolve(__dirname, '../src');

  config.module.rules.push({
    test: /\.graphql$/,
    use: 'graphql-tag/loader',
  });

  return config;
};

Особенность: Storybook не пересоздает конфиг полностью, а накладывает изменения поверх базовой системы.


Plugins в Webpack Storybook

Webpack plugins в Storybook используются для:

  • оптимизации сборки
  • инъекции переменных окружения
  • генерации HTML шаблонов
  • ускорения dev build

Типичные плагины:

  • HtmlWebpackPlugin (для manager)
  • DefinePlugin (env variables)
  • HotModuleReplacementPlugin
  • ForkTsCheckerWebpackPlugin

Manager и preview используют разные наборы плагинов, чтобы не перегружать runtime.


Разрешение модулей и конфликты зависимостей

Storybook добавляет собственную систему resolution, которая может конфликтовать с проектными настройками:

  • дублирование React runtime
  • разные версии styled-components
  • конфликты alias

Для предотвращения проблем используется:

  • dedupe зависимостей
  • strict resolve rules
  • alias на root node_modules

Кэширование и ускорение сборки

Webpack в Storybook активно использует:

  • filesystem cache
  • persistent cache
  • HMR (Hot Module Replacement)
  • splitChunks optimization

HMR особенно важен для preview, так как позволяет обновлять stories без полной перезагрузки.

Кэширование ускоряет повторные запуски, особенно при больших monorepo.


Разделение chunks и оптимизация

Webpack splitChunks применяется для:

  • отделения vendor-кода
  • выделения runtime
  • изоляции аддонов

Типичная структура:

  • main bundle
  • vendors chunk
  • story chunks
  • manager bundle

Это снижает нагрузку на браузер при работе с большим количеством stories.


Особенности обработки MDX

MDX в Storybook является отдельным слоем поверх Webpack.

Pipeline включает:

  • mdx-loader
  • babel transformation
  • React component generation

MDX позволяет описывать stories как смесь markdown и React компонентов, что требует дополнительной AST трансформации.


Runtime связка Storybook и Webpack

После сборки Webpack Storybook переходит в runtime-режим:

  • загружает bundle preview
  • инициализирует story registry
  • связывает iframe с manager UI

Manager управляет preview через postMessage API, а Webpack-бандл предоставляет исполняемую среду для stories.


Типовые проблемы интеграции Webpack в Storybook

На практике часто возникают следующие классы проблем:

Конфликты Babel конфигурации

Разные presets между проектом и Storybook приводят к ошибкам трансформации JSX или decorators.

Дублирование React

Webpack resolution может подтянуть две версии React, что вызывает runtime ошибки hooks.

CSS leakage

Глобальные стили могут проникать в manager через неправильные loaders.

Медленная сборка

Причины:

  • отсутствие cache
  • тяжелые loaders (sass, ts-checker)
  • слишком большой story graph

Архитектурные ограничения Webpack в Storybook

Несмотря на гибкость, Webpack накладывает ограничения:

  • сложность конфигурации при масштабировании
  • чувствительность к version mismatch
  • высокая стоимость initial compile
  • необходимость ручной оптимизации loader pipeline

Эти ограничения частично компенсируются абстракциями Storybook, но не устраняются полностью.


Интеграция пользовательского Webpack-кода

Storybook позволяет встраивать пользовательские правила:

  • кастомные loaders
  • плагины
  • aliasing стратегию
  • feature flags через DefinePlugin

При этом важно учитывать порядок применения конфигураций, так как Storybook сначала формирует базу, а затем применяет пользовательские изменения.


Поведение Webpack в monorepo окружениях

В monorepo структурах Webpack Storybook сталкивается с:

  • hoisted dependencies
  • symlinked packages
  • multiple tsconfigs

Для корректной работы часто требуется:

  • настройка resolve.symlinks
  • корректные include/exclude в loaders
  • унификация babel config

Взаимодействие Webpack и HMR в Storybook

Hot Module Replacement реализован через Webpack dev server и client runtime Storybook.

Процесс обновления:

  1. изменение файла story
  2. Webpack recompilation module graph
  3. push обновления в client
  4. обновление iframe preview

HMR работает на уровне модулей, а не всего приложения, что обеспечивает быстрый feedback loop при разработке компонентов.