はじめに
この記事は React
+ TypeScript
な環境を作成し、Flavor
を設定してビルド環境( Development
, Staging
, Production
)を切り替えられるような Project
を作成することを目的としています。
React + TypeScript 環境の構築
初期設定
サックっと初期設定してしまいましょう。
$ mkdir react-flavor-example
$ cd react-flavor-example
$ npm init
色々聞かれるので、適当に質問に答えましょう。
package name: (app) react-flavor-example
version: (1.0.0)
description:
entry point: (main.tsx) webpack.config.js
test command:
git repository:
keywords:
author: yukitaka13-1110
license: (ISC)
About to write to /app/package.json:
Dependency の追加
React 系
$ npm i -D react react-dom @types/react @types/react-dom
Webpack 系
$ npm i -D webpack webpack-cli webpack-dev-server html-webpack-plugin
TypeScript 系
$ npm i -D typescript ts-loader
tsconfig.json
の作成
{
"compilerOptions": {
"sourceMap": true,
"module": "commonjs",
"esModuleInterop": true,
"resolveJsonModule": true,
"experimentalDecorators": true,
"target": "es5",
"jsx": "react",
"lib": [
"dom",
"es6"
]
},
"include": [
"src"
],
"compileOnSave": true
}
webpack.config.js
の作成
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'development',
entry: './src/main.tsx',
plugins: [
new HtmlWebpackPlugin({
template: 'public/index.html',
}),
],
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
},
],
},
resolve: {
extensions: [
'.ts', '.js', 'tsx',
],
},
};
index.html
の作成
public/
以下に index.html
を作成します。
<html lang="ja">
<body>
<div id="root" />
</body>
</html>
main.tsx
の作成
src/
以下に main.tsx
を作成します。
import * as React from "react";
import * as ReactDOM from "react-dom";
const App: React.FC = () => {
return <div>React Flavor Example</div>
};
ReactDOM.render(<App />, document.getElementById("root"));
この時点でディレクトリ構造が以下のようになっていればOKです。
$ tree ./ -L 2
./
├── node_modules
├── package-lock.json
├── package.json
├── public
│ └── index.html
├── src
│ └── main.tsx
├── tsconfig.json
└── webpack.config.js
package.json
の scripts
にコマンドを追加します。
{
...
"scripts": {
"start": "webpack-dev-server",
"test": "echo \"Error: no test specified\" && exit 1"
},
...
}
npm run start
で起動して http://localhost:8080/
へアクセスして React Flavor Example
という文字が表示されることを確認
Flavor の設定
ここからが本題です。
アプリで利用する環境変数を切り替えたいということは良くあることだと思います。
node.js
では process.env.NODE_ENV
という環境変数を利用することでアプリで利用する環境変数を切り替えることができるようです。
しかし、process.env.NODE_ENV
が staging
を受け取ることができません。型定義を見る感じは受け取れそうですが、どうやらdevelopment
| production
| test
以外は受け付けないようにないっているみたい...。(良く分かっていない)
interface ProcessEnv {
[key: string]: string | undefined;
}
そもそも型定義も貧弱なのでそこも含めて解決します。
process.env
の型を上書きする
process.env
の型を上書きするには、プロジェクト内のどこかに global.d.ts
ファイルを作成し、以下のように書くことで可能です。
/// <reference types="node" />
declare namespace NodeJS {
interface ProcessEnv {
readonly NODE_ENV: 'development' | 'production' | 'test';
readonly FLAVOR: 'development' | 'staging' | 'production';
}
}
NODE_ENV
は触っちゃいけない気がしたので以下のように FLAVOR
を生やしてみました。
その後、package.json
で FLAVOR
を渡す scripts
を追加します。
{
"scripts": {
"start": "webpack-dev-server",
+ "dev": "FLAVOR=\"development\" webpack-dev-server",
+ "stg": "FLAVOR=\"staging\" webpack-dev-server",
+ "prod": "FLAVOR=\"production\" webpack-dev-server",
"test": "echo \"Error: no test specified\" && exit 1"
},
}
渡しただけではアプリ側では受け取れないので、webpack.config.js
で工夫します。
const HtmlWebpackPlugin = require('html-webpack-plugin');
+ const webpack = require('webpack');
+ const flavor = process.env.FLAVOR || 'development';
module.exports = {
mode: 'development',
entry: './src/main.tsx',
plugins: [
new HtmlWebpackPlugin({
template: 'public/index.html',
}),
+ new webpack.DefinePlugin({
+ 'process.env.FLAVOR': JSON.stringify(flavor),
+ })
],
}
main.tsx
に console.log()
を追加してみましょう。
先程、型定義を上書きしたので補完が効くようになっています。
試しに npm run stg
を実行してみましょう。
ちゃんと値を受け取れています。
後は適当に環境毎に変数を定義して process.env.FLAVOR
を使って分岐するだけです。
例えば以下のような config
ディレクトリを用意しておけば良いでしょう。
./src/config
├── development
│ └── index.ts
├── index.ts
├── production
│ └── index.ts
└── staging
└── index.ts
import { EnvVariables } from '../';
const stgVariables: EnvVariables = {
HOGE: 'STAGING_HOGE',
FUGA: 'STAGING_FUGA',
};
export default stgVariables;
import devVariables from './development';
import stgVariables from './staging';
import prodVariables from './production';
export type EnvVariables = {
HOGE: string;
FUGA: string;
};
const envVariables = (): EnvVariables => {
if (process.env.FLAVOR === 'production') {
return prodVariables;
}
if (process.env.FLAVOR === 'staging') {
return stgVariables;
}
return devVariables;
};
export default envVariables();
import * as React from "react";
import * as ReactDOM from "react-dom";
import envVariables from './config' // Add import;
const App: React.FC = () => {
return (
<div>
<div>React Flavor Example</div>
<div>{envVariables.HOGE}</div>
<div>{envVariables.FUGA}</div>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
npm run stg
を実行して http://localhost:8080/
にアクセスします。
ちゃんと値を表示することができました。
終わりに
今回使用したコードはこちらに載せています。
https://github.com/yukitaka13-1110/react-flavor-example