Create React App + TypeScript + SCSS 環境を構築してみる
2016年に create-react-app 単体で試したことがあった。
あれから3年半が経過。React がもてはやされていた中で「Angular はちょっと重たいよねー」「とはいえ React も難解になってきたよねー」とか言っていると Vue.js の手軽さで SPA 全体が完全に主流になったと思う。Next.js や Nuxt.js、Angular CLI などの発展で、統一感のある CLI に沿った開発環境というのも安定してきたと思う。
そして何より、TypeScript を使った開発というのが、もはや「モダン」でもなんでもない「スタンダード」にすらなったかなと思う。
以前の記事では TypeScript などを試さなかったので、今回は最新の Create React App をベースに、TypeScript + SCSS を使った環境を作ってみる。そこで遭遇したトラブルも記録するのでご参考までに。
目次
- Create React App でプロジェクトの雛形を作る
- SCSS を書けるようにする
- Linux 環境で
npm start
実行時に「System limit for number of file watchers reached」エラーが出た package.json
にhomepage
プロパティを指定するとnpm start
が正常に動作しなくなる- ビルドしたモノを動かす
npm start
時とnpm run build
時とでhomepage
を変えたい- Service Worker を使わない場合は完全削除して良い
- Component クラスの関数はアロー関数で書くとよさげ
- 条件付きレンダ
- kuromoji を使う
- ts-node のコンパイラオプションを上書きする
- 以上
Create React App でプロジェクトの雛形を作る
npm の npx
コマンドを使えば、create-react-app
のグローバルインストールは不要。もちろん、事前に $ npm i -g create-react-app
としても問題はない。
# 以下のコマンドで雛形を作成する
$ npx create-react-app example-my-app --use-npm --typescript
Yarn が別に好きではないので、個人的な趣味で npm を使う --use-npm
オプションを設定。
TypeScript ベースのプロジェクトにするため --typescript
オプションを付けたが、ワーニングで「今後は --template typescript
オプションを使え」と出ていた。今後は
$ npx create-react-app example-my-app --use-npm --template typescript
が雛形作成コマンドになるな。
$ cd ./example-my-app/
$ npm start
プロジェクトを作成したら、上のようにすることで http://localhost:3000/
に簡易サーバが起動する。
- 参考 : 新しい React アプリを作る – React … 公式
- 参考 : Create React AppでパッケージマネージャーにYarnではなくnpmを使用する方法 | 綺麗に死ぬITエンジニア … 標準の Yarn の代わりに npm を使う
SCSS を書けるようにする
上述のように TypeScript ベースのプロジェクトを作っても、CSS 周りは標準的な CSS しかサポートされていない。
SCSS を書けるようにするには、node-sass
をインストールしておくだけで良い。とてもお手軽!
$ npm install --save node-sass
で node-sass
をインストールするだけ。
あとは index.css
や App.css
の拡張子を .scss
にリネームし、import
部分も .css
から .scss
に直せば、自動的に SCSS のコンパイルを行って動作してくれるようになる。
Linux 環境で npm start
実行時に「System limit for number of file watchers reached」エラーが出た
Ubuntu 18.04 環境で React プロジェクトを立ち上げたところ、npm start
時に
Error: ENOSPC: System limit for number of file watchers reached,
このようなエラーメッセージが出た。
以下のとおり対応すれば良い。
# inotify が小さいと思われる
$ cat /proc/sys/fs/inotify/max_user_watches
8192
# 上限値を増やす
$ echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
$ sudo sysctl -p
コレで npm start
してもエラーが出なくなる。
package.json
に homepage
プロパティを指定すると npm start
が正常に動作しなくなる
npm init
で package.json
を生成すると、homepage
プロパティが記録される。コレに合わせて、Create React App が作った package.json
にも homepage
プロパティを書いた。すると npm start
時に URL の階層構造が狂ってしまった。
どうやら React は package.json
の homepage
プロパティを見てパス解決を調整しているようなので、通常の npm パッケージの感覚でこのプロパティを書かないようにしないといけない。最終的にアプリが動作する URL、例えば GitHub Pages の URL などを書いておくのが適切だろう。
ビルドしたモノを動かす
npm start
による簡易サーバ・ホットリロードではなく、一度ちゃんとビルドして、それを動作させてみる場合。serve
というパッケージを使うのが公式で紹介されていた。
$ npm run build
$ npx serve -s ./build/
# http://localhost:5000/
npm start
時と npm run build
時とで homepage
を変えたい
前述のとおり、package.json
の homepage
プロパティは、npm run build
でビルドした資材を公開する場所に合わせておくことが望ましい。
しかしそれだと、npm start
で開発したい時にこの URL が適用されてしまい、パス解決に不具合が出る場合がある。
その場合は、次のように PUBLIC_URL
環境変数を指定して npm start
を実行すれば良い。
{
"scripts": {
"start": "PUBLIC_URL='.' react-scripts start"
}
}
Service Worker を使わない場合は完全削除して良い
標準だと、index.tsx
より serviceWorker.tsx
がインポートされているが、いきなり有効化されないように、unregister()
としかしていない。
// src/index.tsx 抜粋
import * as serviceWorker from './serviceWorker';
serviceWorker.unregister();
Service Worker を使わないことが確定している場合は、これらの記述をすべて削除し、serviceWorker.tsx
ごと削除しても問題なかった。
Component クラスの関数はアロー関数で書くとよさげ
イマイチ分かっていないのだが、Component クラスに独自に定義する関数について。
export default class App extends React.Component {
// State の型を宣言しておく
state: Readonly<any>;
// 画面から呼び出す予定の関数を定義
onSubmit() {
this.setState({ hoge: 'FUGA' }); // ← コレができない
}
}
上のように、関数を onSubmit() {}
という風に定義し、this.setState()
を呼び出して値を変更しようとすると、なぜか undefined
となってしまう。
this
が解決できていないんだろうなーとは思ったが、何でコレがダメなんだっけ?というのが分かっていない。
とりあず回避するには、
onSubmit() {}
のようにクラスのメソッドとして書くのではなく、onSubmit = () => {}
のようにアロー関数で書いてやると
エラーを回避できる。
export default class App extends React.Component {
// State の型を宣言しておく
state: Readonly<any>;
// 画面から呼び出す予定の関数を定義
onSubmit = () => {
this.setState({ hoge: 'FUGA' }); // ← コレなら OK
}
}
条件付きレンダ
Component の render()
メソッドは、最終的に JSX を return
すれば良いので、return
キーワードを書くまでに if
文を組み合わせてみたりしても良い。状態に応じて大きく HTML 構造が変わる場合は、if
文で処理して複数の return
を書いたりした方がスッキリするかもしれない。
export default class App extends React.Component {
render() {
// ローディング中の HTML
if(this.state.isLoading) {
return (
<div>Loading...</div>
);
}
// ロード完了後の HTML…
return (
<div>…</div>
);
}
}
一方、JSX の中で条件分岐を行いたい場合は、「条件付きレンダ」で書けば良い。
return (
<div>
{ messages.length === 0 &&
<p>表示できるメッセージはありません</p>
}
</div>
);
ブレース {}
内は JavaScript の構文を直接書けるので、JavaScript のイディオムである &&
や ||
の他、三項演算子を組み合わせたりもできる。覚えておこう。
- 参考 : 条件付きレンダー – React
kuromoji を使う
nemui-gacha-js を作った時のメモ。kuromoji
という形態素解析ツールを React 内で使うためにやったこと。
まずはインストール。@types
での型定義もあるので一緒にインストールしておくと良い。
$ npm install -S kuromoji
$ npm install -D @types/kuromoji
同梱の dict/
ディレクトリを、./public/dict/
でアクセスできるように移動しておく。
$ cp -a ./node_modules/kuromoji/dict/ ./public/
そうすれば、次のように書くことで kuromoji が使えるようになる。
import * as kuromoji from 'kuromoji';
kuromoji.builder({
dicPath: './dict' // 予め kuromoji の dict/ ディレクトリを public/ 配下にコピーしておく
}).build((error: Error, tokenizer: kuromoji.Tokenizer<any>) => {
// tokenizer を使って処理…
});
- 参考 : Kuromoji を使ってブラウザ上で形態素解析を行う (Reactあり/なし) - Qiita
- 参考 : https://takumon.com/wordcloud-with-kuromoji-d3cloud-react
ts-node のコンパイラオプションを上書きする
React ベースのプロジェクト内で、ちょっとだけ ts-node
を使って CLI 向けスクリプトを動かしたい場面があった。そんな時、React 向けの tsconfig.json
だと ts-node
が動作しなかった。
調べてみると、次のように環境変数 TS_NODE_COMPILER_OPTIONS
で tsconfig.json
の設定を上書きしてやれば動作した。
$ TS_NODE_COMPILER_OPTIONS='{"module":"commonjs"}' ts-node HOGE.ts
package.json
に定義するならこんな感じ。
{
"scripts": {
"exec-cli": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node HOGE.ts"
}
}
以上
こんな感じ~。TypeScript と SCSS が使えるようにできたので、Angular CLI や Vue CLI と同じく、React も Create-React-App で良い感じですね~。