環境
- mac
- node v10.9.0
まず雛形を作成
- Facebook の提供している、React.js アプリを素早く作成するコマンドラインツール、create-react-app を使う。まずインストール
npm install -g create-react-app
- create-react-app には TypeScript のボイラープレートもあってそれを使ってプロジェクトを生成
create-react-app react-ts-app --scripts-version=react-scripts-ts
とりあえずアプリを実行
yarn start
http://localhost:3000 の URL でブラウザが立ち上がるyarn test
Jest による単体テストyarn build
本番ビルドが ‘./build’ に生成- React 雛形画面が表示された
create-react-app を削除
- create-react-app は非常に便利なのだが、なにをやってるか中身がよくわからないので、
yarn eject
を実行して create-react-app に頼らないプロジェクトにしよう。 yarn eject
を実行すると? Are you sure you want to eject? This action is permanent.
と聞かれるのでY
にしておく。- package.json の
tsConfigFile
が絶対パスになってるので、相対パスに変更する
"globals": {
"ts-jest": {
- "tsConfigFile": "/Users/ユーザー名/workspace/react-ts-app/tsconfig.test.json"
+ "tsConfigFile": "./tsconfig.test.json"
}
}
tslint.json の修正
- tslint の設定を latest に修正
"extends": [
"tslint:latest",
tsconfig.json の修正
- 型定義ファイルの場所
rootDir
をrootDirs
へ変更してtypings
を追加する(typings
には css の型定義を格納する予定)
"rootDirs": ["src", "typings"],
- configディレクトリを除外する
"exclude": [
"node_modules",
"build",
"scripts",
"acceptance-tests",
"webpack",
"jest",
"src/setupTests.ts",
+ "config"
]
Prettier
- Prettier の追加
yarn add -D prettier tslint-plugin-prettier tslint-config-prettier
- tslint.json へ
tslint-config-prettier
を追加する。もしかして勝手に追加されているかも
{
"extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"],
"linterOptions": {
"exclude": [
"config/**/*.js",
"node_modules/**/*.ts",
"coverage/lcov-report/*.js"
]
}
}
CSS Modules with TypeScript
- CSSにも型定義をするやつです。違和感あったが、使ったほうがよさそうです。
yarn add -D typed-css-modules typed-css-modules-loader
- package.json の script に
tcm
の実行を追加して、preのscriptを追加する。 - prestartは、startの前に実行される。prebuildはbuildの前に実行される。これ最近しった。。。
/react-ts-app/package.json
"scripts": {
"tcm": "tcm ./src -c -o ./typings",
"prestart": "yarn run tcm",
"start": "node scripts/start.js",
"prebuild": "yarn run tcm",
"build": "node scripts/build.js",
"pretest": "yarn run tcm",
"test": "node scripts/test.js --env=jsdom"
},
- Webpackの設定を修正
/react-ts-app/config/webpack.config.dev.js
use: [
require.resolve("style-loader"),
{
loader: require.resolve("css-loader"),
options: {
- importLoaders: 1,
+ importLoaders: 2,
+ modules: true,
+ localIdentName: "[name]__[local]___[hash:base64:5]",
+ sourceMap: true
}
},
+ {
+ loader: require.resolve("typed-css-modules-loader"),
+ options: {
+ camelCase: true,
+ searchDir: "./src",
+ outDir: "./typings"
+ }
+ },
{
loader: require.resolve("postcss-loader"),
- 本番も一部追加
/react-ts-app/config/webpack.config.prod.js
{
loader: require.resolve("css-loader"),
options: {
importLoaders: 1,
+ modules: true,
minimize: true,
sourceMap: shouldUseSourceMap
}
},
Storybook
- コンポーネントを管理しやすいのでstorybookを追加する
- storybookの追加
yarn global add @storybook/cli
getstorybook
- TypeScriptで実装するので、設定を修正する。
/react-ts-app/.storybook/config.js
- // automatically import all files ending in *.stories.js
- const req = require.context('../stories', true, /.stories.js$/);
+ // automatically import all files ending in *.stories.tsx or jsx
+ const req = require.context('../src', true, /\.stories\.[jt]sx?$/);
- tsx のストーリーに対しても動くように設定を変える。
yarn add -D @types/storybook__react @types/storybook__addon-actions
- .storybookのWebpackの設定を修正する
/react-ts-app/.storybook/webpack.config.js
const dev = require('../config/webpack.config.dev');
module.exports = {
plugins: [
// your custom plugins
],
module: dev.module,
resolve: dev.resolve,
};
- storybookのファイルはトランスパイルしないよう除外設定を修正
/react-ts-app/config/webpack.config.dev.js
- exclude: [/\.js$/, /\.html$/, /\.json$/],
+ exclude: [/\.js$/, /\.html$/, /\.json$/, /\.ejs$/],
- .gitignore へ
storybook-static
を追加
Storybookの確認のためコンポーネントを作成してみる
- srcの下に
components
ディレクトを作成して以下3つのファイルを作成する
/react-ts-app/src/components/Button.css
.root {
border: 1px solid red;
background-color: gray;
}
.content {
font-size: large;
color: white;
}
.description {
color: red;
}
/react-ts-app/src/components/Button.stories.tsx
import { action } from "@storybook/addon-actions";
import { storiesOf } from "@storybook/react";
import * as React from "react";
import Button from "./Button";
storiesOf("Button", module)
.add("with hello", () => <Button onClick={action("clicked")}>Hello</Button>)
.add("with hey", () => <Button onClick={action("clicked")}>Hey</Button>);
/Users/ka-yamao/workspace/react-ts-app/src/components/Button.tsx
import * as React from "react";
import * as style from "./Button.css";
export default (props: {
children?: string;
onClick(event: React.MouseEvent<HTMLButtonElement>): void;
}) => (
<button className={style.root} onClick={props.onClick}>
<span className={style.content}>{props.children}</span>
<span className={style.description}> I am a button..</span>
</button>
);
- ts-loader が古くて動かなかったので、もう一度追加する。
yarn add ts-loader
"ts-loader": "^5.3.2",
だと動いた。- Storybookで確認してみる
yarn storybook
- http://localhost:6006/ をブラウザで開く
ここまでしたことのソース
https://github.com/ka-yamao/react-ts-app/tree/etc1
参考サイト
React を TypeScript で使う際のツール考察 2018 春
次にしたいこと
- webpack3からwebpack4へバージョンアップ
- typescript-fsa、typesafe-actionsを追加して実装を進める
- redux-sagaの導入
- クロスドメインを気にせず実装したいから、webpackでプロキシの設定をする