【2021-8】 Next.js + TypeScript + Storybook(Atomic Design) + Sass + jest
フロントエンド環境に実装をしたStorybookに、Sassを導入する
StorybookへのSassの導入でcss-loaderでエラーにはまり、手順の記事を書きました。
原因はWebpack4と5で破壊的な変更(更新)からPKGをインストールして解決できました。(めでたし)
でも、フロントエンド開発に必要そうなベーシックな環境構築を、「ざーーっと、まとめたかった」ことが、個人的には一番の記事の動機です。
実装リスト
- docker
- Next.js/TypeScript
- Sass
- Storybook
- jest
- Atomic design
※導入は個人の責任でおねがいします。(お約束文)
開発情報
- Macbook MacOS BigSur 11系
- docker ※PCのローカル環境は汚したくない
- node v16.3.0 ※v14系ではない(わりとポイントかもしれません)
docker-compose ※今後、バックエンド側も実装する予定です(今後の別記事に書くかも)
初期のディレクトリ構成(最初の状態だけ画像を貼ります)
- docker-compose.yamlファイルをルートディレクトリ直下に作成
- dockerディレクトリの直下に、test_frontendディレクトリを作成して、Dockerfileを作成
フロー
- Docker環境構築
- Next.js + Typescriptの導入
- storybookの導入
- jestの導入
- Sassの導入
- StorybookにSassを導入
Step_1 Docker環境構築
Dockerfileの作成
最小限をインストールします。
FROM node:16.3-alpine
RUN yarn install && yarn global add \
create-react-app
WORKDIR /test_frontend
docker-compose.yamlの作成
Next.jsとStorybookのport番号はお好きなもので
ディレクトリもお好きに
version: '3.8'
services:
test_frontend:
container_name: next_storybook_jest_container
build: ./docker/test_frontend
ports:
- 13030:3000
- 16036:6006
volumes:
- ./test_frontend:/test_frontend
stdin_open: true
tty: true
environment:
- TZ=Asia/Tokyo
networks:
- default
networks:
default:
dockerをbuildする
確認用コマンド(参考)
docker images -a
docker ps -a
docker-compose ps -a
- docker-compose build
docker-compose build --no-cache
--no-cacheは念のため
- docker-compose up -d
docker-compose up -d
- アップしてるかチェックをする
docker-compose ps -a
こんな形で、あとはルートディレクトリ直下に、test_frontendの空ディレクトリができてればOK
docker、docker-composeのどちらでもお好きなようにcontainerに接続ください。
以下はdockerコマンド(参考)
docker exec -it next_storybook_jest_container sh
Step_2 Next.js + Typescriptの導入
起動したdocker contianerに接続をして、早速、create-next-appをします。
Next.jsのインストール
npx create-next-app .
TypeScriptのインストール
- tsconfig.jsonファイルを作成する
touch tsconfig.json
- PKGをインストールする
yarn add -D typescript @types/react @types/node
- インストールできたら起動する
yarn dev
prettierの設定
しわすれるので先に作成をします。※設定はお好みで
- .prettierrc ファイルを作成する
touch .prettierrc
- .prettierrcを編集する
{
"singleQuote": true,
"semi": false
}
Next.jsのファイル編集
- pages/_app.jsと、pages/index.jsのファイル拡張子を.tsxに変更する
pages/_app.js
mv pages/_app.js pages/_app.tsx
pages/index.js
mv pages/index.js pages/index.tsx
- pages/_app.tsxを編集する
import { AppProps } from 'next/app'
import '../styles/globals.css'
function MyApp({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />
}
- pages/index.jsを編集する
不要なコードを削除するのと、後ほど、CSS/Sassの動作テスト用に、classNameを付与したbuttonタグをコーディングしています。
const Home: React.FC = () => {
return (
<>
<h1>Next</h1>
<button className="sample" >sample</button>
</>
)
}
export default Home
Step_3 Storybookの導入
- npx sb init
yarn global add create-react-appがすんでいるため、コマンドを実行できます。(参考)
npx sb init
ファイルが作成されますが、以降の手順でAtomic Designのディレクトリを構築していきます。
Atomic Designの導入
※本記事の構成は参考です。(今回、atomsしか使いません)
- 各ディレクトリを作成する。
mkdir assets
mkdir -p components/atoms
mkdir components/atoms/types
mkdir components/molecules
mkdir components/organisms
mkdir components/templates
typesフォルダで、TypeScriptの型ファイルをそこで管理します。
- npx sb init で作成されたファイルをテスト用で一部だけ移動する。
mv stories/button.css components/atoms
mv stories/Button.stories.tsx components/atoms
mv stories/Button.tsx components/atoms
touch components/atoms/types/Button.types.ts
- components/atoms/types/Button.types.tsを編集する。
export interface ButtonProps {
primary?: boolean;
backgroundColor?: string;
size?: 'small' | 'medium' | 'large';
label: string;
onClick?: () => void;
}
- components/atoms/Button.tsx を編集する。
なお、もともとコーディングされてあった、interface ButtonPropsは削除してください。
./types/Button.typesをインポートする
import { ButtonProps } from './types/Button.types'
- storiesディレクトリはいらないので削除する
rm -r stories
.storybook/main.jsの編集
.storybook/main.jsを以下へ修正します。
なお、Sassはあとでいれてくので、CSSのまま進めます。
module.exports = {
"stories": [
"../components/**/*.stories.@(js|jsx|ts|tsx)"
],
"addons": [
'@storybook/addon-links',
'@storybook/addon-essentials',
],
}
Storybookの起動
起動の前に、package.jsonのscriptsを編集します。
"scripts": {
<省略>
"storybook": "start-storybook -s public -p 6006"
},
yarn storybook
Step_4 jestの導入
PKGをインストール
各PKGの解説は省きます。
yarn add -D setimmediate next-page-tester jest babel-jest @babel/core @testing-library/react @types/jest @testing-library/jest-dom @testing-library/dom @testing-library/user-event jest-css-modules
ついでではないですが、開発に他PKGもインストールします。
yarn add axios msw swr
.babelrcファイルの作成
- .babelrcファイルを作成する
touch .babelrc
- .babelrcファイルを編集する
{
"presets": ["next/babel"]
}
packege.jsonへjestの設定
こちら参考にどうぞ moduleNameMapperの参考
- packege.jsonへ、jestを追記する
"jest": {
"testPathIgnorePatterns": [
"<rootDir>/.next/",
"<rootDir>/node_modules/"
],
"moduleNameMapper": {
"\\.(css|scss)$": "<rootDir>/node_modules/jest-css-modules"
}
}
- packege.jsonへ、scriptsを追記する
"scripts": {
<省略>
"test": "jest --env=jsdom --verbose"
},
jestのテストファイルなどの準備
- test用ファイルのディレクトとファイルを作成する
mkdir __test__
touch __test__/Home.test.tsx
- 作成したHome.test.tsxファイルを編集する
import { render, screen } from '@testing-library/react'
import '@testing-library/jest-dom/extend-expect'
import Home from '../pages/index'
it('Should render title text', () => {
render(<Home />)
expect(screen.getByText('sample')).toBeInTheDocument()
})
jestのテスト動作チェック
yarn test
正常にpassしたらOKです。(jestはこれにておわり)
Step_5 Sassの導入
- Sassをインストールする
Next.js的にはこれだけで終わりです。
yarn add sass
公式のガイドの通り、以下のパス設定を行います。
以降の、babel-plugin-module-resolverを使うことで同じように動作します。
const path = require('path'); //追加
module.exports = {
reactStrictMode: true,
// 以下を追加
sassOptions: {
includePaths: [path.join(__dirname, 'styles')],
},
}
- styles/global.scssファイルにテスト用の編集をする
$color_orange: orange;
$base_font_size: 20px;
.sample {
color: $color_orange;
font-size: $base_font_size;
}
- pages/_app.tsxにimportする
import '../styles/globals.scss'
- Sassの動作チェックをする
yarn dev
pages/_app.tsxに、確認するためテストでclassNameを付与したbuttonタグを作成しましたね。
Sassが動作してることが確認できたらOKです。
Step_6 StorybookにSassを導入
本題のStorybookへSassを設定していきます。
各Stepは以下の通りです。
- sass-loaderインストール
- 各PKGのインストール
- StorybookがSassファイルを認識するためのパス設定
- .storybookディレクトリのファイル編集
PKGの解説(参考情報)
Sassの導入で「あれ?」と思った方はいるかもしれません。
Next.jsの記事で目にする、@zeit/next-sass,node-sassのPKGをインストールしてないからです。(もしかしたら、この結果、ハマる人がおおいのかもしれないです)
記事も長くなりましたから、上記の理由は別の記事:node-sassの終了アナウンスから、dart-sassを使うで解説します
StorybookにSassを導入するためのポイントはStep_2です。
StorybookでSassを動かすため、Webpackの破壊的な更新により(重要)、以下のPKGが必要になります。
@storybook/builder-webpack5
@storybook/manager-webpack5
webpack ←最新ヴァージョンを使うため必要です。
および、Storybookがファイルのパスを認識するために、babel-plugin-module-resolverをインストールする必要があります。
PKGのインストールができてしまえば、あとはファイルを編集するだけですね。(苦労・・・)
css-loader,style-loaderも忘れずに!
1. sass-loaderインストール
まずお約束の、sass-loaderインストール ※10系でないと、storybookが起動しません。
yarn add -D sass-loader@^10
2. 各PKGのインストール
yarn add -D webpack @storybook/builder-webpack5 @storybook/manager-webpack5 css-loader style-loader babel-plugin-module-resolver
3. StorybookがSassを認識するためのパス設定
babel-plugin-module-resolverを使ってパス設定を行います。
- .babelrcファイルの編集をする
pluginsを追加します。
"plugins": [
[
"module-resolver",
{
"root": [
"."
],
"alias": {
"@": "./"
}
}
]
]
- tsconfig.jsonファイルを編集する
baseUrlとpathsを追記します。
"baseUrl": ".",
"paths": {
"@/":[
"./*"
]
},
4. .storybookディレクトリのファイル編集
- .storybook/main.jsファイルを編集する
const path = require('path');
module.exports = {
"stories": [
"../components/**/*.stories.@(js|jsx|ts|tsx)"
],
"addons": [
'@storybook/addon-links',
'@storybook/addon-essentials',
],
core: {
builder: 'webpack5',
},
webpackFinal: async (config) => {
const rootPath = path.resolve(__dirname, '../');
config.resolve.alias['@'] = rootPath;
config.module.rules.push({
test: /\.scss$/,
sideEffects: true,
use: [
"style-loader",
{
loader: "css-loader",
options: {
importLoaders: 2,
},
},
{
loader: "sass-loader",
options: {
sourceMap: true,
},
},
],
});
return config;
}
}
- .storybook/preview.jsファイルを編集する
import '@/styles/globals.scss'
- componets/atoms/button.css の拡張子を.scssへ変更する
mv components/atoms/button.css components/atoms/button.module.scss
- components/atoms/button.module.scssのディレクトリを移動する
mv components/atoms/button.module.scss ../../styles/components/atoms
- components/atoms/Button.tsxファイルを修正する
# import './button.css'; 削除でOK
import '../../styles/components/atoms/button.module.scss';
- components/atoms/Button.tsxに、テスト用でbuttonタグをコーディングしておきます
<button className="sample">sample</button>
- styles/components/atoms/button.module.scss にインポートを追記する
変数やmixinを読み込むためのコーディングです。
@import '@/styles/global.scss';
Sassを導入したStorybookを起動する
yarn storybook
お疲れさまでした。
エラーなく導入ができますように
Discussion