
최근 기존 프로젝트에 아토믹 디자인 패턴을 적용하며 StoryBook을 함께 사용하고 있다.
추후에 StoryBook을 계속 사용할 것 같아서 사용하면서 발생했던 문제들을 작성해 볼 예정이다.
요즘 웹 서비스는 Desktop, Mobile, Tablet 등 다양한 디바이스에서 정상적으로 작동해야 하므로 보통의 경우 필수적으로 반응형 작업을 해야한다. 이번 StoryBook에서 userAgent 다루기는 StoryBook에서 반응형 작업을 할 때 발생했던 문제를 다룬다.
navigator.userAgent는 Web.API로 브라우저의 사용자 정보를 문자열로 반환해준다.
navigator.userAgent를 사용하면 다음과 같은 문자열을 얻을 수 있는데
// Desktop
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36'
// Mobile
Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Mobile Safari/537.36'
이를통해 사용자가 어떤 디바이스에서 접근했는지 확인할 수 있다.
🚨주의!
userAgent는 사용자가 구성할 수 있기 때문에 (ex. 개발자 도구 .. ) MDN 공식 문서에서는 navigator.userAgent가 반환하는 문자열에 기반한 브라우저 식별은 신뢰할 수 없어 권장하지 않는다고 한다.
사용자가 변경할 수 있기 때문에 navigator.userAgent를 기반으로 한 브라우저 식별은 신뢰 할 수 없다고 하지만 중요한 비지니스 로직이 아닌 식별한 디바이스에 대해 알맞은 UI를 제공하는 역할로만 사용할 예정이라 사용해도 무방하다고 판단했다.
Desktop 환경이 아닌 다른 환경에서 접근했을 때 Desktop과 다른 View를 보여주도록 개발했는데, 이때 userAgent를 사용해 브라우저를 식별하고 알맞은 View를 표시할 수 있도록 했다.
해당 기능을 StoryBook에서도 정상적으로 작동하게 하려면 userAgent를 상황에 맞게 핸들링 해야하는데 쉽지 않다.
StoryBook을 누군가에게 공유해하 한다고 생각하면 매번 개발자 도구를 켜서 확인하라고 할 수 없었고, StoryBook의 Canvas 툴에 제공되는 기능은 개발자 도구처럼 View Port와 userAgent를 함께 변경해주지 않기 때문에 그 기능만 사용할 수 없었다.
그러다 storybook-addon-useragent 라이브러리를 찾았고 문제를 해결할 수 있었다.
storybook-addon-useragent는 스토리북에서 userAgent에 따라 다르게 화면을 구성할 수 있고, 페이지 자체를 모바일로 인식할 수 있다고 한다.
// npm
npm i storybook-addon-useragent -D
// yarn
yarn add storybook-addon-useragent -D
// .storybook/userAgent.js
export const customUserAgents = [
{
name: "Windows_7-IE_11", // 원하는 이름 사용 가능
userAgent: // 다른 userAgent를 넣어도 상관 없음
"Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko",
},
];
// .storybook/preview.js
...
import { customUserAgents } from "./userAgent";
export const parameters = {
...
userAgent: customUserAgents,
};
설정 후 Storybook를 재실행 하면 아래와 같이 Storybook에 UserAgent 탭이 생성된다.

User Agent 탭을 살펴보면 iframe과 window에 각각 브라우저가 저장되어있다. Storybook의 Cavnas가 iframe으로 생성되어있기 때문에 iframe의 userAgent를 강제로 변경시켜 사용하는 것으로 생각된다.

// Example.stories.tsx
...(생략)
const Template = (args) => <Example {...args} />;
export const IOS = Template.bind({});
IOS.args = {
activeUserAgent:
"Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1 Mobile/15E148 Safari/604.1",
};
사용법은 활성화 시키고 싶은 userAgent 정보를 위의 사진처럼 activeUserAgent에 담아 파라미터 값으로 넘겨주면 된다. 매우 간단.
적용시킨 stories를 Storybook에서 열어보면 아래와 같이
User Agent -> iframe 으로 activeUserAgent로 넘겨주었던 정보가 등록된다.

실제 적용시 activeUserAgent에 항상 userAgent 값을 string 형식으로 넘겨주기엔 불편함과 가독성이 떨어지는 문제로 미리 여러 환경의 userAgent를 저장해 두고 필요시 아래와 같이 import 해서 사용했다.
// somthing.stories.tsx
import { USER_AGENT_IOS, USER_AGENT_MAC } from 'src/constants'; // userAgent 상수로 관리
...
export const Desktop = Template.bind({});
Desktop.args = {
...
activeUserAgent: USER_AGENT_MAC,
};
export const Mobile = Template.bind({});
Mobile.args = {
...
activeUserAgent: USER_AGENT_IOS,
};
storybook-addon-useragent를 사용하면서 activeUserAgent를 넘겨주었을 때는 iframe에 해당 정보가 등록되고, 넘기지 않았을 때는 정보가 제거되는 것을 확인하고 모바일인 경우에만 activeUserAgent를 넘기도록 작업했다.
iframe에 활성화된 userAgent가 없으면 기본 값인 Window의 정보로 대체 될 것 이라고 생각했는데 실제로는 변경된 값이 유지가 된다.
아래와 같이 PC에서 Mobile로 변경 했을 때 정상적으로 iframe의 userAgent가 변경되어 인식한다.
하지만 다시 PC로 돌아갈 경우 iframe의 userAgent 정보는 사라진 것 처럼 보이지만 실제로는 사라지지 않았다.

activeUserAgent로 특정 userAgent를 활성화 시키면 처음 활성화 된 정보가 페이지 새로고침 혹은 특정 activeUserAgent를 다시 활성화 시킬 때 까지 유지되는 것으로 보인다.
따라서 해당 라이브러리를 사용 할 때 PC 및 Mobile 환경에 각각 변화가 있어야 하는 스토리에는 알맞은 userAgent 정보를 activeUserAgent 값으로 필수로 넘겨줘야 할 것 같다.