3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

React + TypeScript 環境構築 + ビルド環境を Flavor で切り替える (not create-react-app)

Last updated at Posted at 2020-07-13

はじめに

この記事は 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 の作成

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 の作成

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 を作成します。

public/index.html
<html lang="ja">
  <body>
    <div id="root" />
  </body>
</html>

main.tsx の作成

src/ 以下に 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.jsonscripts にコマンドを追加します。

package.json
{
  ...
  "scripts": {
    "start": "webpack-dev-server",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  ...
}

npm run start で起動して http://localhost:8080/ へアクセスして React Flavor Example という文字が表示されることを確認

スクリーンショット 2020-07-14 01.19.36.png

Flavor の設定

ここからが本題です。
アプリで利用する環境変数を切り替えたいということは良くあることだと思います。
node.js では process.env.NODE_ENV という環境変数を利用することでアプリで利用する環境変数を切り替えることができるようです。
しかし、process.env.NODE_ENVstaging を受け取ることができません。型定義を見る感じは受け取れそうですが、どうやらdevelopment | production | test 以外は受け付けないようにないっているみたい...。(良く分かっていない)

@types/node
interface ProcessEnv {
    [key: string]: string | undefined;
}

そもそも型定義も貧弱なのでそこも含めて解決します。

process.env の型を上書きする

process.env の型を上書きするには、プロジェクト内のどこかに global.d.ts ファイルを作成し、以下のように書くことで可能です。

src/types/global/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.jsonFLAVOR を渡す scripts を追加します。

package.json
{
  "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 で工夫します。

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.tsxconsole.log() を追加してみましょう。
先程、型定義を上書きしたので補完が効くようになっています。

スクリーンショット 2020-07-14 01.56.01.png

試しに npm run stg を実行してみましょう。
ちゃんと値を受け取れています。

スクリーンショット 2020-07-14 01.57.50.png

後は適当に環境毎に変数を定義して process.env.FLAVOR を使って分岐するだけです。
例えば以下のような config ディレクトリを用意しておけば良いでしょう。

./src/config
├── development
│   └── index.ts
├── index.ts
├── production
│   └── index.ts
└── staging
    └── index.ts
staging/index.ts
import { EnvVariables } from '../';

const stgVariables: EnvVariables = {
  HOGE: 'STAGING_HOGE',
  FUGA: 'STAGING_FUGA',
};

export default stgVariables;
index.ts
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();
src/main.tsx
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/ にアクセスします。

スクリーンショット 2020-07-14 02.22.48.png

ちゃんと値を表示することができました。

終わりに

今回使用したコードはこちらに載せています。
https://github.com/yukitaka13-1110/react-flavor-example

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?