Standalone UI Development Environment Built with Storybook

Standalone UI Development Environment Built with Storybook

1. Introduction

As a project progresses, the process of completing a single screen is often divided into more tasks than expected.

In projects, I am responsible for implementing UI elements such as screen markup, styling, and interactions. Previously, the publishing repository and development repository were physically separated, so I worked only within the publishing repository. Once the screen markup and styles were completed, a developer would move them to the development repository and add the logic and APIs.

However, the structure was different in this project. The process changed so that the publisher would work directly in the development repository, splitting off a branch and working in parallel with the developers. Sharing the same repository and codebase brought certain benefits, but it also introduced new difficulties. Even though we were working on the same screen within the same repository, it was difficult to view the actually completed screen together until the work on each other's branches had been merged.

When working on the publishing branch, the API might not yet be ready, or the state management logic being developed on another branch might still be incomplete.

In this article, I would like to summarize my experience applying Storybook to develop and review UI more independently in an environment where publishing and development are carried out separately by branch within a single repository, along with the issues I encountered during the actual implementation.

2. Problem Definition: What Is Needed to Review a Single Screen

Because work was divided across branches within the same repository, there was a frustrating situation where it seemed like "we should be able to see it immediately once we merge it, but in reality, that isn't the case." When the markup on my branch and the logic on the development branch had not yet been merged, there was no practical way to review the completed screen together.

In this state, several conditions were required to review a specific screen in the actual environment.

First, we had to run the development environment containing the relevant screen, and in some cases, multiple applications or development servers had to be running together. In addition, for screens requiring a logged-in state or API responses, we had to prepare actual data to create the desired state.

However, when working on a branch that had not yet been merged, these conditions were not always ready.

For example, the API specification might be defined while the actual server had not yet been implemented, or it might be difficult to intentionally create data for a specific state. Empty lists, conditions for displaying specific buttons, completed application states, and error states were not always easy to review simply by running the actual service.

As a result, even to check a simple UI state, we had to run the entire development environment, navigate to the desired screen, and then create specific conditions.

This process presented the following problems.

  • Publishing work was affected by the readiness of the development environment.
  • It was difficult to repeatedly reproduce specific UI states.
  • Every time API data changed, the screen review process was also affected.
  • To review a screen state, we had to wait for or request the data or environment to be prepared by the development team each time.

UI work in particular requires reviewing not only normal states but also various situations such as empty, exceptional, and loading states. However, in the actual development environment, intentionally creating these states each time required additional time.

Therefore, what we needed was not simply a way to display screens separately, but an environment where the states of specific components and screens could be reproduced consistently at any time.

3. Solution: Building an Independent UI Development Environment with Storybook

To solve this problem, I applied Storybook.

The primary motivation was to be able to check screen states immediately on my local machine without requesting data or an environment from the development team, even when the API was not yet ready—or, in extreme cases, when it was not even possible to log in and access the screen through the development environment.

Storybook is a tool that allows components to be rendered and reviewed independently, separately from the application's overall environment. However, rather than using it simply to view a list of components, I aimed to create an environment that was as similar as possible to the project's actual UI development environment.

To achieve this, I configured it around the following main principles.

  • Use the same Vite configuration as the actual project in Storybook
  • Reproduce the Provider environment used by the actual application
  • Make it possible to check screen states immediately on my local machine without requests, even when the development team's API or login environment is not ready

3.1 Aligning the Actual Project Environment with the Storybook Environment

Configuring Storybook as a separate environment is convenient, but if its settings differ from those of the actual application, it can create additional problems.

For example, something may appear correctly in Storybook while alias or style settings are applied differently in the actual application.

To reduce this discrepancy, I configured the project so that the Vite settings already in use could also be used in Storybook.

framework: {
  name: '@storybook/react-vite',
  options: {},
},
viteFinal: async (config) => {
  const { config: userConfig } = await loadConfigFromFile(
    path.resolve(__dirname, '../vite.config.mts'),
  );
  return mergeConfig(config, {
    ...userConfig,
    resolve: {
      alias: {
        '~': path.resolve(__dirname, '../src'),
      },
    },
  });
},

With this configuration, settings such as the alias and style processing method used in the actual project could be kept as consistent as possible in Storybook as well.

In addition, I configured the Provider environment used by the actual application in Storybook's preview settings.

For example, I also applied the Provider for supplying themes, the Provider for managing data requests, and the Provider for handling notification messages in the Storybook environment.

This process was not merely configuration for running Storybook; it was work intended to reduce the differences between Storybook and the actual application.

Although we created an environment for reviewing UI independently, if it differed too much from the actual application, we would ultimately need to perform validation twice.

3.2 Configuring Mock Data to Reduce API Dependencies

When applying Storybook, the aspect I considered most important was reducing API dependencies.

Many actual screens are built around data received from the server. Therefore, simply rendering components in Storybook made it difficult to sufficiently reproduce a variety of states.

Initially, we could consider writing the required data directly in each Story file.

export const Default = {
  args: {
    data: {
      // Story마다 필요한 Mock 데이터 작성
    },
  },
};

However, as the number of screens increased and the states became more diverse, the likelihood of identical or similar Mock data being repeated across multiple Stories also increased.

Therefore, I applied an approach that separated Mock data by role.

src
 └── mocks
      ├── fixtures
      └── handlers

In fixtures, I organized representative data used by the screens, while in handlers, I configured the system to intercept actual API requests and return the desired data.

This made it possible to separate multiple states for a single screen relatively clearly.

For example, it could be configured as follows.

화면
 ├── 기본 상태
 ├── 빈 상태
 ├── 특정 조건 상태
 └── 에러 상태

In Storybook, I created each state as an independent Story so that it could be reviewed immediately.

As a result, I was able to continue UI work even when the actual backend was not ready, and I could also reduce the need to create data in the actual environment every time I wanted to check a specific state.

4. Problems Encountered During the Actual Implementation

Applying Storybook did not solve every problem between publishing and development.

Rather, applying Storybook to an actual project made issues that had previously gone largely unnoticed become more apparent.

4.1 Story Errors Caused by Component Renaming

As the project progressed, we worked on organizing the naming to clearly distinguish the roles of the components.

As suffixes that distinguished the roles were added to the existing component names, the names of multiple files and their import paths changed.

For example, changes like the following may occur.

JobDetail
↓
JobDetailWkr

In this process, the import paths in Story files that had already been written were also affected.

// 변경 전
import { JobDetail } from './JobDetail';
 
// 변경 후
import { JobDetail } from './JobDetailWkr';

Changing the name of a single component may not be a major task in itself. However, if Story files reference that component, the scope of the changes can be broader than expected.

If the publishing and development repositories had remained separate as before, I would not have discovered this change until I brought the work results back. However, because I was working on branches within the same repository, changes in the development branch immediately surfaced as conflicts during merging, and we had to reconcile them on the spot.

Through this experience, I realized that Storybook is not a separate deliverable isolated from the actual project code, but code that is also affected by changes in the project structure.

I also felt that changes affecting multiple people, such as file structure or naming, should be shared in advance whenever possible.

For those maintaining Story files, even a small amount of advance notice can reduce unnecessary modification work.

4.2 Not Everything Could Be Checked in Storybook

One thing I clearly realized while applying Storybook was that it is not a tool that completely replaces the actual application.

Although it is highly efficient for checking UI states at the component level, flows connecting multiple screens and features that depend on the actual environment required separate verification.

For example, these included the following areas.

  • Navigation between screens
  • Switching between multiple applications
  • Connecting actual API responses to the UI
  • Issues that occur only in the actual runtime environment
  • Message handling with external environments

These aspects were difficult to check in Storybook's independent environment or required separate Mock implementations.

At first, I thought it would be best to make as many screens as possible available in Storybook. However, after applying it in practice, I concluded that moving everything to Storybook itself should not become the goal.

Ultimately, distinguishing their roles proved more efficient.

Storybook
→ 컴포넌트 및 화면의 상태 확인
→ UI 리뷰
→ 다양한 데이터 상태 재현
→ 퍼블리싱 결과 공유
 
실제 개발 환경
→ 화면 간 이동 확인
→ 실제 API 연동 확인
→ 전체 사용자 흐름 확인
→ 실제 실행 환경 검증

Rather than treating Storybook and the actual application as competitors, it was more appropriate to use them as verification environments with different purposes.

5. Comparison Before and After Adoption

Category

Previous Approach

After Adopting Storybook

Execution Unit

Required running the entire development environment

Run only the required component or screen

Data Preparation

Affected by the actual API and login state

Configure the desired state with Mock data

State Reproduction

A specific state had to be created manually

Check the state immediately for each Story

UI Verification

Required navigating to the desired screen

Access directly through the relevant Story

Reverification Method

The scenario had to be repeated every time

Reproduce it immediately using the saved Story

Suitable Areas

Checking the overall flow and actual integrations

Verifying UI states and components

The biggest change after adopting Storybook was not simply that screens became easier to view.

Previously, checking a specific screen state first required preparing the environment and creating that state.

With Storybook, however, the required state itself could be created as a single Story.

In other words, the preparation process for checking a screen was reduced, and once a state was defined, it could be reproduced consistently thereafter.

6. Lessons Learned from This Experience

6.1 Storybook’s Greatest Strength Was Reproducing States Rather Than the UI Itself

At first, I thought of Storybook as a tool for checking components in isolation.

However, as I applied it to an actual project, I found that its greatest strength was the ability to repeatedly reproduce specific states.

In addition to normal states, I could also define situations that would be difficult to create in a real environment, such as empty screens or error states.

Because a Story retains the same state after it has been created, it could be reused repeatedly during UI modifications and reviews.

6.2 I Could Continue Working Even When the Development Environment Was Not Ready

There were more frequent occasions than expected when a branch had not yet been merged or, in more serious cases, when I could not even log in and access the screen through the development environment.

In the past, I would have had to ask the development team for data or account status information, or postpone my work until the environment was restored to normal.

However, after I started using Storybook together with Mock data, I could create and check the desired screen states directly in my local environment even in these situations. I was able to continue working on the UI without requesting the necessary data or waiting for the environment to be restored.

What I learned from this experience was that Storybook’s value lies less in making screens look attractive and more in making my work as independent as possible from the readiness of other parts of the project.

6.3 The Goal Was Not to Build Every Screen in Storybook

As I applied Storybook, the most important consideration became not how extensively I used the tool, but where it would be most effective.

Storybook was highly effective for screens with many UI states that could be sufficiently checked without actual data.

On the other hand, for features where the flow between multiple screens or integration with the real environment was important, it was more appropriate to check them in the existing development environment.

Therefore, rather than managing every screen in the same way, I came to believe that it would be more efficient to separate into Storybook the screens with the highest verification costs during parallel development first.

7. Conclusion

Through this experience, I learned that Storybook is not merely a tool for displaying UI components. It can also serve as a verification environment that allows me to independently validate the UI work assigned to me even when the development environment is not yet ready.

In particular, when used together with Mock data in situations where development-side resources such as APIs or login are not ready, it was effective because I could continue working by repeatedly reproducing specific states without making requests to the development team or waiting.

Of course, Storybook cannot solve every problem on its own. Actual API integration, flows between screens, and features that depend on the execution environment still need to be checked in the real development environment.

However, rather than trying to solve everything in a single environment, it was more efficient to divide the roles: checking UI states in Storybook and verifying actual flows and integrations in the real application.

Ultimately, the biggest lesson I took away from this experience was that, more than Storybook itself as a specific tool, the more important question is how independently my work can proceed from the readiness of other parts of the project.

Going forward, when working on new projects, rather than building every screen in Storybook from the beginning, I plan to prioritize areas where UI verification is costly because of their high dependence on the development environment or data. I believe that the Stories accumulated in this way can serve not merely as screens for testing, but as a shared standard for checking and communicating about the UI.

nature

Site footer