経年劣化に耐える React のソフトウェア設計を考えるためのサンプルプロジェクト。
学習目的で、実際に React を使ってアプリケーション開発を行う上で必要だと思ったものをまとめてみました。
- Typescript & React で Single File Components
- 目次
- デモ
- 設計・アーキテクチャ
- 詳細
- VSCode の設定について
- 既存の React プロジェクトのアップデート
- 参考資料
- 公式ドキュメント
Storybook - スタイルガイド(GitHub Pages)
https://imamachi-n.github.io/react-typescript-sfc/
React アプリケーション(AWS: CloudFront/S3)
準備中。。。
- ランディングページによくある、リンクをクリックすると自動スクロールされる仕組み。
- トップページの先頭に戻るボタンを表示(スクロールをトリガーにする)。
- Desktop 用の画面では、ナビゲーションをページ上部に表示させる。
- Mobile 用の画面では、ナビゲーションをページ下部に表示させる(指で押しやすいため)。
準備中。
参考資料
経年劣化に耐える ReactComponent の書き方
準備中。
npx create-react-app react-typescript-sfc --template typescript
Adding TypeScript
https://create-react-app.dev/docs/adding-typescript/
相対パスだと、リファクタリングによってコンポーネントの配置を変更した場合に、インポート先もすべて変更する必要が出てくる。絶対パスを指定することにより、上記の問題を回避する。
設定方法としては、tsconfig.json
に以下の設定を追加するだけ。
{
"compilerOptions": {
"baseUrl": "src"
},
"include": ["src"]
}
例えば、components/Button
を以下のように絶対パスを使ってインポートできるようになる。
import Button from 'components/Button';
おそらく、絶対パスにすると補完が効かなくなるので、さらに、path-intellisense
を拡張機能として追加する。
参考資料
Create React App - Absolute Imports
VS Code: “Cannot find module” from root path
まず、コーディングスタイルを統一するために、ESLint と Prettier の導入を行う。
yarn add -D \
eslint @types/eslint \
prettier @types/prettier \
@typescript-eslint/eslint-plugin \
@typescript-eslint/parser \
eslint-config-airbnb \
eslint-config-prettier \
eslint-plugin-import \
eslint-plugin-react \
eslint-plugin-react-hooks
eslint-plugin-jsx-a11y \
eslint-plugin-jest \
eslint-plugin-prefer-arrow \
eslint-plugin-mdx \
eslint-plugin-prettier \
@types/eslint-plugin-prettier
以下の各種設定を 設定ファイル .eslitrc.js
に記述する。デフォルトの .eslitrc
の JSON ファイルの場合、キーにいちいちダブルクオーテーションをつけないといけないので、JSファイル
にしたほうが書きやすいと思う。
AirBnb が提供する ESLint の有名な共通設定を導入する。
eslint-config-airbnb
を導入する際、以下のパッケージが必要になる。
- eslint
- eslint-plugin-import
- eslint-plugin-react
- eslint-plugin-react-hooks
- eslint-plugin-jsx-a11y
- @typescript-eslint/parser
eslint-config-airbnb の導入
https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb#eslint-config-airbnb-1
eslint-plugin-react
は React 固有の lint の設定を追加するためのプラグイン。使用するために、extends
と plugins
に設定を追加する。
extends: [
'eslint:recommended',
'plugin:react/recommended',
],
plugins: [
'react'
],
また、React のバージョンを自動的に特定するために、detect
の設定を行う(将来的に、detect
がデフォルトになる予定なので、いずれ設定する必要がなくなる)。
settings: {
react: {
version: 'detect',
},
}
さらに、JSX のサポート(ESLint 2+)を追加するために、
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
eslint-plugin-react の設定
https://github.com/yannickcr/eslint-plugin-react#configuration
eslint-plugin-react-hooks
は、React Hook に対する lint を設定するためのプラグイン。マニュアル設定を適応する場合、以下のように設定する。
plugins: [
"react-hooks"
],
rules: {
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'error',
},
eslint-plugin-import
は ES2015+ (ES6+) import/export syntax の lint に使われる。
デフォルトではすべてのルールが無効化されているので、extends
内でプラグインの設定を行うか、
extends: [
'eslint:recommended',
'plugin:import/errors',
'plugin:import/warnings',
],
個別にルールを rules
内に書き込む必要がある(両方、設定することも可能)。
plugins: [
'import',
],
rules: {
'import/extensions': [
'error',
'always',
{
js: 'never',
jsx: 'never',
ts: 'never',
tsx: 'never',
},
],
'import/prefer-default-export': 'off',
}
また、TypeScript を使っている場合は、次の設定を追加する必要がある。このとき、@typescript-eslint/parser
パッケージが依存パッケージに含める必要がある。
extends: [
'eslint:recommended',
'plugin:import/errors',
'plugin:import/warnings',
'plugin:import/typescript', // 追加
],
eslint-plugin-import のインストール方法
https://github.com/benmosher/eslint-plugin-import#installation
ルールを適応するファイルを以下のように指定する。import/resolver
では、src
ディレクトリ以下の ts
や tsx
などの拡張子を持つファイルのみを対象とする。
settings: {
'import/resolver': {
node: {
extensions: ['.js', 'jsx', '.ts', '.tsx'],
paths: ['src'],
},
},
}
また、import/parsers
を使うことで、対象のファイルに対して、指定した parser を使用することができる。以下では、ts
や tsx
の拡張子を持つファイルに対して、TypeScript 用の parser を使うように設定している。
settings: {
'import/parsers': {
'@typescript-eslint/parser': ['.ts', '.tsx'],
},
}
eslint-plugin-import の設定
https://github.com/benmosher/eslint-plugin-import#settings
eslint-plugin-jsx-a11y
は Web アクセシビリティに関する lint を行うためのプラグイン。plugins
で以下のように設定する。
"plugins": [
"jsx-a11y",
]
推奨設定を適応する場合、以下のように設定する。
extends: [
'plugin:jsx-a11y/recommended',
]
eslint-plugin-jsx-a11y の使い方
https://github.com/evcohen/eslint-plugin-jsx-a11y#usage
eslint-plugin-jest
は Jest に対する lint を行うためのプラグイン。以下では、推奨設定とスタイルを強制する設定を示した。
extends: [
'plugin:jest/recommended',
'plugin:jest/style',
],
plugins: [
'jest',
],
また、Jest が提供するグローバル変数をホワイトリストに追加するために、以下のように設定を行う。
env: {
'jest/globals': true,
},
eslint-plugin-jest の使い方
https://github.com/jest-community/eslint-plugin-jest#usage
eslint-plugin-prefer-arrow
はアロー関数に関する lint を行うためのプラグイン。以下のように設定を行う。
plugins: [
'prefer-arrow',
],
rules: {
'prefer-arrow/prefer-arrow-functions': [
'error',
{
disallowPrototype: true,
singleReturnOnly: true,
classPropertiesAllowed: false,
},
],
}
eslint-plugin-prefer-arrow の使い方
https://github.com/TristonJ/eslint-plugin-prefer-arrow#installations
eslint-plugin-mdx
は MDX ファイル(JSX/TSX 内に markdown ファイルがかけるようにした拡張構文)を lint するためのプラグイン。以下のように設定を行う。
{
extends: ["plugin:mdx/recommended"]
}
eslint-plugin-mdx の使い方
https://github.com/mdx-js/eslint-mdx#install
TypeScript で型の情報を必要とする場合は、必須の設定。
parserOptions: {
project: './tsconfig.json',
}
@typescript-eslint/parser の使い方
https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser#parseroptionsproject
@typescript-eslint/eslint-plugin
は TypeScript の lint を行うためのプラグイン。@typescript-eslint/parser
がインストールされていることが前提。推奨設定は以下のように設定を行う。
extends: [
'plugin:import/typescript',
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
],
parser: '@typescript-eslint/parser',
plugins: [
'@typescript-eslint',
],
rules: {
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-member-accessibility': 'off',
indent: 'off',
'@typescript-eslint/indent': 'off',
'@typescript-eslint/no-unnecessary-type-assertion': 'error',
}
@typescript-eslint/eslint-plugin の使い方
https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#usage
eslint-plugin-prettier
は Prettier と ESLint を連携させるためのプラグイン。推奨設定は以下のように設定を行う。また、他のプラグインと連携を行うことできる。
extends: [
'plugin:prettier/recommended',
'prettier/react',
'prettier/standard',
],
マニュアルで設定を変更する場合は、以下のように設定を行う。
extends: [
'prettier',
],
plugins: [
'prettier',
],
rules: {
'prettier/prettier': 'error',
}
eslint-plugin-prettier の使い方
https://github.com/prettier/eslint-plugin-prettier#recommended-configuration
連携できる ESLint プラグインの一覧
https://github.com/prettier/eslint-config-prettier/blob/master/README.md#installation
Styled-components に Stylelint と Prettier を導入する。ただし、Styled-components の場合、--fix
オプションを使うことができないため、自動で修正することは不可能(問題箇所の検知のみ可能)。
yarn add -D \
stylelint \
@types/stylelint \
stylelint-processor-styled-components \
stylelint-config-styled-components \
stylelint-config-recommended \
stylelint-config-prettier
.stylelintrc
ファイルを作成して、以下の Styled-components の設定を追加する。
{
"processors": ["stylelint-processor-styled-components"],
"extends": [
"stylelint-config-recommended",
"stylelint-config-styled-components"
]
}
Styled-components tooling
https://styled-components.com/docs/tooling#stylelint
Prettier と競合するルールを排除する。
{
"extends": ["stylelint-config-prettier"]
}
stylelint-config-prettier の使い方
https://github.com/prettier/stylelint-config-prettier#installation
yarn add husky lint-staged
lint-staged
を使うことで、staged git ファイルのみに対して lint をコマンドで実行することができる。
{
"lint-staged": {
"src/**/*.{js,jsx,ts,tsx}": ["eslint --fix", "git add"]
}
}
lint-staged の使い方
https://github.com/okonet/lint-staged#configuration
husky
は git での commit・push の前に実行するコマンドを設定できる。ここでは、lint-staged
と合わせて使用し、コミット時に lint が実行されるように設定する。package.json
を以下のように設定する。
// package.json
{
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
}
}
Husky の使い方
https://github.com/typicode/husky#install
yarn add redux react-redux @types/redux @types/react-redux
React Redux - Quick Start
https://react-redux.js.org/introduction/quick-start
Redux - Configuring Your Store
https://redux-docs.netlify.com/recipes/configuring-your-store/
Using combineReducers
https://redux-docs.netlify.com/recipes/structuring-reducers/using-combinereducers
yarn add react-router-dom @types/react-router-dom
React Router - Quick Start
https://reacttraining.com/react-router/web/guides/quick-start
デフォルトの設定では、画面遷移時に前のページのスクロール位置が残ってしまい、ページの最上部から表示されない問題が発生する。
以下の設定を追加し、問題を解消する必要がある。
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
export default function ScrollRestoration() {
const { pathname } = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);
return null;
}
import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import ScrollRestoration from 'components/Common/ScrollRestoration';
function App() {
return (
<Router>
<ScrollToTop />
<App />
</Router>
);
}
React Router - Scroll Restoration
https://reacttraining.com/react-router/web/guides/scroll-restoration
React Router - Redux Integration
https://reacttraining.com/react-router/web/guides/redux-integration
createGlobalStyle
https://styled-components.com/docs/api#createglobalstyle
yarn add @material-ui/core @material-ui/icons
Material-UI のインストール
https://material-ui.com/getting-started/installation/
CSS インジェクションの順番を、Styled-components が最も優先されるように指定する。
ルートコンポーネントをラップする形で、StylesProvider
コンポーネントを使用し、プロパティに injectFirst
を指定することで、Styled-components を最も優先するように設定できる。
import { StylesProvider } from '@material-ui/core/styles';
ReactDOM.render(
<StylesProvider injectFirst>
<App />
</StylesProvider>,
document.getElementById('root'),
);
Controlling priority
https://material-ui.com/guides/interoperability/#controlling-priority-%EF%B8%8F-3
injectFirst
https://material-ui.com/styles/advanced/#injectfirst
Material-UI の ThemeProvider
を用いて、カスタムテーマを対象のコンポーネントに適応する。このとき、Styled-components でも、Material-UI のカスタムテーマを使うために、ThemeProvider
を併用する。
モジュール名が同じため、以下のように、Material-UI の ThemeProvider
を MaterialThemeProvider
、Styled-components の ThemeProvider
を StyledThemeProvider
と定義する。
import { ThemeProvider as MaterialThemeProvider } from '@material-ui/styles';
import { ThemeProvider as StyledThemeProvider } from 'styled-components';
ReactDOM.render(
<MaterialThemeProvider theme={theme}>
<StyledThemeProvider theme={theme}>
<App />
</StyledThemeProvider>
</MaterialThemeProvider>,
document.getElementById('root'),
);
カスタムテーマを使用する場合は、以下のように props
からアクセスできる。ただし、上記の設定のみだと、TypeScript の場合、theme の型が any
になってしまう。
import { AppBar } from '@material-ui/core';
import styled from 'styled-components';
const StyledAppBar = styled(AppBar)`
background-color: ${props => props.theme.palette.primary.main};
`;
そこで、Styled-components の TypeScript の型を拡張する。具体的には、Material-UI の Theme を継承した、DefaultTheme
を新たに定義する。ファイル名は、styled.d.ts
とする。
DefaultTheme
は props.theme
のインターフェースとして使用される。デフォルトでは、DefaultTheme
は未定義なので、Material-UI の Theme を継承して、カスタムテーマの型を定義している。
// import original module declarations
import 'styled-components';
import { Theme } from '@material-ui/core';
// and extend them!
declare module 'styled-components' {
export interface DefaultTheme extends Theme {} // eslint-disable-line
}
ESLint のせいで、interface の中身が空の場合、エラーとなるため、// eslint-disable-line
を指定して、ESLint を無視する(あくまで例外的な処置)。
これにより、VSCode 上で補完が効くようになる。
参考資料
Material-UI のテーマのカスタマイズ
Material-UI のカスタムテーマをコンポーネントに適応する方法
How to use Material-UI theme with styled-components?
Styled-components で TypeScript の型定義ファイルを設定する
Material-UI と styled components のテーマの共通化
React.cloneElement
を使って、子コンポーネントに elevation
を props
として渡す。
カスタム Hook である useScrollTrigger
を使うことで、スクロールをトリガーとして、対象のコンポーネント(ヘッダーなど)を上部に配置する(デフォルトで elevation の値が 4
であり、スクロール時にこれを 0
にすることで、対象のコンポーネントが上部に固定される)。
import React from 'react';
import { useScrollTrigger } from '@material-ui/core';
interface ScrollProps {
children: React.ReactElement;
}
export default function ElevationScroll(props: ScrollProps) {
const { children } = props;
const trigger = useScrollTrigger({
disableHysteresis: true,
threshold: 0,
});
return React.cloneElement(children, {
elevation: trigger ? 4 : 0,
});
}
参考資料
Material-UI - Elevate App Bar
React - cloneElement()
innerWidth |xs sm md lg xl
|--------|--------|--------|--------|-------->
width | xs | sm | md | lg | xl
smUp | show | hide
mdDown | hide | show
参考資料
Grid - How it works
Grid API
Mobile 用と Desktop 用で画面の表示を切り替えるのに有用。
// 1. Import Layer
import React from 'react';
import styled from 'styled-components';
import { Hidden } from '@material-ui/core';
import { ContaineredTitle, Title } from './Title';
import { ContaineredScrollButton } from './ScrollButton';
import { ContaineredToDoButton } from './TodoButton';
import { ContaineredApiButton } from './ApiButton';
// 2. Types Layer
type Props = {
className?: string;
};
// 3. DOM Layer
const LeftSide: React.FC<Props> = props => {
const { className } = props;
return (
<div className={className}>
{/* For mobile */}
<Hidden mdUp>
<Title />
</Hidden>
{/* For Desktop */}
<Hidden smDown>
<ContaineredTitle />
<ContaineredScrollButton />
<ContaineredToDoButton />
<ContaineredApiButton />
</Hidden>
</div>
);
};
// 4. Style Layer
export const StyledLeftSide = styled(LeftSide)`
display: flex;
`;
export default StyledLeftSide;
Material-UI - Hidden
https://material-ui.com/components/hidden/#breakpoint-up
ScrollTop コンポーネント
// 1. Import Layer
import React from 'react';
import styled from 'styled-components';
import { useScrollTrigger, Zoom } from '@material-ui/core';
type ContainerProps = {
children: React.ReactElement;
};
type Props = {
className?: string;
trigger: boolean;
handleClick: (event: React.MouseEvent<HTMLDivElement>) => void;
} & ContainerProps;
// 3. DOM Layer
const ScrollTop: React.FC<Props> = props => {
const { className, children, trigger, handleClick } = props;
return (
<>
<Zoom in={trigger}>
<div className={className} onClick={handleClick} role="presentation">
{children}
</div>
</Zoom>
</>
);
};
// 4. Style Layer
export const StyledScrollTop = styled(ScrollTop)`
position: fixed;
bottom: ${props => props.theme.spacing(2)}px;
right: ${props => props.theme.spacing(2)}px;
`;
// 5. Container Layer
export const ContaineredScrollTop: React.FC<ContainerProps> = props => {
const trigger = useScrollTrigger({
disableHysteresis: true,
threshold: 100,
});
const handleClick = (event: React.MouseEvent<HTMLDivElement>) => {
// TODO: アンカーに`id="#back-to-top-anchor"`を設定する必要あり。
const anchor = (
(event.target as HTMLDivElement).ownerDocument || document
).querySelector('#back-to-top-anchor');
if (anchor) {
anchor.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
};
return (
<StyledScrollTop {...props} trigger={trigger} handleClick={handleClick} />
);
};
export default ContaineredScrollTop;
ScrollTopButton コンポーネント
// 1. Import Layer
import React from 'react';
import styled from 'styled-components';
import { ContaineredScrollTop } from 'components/Common/ScrollTop';
import { Fab } from '@material-ui/core';
import KeyboardArrowUpIcon from '@material-ui/icons/KeyboardArrowUp';
// 2. Types Layer
type Props = {
className?: string;
};
// 3. DOM Layer
const ScrollTopButton: React.FC<Props> = props => {
const { className } = props;
return (
<div className={className}>
<ContaineredScrollTop {...props}>
<Fab color="primary" size="small" aria-label="scroll back to top">
<KeyboardArrowUpIcon />
</Fab>
</ContaineredScrollTop>
</div>
);
};
// 4. Style Layer
export const StyledScrollTopButton = styled(ScrollTopButton)``;
export default StyledScrollTopButton;
使用例
// 1. Import Layer
import React from 'react';
import styled from 'styled-components';
import { StyledScrollTopButton } from 'components/Common/ScrollTop/ScrollTopButton';
import { Menu } from './components/Menu';
import { Contents } from './components/Contents';
// 2. Types Layer
type Props = {
className?: string;
};
// 3. DOM Layer
const App: React.FC<Props> = props => {
const { className } = props;
return (
<Router>
<div className={className}>
<Menu />
{/* Anchor for ScrollToTop */}
<div id="back-to-top-anchor" />
<Contents />
{/* ScrollToTop Button */}
<StyledScrollTopButton />
</div>
</Router>
);
};
// 4. Style Layer
const StyledApp = styled(App)`
background-color: #282c34;
font-size: calc(10px + 2vmin);
color: white;
`;
export default StyledApp;
Material-UI - Back to top
MDN - Element.scrollIntoView()
yarn add react-helmet @types/react-helmet
メタ情報やタイトルなどをヘッダー情報として追加することができる。
// 1. Import Layer
import React from 'react';
import { Helmet } from 'react-helmet';
// 2. Types Layer
type Props = {};
// 3. DOM Layer
export const Header: React.FC<Props> = () => {
return (
<>
<Helmet>
<meta charSet="utf-8" />
<title>React & TypeScript SFC - TopPage</title>
<link
rel="GitHub"
href="https://github.com/Imamachi-n/react-typescript-sfc"
/>
</Helmet>
</>
);
};
React Helmet の使い方
https://github.com/nfl/react-helmet#example
以下のコマンドを実行すると、Storybook を動かすのに必要なパッケージやファイル・コマンド群をすべて自動で用意してくれる(TypeScript への対応もやってくれるため、他に設定はいらない)。
npx -p @storybook/cli sb init --type react_scripts
.storybook/main.js
ファイルを以下の通り書き換える。.js
を .(js|jsx|ts|tsx)
に変更するだけ。
module.exports = {
stories: ['../src/**/*.stories.(js|jsx|ts|tsx)'],
addons: [
'@storybook/preset-create-react-app',
'@storybook/addon-actions',
'@storybook/addon-links',
],
};
参考文献
Storybook - Storybook for React
Storybook - TypeScript Config
ここでは、Component Story Format (CSF)
での記述方法を説明する。
以下に例を示す。
import React from 'react';
import { action } from '@storybook/addon-actions';
import { StyledBottomNavi } from 'components/BottomNavigation';
export default {
title: 'BottomNavi',
component: StyledBottomNavi,
};
export const BottomNavi = () => (
<StyledBottomNavi
handleClick4Home={action('Home')}
handleClick4Scroll={action('Scroll')}
handleClick4Todo={action('Todo')}
handleClick4Api={action('Api')}
/>
);
export default
プロパティ | 説明 |
---|---|
tille | サイドメニューに表示されるタイトル(詳細は下記参照)。 |
component | 対象のコンポーネントを指定。 |
タイトルは、以下のように変換される。
name -> 'Name'
someName -> 'Some Name'
someNAME -> 'Some NAME'
some_custom_NAME -> 'Some Custom NAME'
someName1234 -> 'Some Name 1234'
someName1_2_3_4 -> 'Some Name 1 2 3 4'
export
あとは、表示させたいコンポーネントを export
するだけ。表示されるコンポーネント名は、export
したときの変数名で決まる(タイトル名の変換は上記と同様)。
参考資料
Storybook - Component Story Format (CSF)
以下のコマンドを実行して、Storybook Docs のアドオンをインストールする。
yarn add -D @storybook/addon-docs
Storybook の設定ファイル .storybook/main.js
に以下の設定を追加する。
module.exports = {
stories: ['../src/**/*.stories.(js|jsx|ts|tsx|mdx)'],
addons: ['@storybook/addon-docs'],
};
以下に例を示す。
import { Meta, Story, Preview } from '@storybook/addon-docs/blocks';
import { action } from '@storybook/addon-actions';
import { StyledBottomNavi } from 'components/BottomNavigation';
<Meta title="MDX/BottomNavi" component={StyledBottomNavi} />
# Bottom Navi
With `MDX` we can define a story for `BottomNavi` right in the middle of our
markdown documentation.
<Preview>
<Story name="Botom Navi">
<StyledBottomNavi
handleClick4Home={action('Home')}
handleClick4Scroll={action('Scroll')}
handleClick4Todo={action('Todo')}
handleClick4Api={action('Api')}
/>
</Story>
</Preview>
<Meta>
タグ
属性 | 説明 |
---|---|
title | サイドメニューに表示されるコンポーネント名を記載。/ で区切ることで階層も表現できる。 |
component | 対象のコンポーネントを指定 |
<Preview>
タグ
属性 | 説明 |
---|---|
withSource | ソースコードをデフォルトで表示させるかどうか(open/closed)。 |
<story>
タグ
属性 | 説明 |
---|---|
name | サイドメニューに表示されるコンポーネント名。 |
このタグ内に、表示させたいコンポーネントを追加する。
参考資料
Storybook Docs - インストール方法
Storybook Docs MDX
Storybook の新しいアドオン addon-docs がいい感じ
以下のコマンドを実行して、Storybook Deployer をインストールする。
yarn add -D @storybook/storybook-deployer
package.json
ファイルに以下のコマンドを追加する。
{
"scripts": {
"deploy-storybook": "storybook-to-ghpages"
}
}
以下のコマンドを実行して、GitHub Pages へ Storybook をデプロイする。
yarn deploy-storybook
GitHub Settings の GitHub Pages の項目で、gh-pages
ブランチを使って、静的 HTML ファイルをデプロイする設定になっていることを確認。
参考資料
Storybook Deployer - インストール方法
docker/node/Dockerfile
を用意する。
FROM node:12.16.1-alpine3.11
WORKDIR /usr/src/app
docker-compose.yml
ファイルを用意する。
version: '3'
services:
web:
build:
context: ./docker/node
dockerfile: Dockerfile
volumes:
- ./:/usr/src/app
command: sh -c "yarn start"
ports:
- '3000:3000'
package.json
ファイルに以下を追加する。
{
"scripts": {
"docker:build": "docker-compose build",
"docker:install": "docker-compose run --rm web sh -c 'yarn install'",
"docker:run": "docker-compose up",
"docker:stop": "docker-compose down"
}
}
yarn docker:build
で Docker コンテナをビルドする。
yarn docker:install
で Docker コンテナ内でyarn install
を実行する(少なくとも、Docker for MacOS では遅くて使い物にならない…。10 数分かかる…)。
yarn docker:run
で Docker コンテナを起動する。
yarn docker:stop
で Docker コンテナを停止する。
Docker 環境内で create-react-app
https://qiita.com/mii288/items/aac597bc02575831ea90
- VSCode 上で、
command + shift
でコマンドパレットを開く。 Extensions: Configure Recommended Extensions (Workspace Folder)
を実行する。.vscode/extensions.json
ファイルが作成される。- 以下の図のように、拡張機能の略称をリストアップする。
"recommendations": [
"equinusocio.vsc-material-theme",
],
VSCode - Workspace recommended extensions
https://code.visualstudio.com/docs/editor/extension-gallery#_workspace-recommended-extensions
.vscode/settings.json
内に設定を書き込むことで、書き込んだ設定を対象のプロジェクトで使うことができる。
ファイルの保存を行ったときに、ESLint の修正が実行されるように設定する。
{
"editor.codeActionsOnSave": { "source.fixAll.eslint": true },
"editor.formatOnSave": true
}
Create React App をアップデートする場合、Change Log に書かれているマイグレーション用のコマンドを実行すること。
Updating to New Releases
https://create-react-app.dev/docs/updating-to-new-releases/
Storybook をアップデートする場合、Migration に記載されている内容をもとにマイグレーションを行う。
Storybook v5 以降、TypeScript へのデフォルト対応などを始めとするプリセット周りの整備が進み、更新頻度が高め。
以下のコマンドを実行することで、すべての依存パッケージのアップグレードを行うことができる。
yarn upgrade
Upgrade for Minor or Patch Releases
https://www.gatsbyjs.org/docs/upgrade-gatsby-and-dependencies/