Edited at

TypeScript + React + styled-components + Firestore + Firebase HostingでWebアプリを作り始める

TypeScript, React, styled-components, Cloud Firestore, Firebase Hostingを使ってWebサイトを公開する方法。1

「FirestoreもReactも使ったことない人(筆者もそう)」が

Firestoreに接続するReactアプリを作り、Firebase Hostingにデプロイするまで」を簡潔にまとめました。2


  • VSCodeを使っています

  • 色々な考慮を省略しています


1. Reactプロジェクトの作成


まずは必要なものインストール


firebase-tools

公式のコマンドラインツール

$ npm install -g firebase-tools


create-react-app

Facebook公式。Reactアプリの雛形を生成できる。

$ npm install -g create-react-app


雛形の生成

任意の場所で以下を実行するだけ。

オプション「--scripts-version=react-scripts-ts」により、TypeScriptを使う構成で生成してくれる。

$ create-react-app hoge-react-app --scripts-version=react-scripts-ts


VSCodeの拡張機能や設定

【Prettierについての補足】

上記のプラグインを入れた後、設定に以下を追加するだけで済む。

"[typescriptreact]": {

"editor.formatOnSave": true
},

フォーマットのルールをカスタマイズしたい場合は、.prettierrcを作成して定義すればOK。


.prettierrc.json

{

"singleQuote": true
}


2. Firebase Hostingへのデプロイ


Firebaseプロジェクトの生成

無料で開始」ボタンからプロジェクトを作成する。

Databaseの項目からFirestoreも開始しておく。


ターミナルからFirebaseにログインする

$ firebase login


Reactアプリをfirebase Hostingと接続する 

hoge-react-appディレクトリで以下を実行する

$ firebase init

// 「◯ Hosting: Configure and deploy Firebase Hosting sites」をスペースキーで選んでEnter
// さっき作成したプロジェクトを選んでEnter


firebase.jsonの編集

hostingのpublicを"build"にしておく。


firebase.json

{

"hosting": {
"public": "build",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
}
}


動作確認

$ npm start


deployしてみる

$ npm run build && firebase deploy

ここまでは特に面倒なこともなくスムーズにいける(はず)


3. Firestoreとの接続

こっからが本記事の本番

最終的に↓のようになる。

スクリーンショット 2018-10-22 13.39.50.png


Firestoreのルールを設定する

hoge-react-appディレクトリのルートに、firestore.rulesファイルを新規作成する。

とりあえず、書き込みだけは認証が必要な設定にしてみる。


firestore.rules

service cloud.firestore {

match /databases/{database}/documents {
match /{document=**} {
allow read;
allow write: if request.auth != null;
}
}
}


Firebase関連のコードを追加

srcディレクトリ配下に、firebaseディレクトリを作成し、以下のファイルを新規作成します。

(ディレクトリ名はわかりやすくfirebaseにしただけで、別になんでもいい)

ちょっとこの実装最高に雑ですが...おゆるしを...


firebase/index.tsx

import * as firebase from "firebase/app";

import "firebase/auth";
import "firebase/firestore";
import { FIREBASE_CONFIG } from "./config";

export default class Env {
private static singleInstance: Env;

public readonly firebase: firebase.app.App;
public readonly firestore: firebase.firestore.Firestore;
public readonly providerGoogle = new firebase.auth.GoogleAuthProvider();

private constructor() {
this.firebase = firebase.initializeApp(FIREBASE_CONFIG);
this.firestore = this.firebase.firestore();
const settings = { timestampsInSnapshots: true };
this.firestore.settings(settings);
}

public static get instance(): Env {
if (!this.singleInstance) {
this.singleInstance = new Env();
}
return this.singleInstance;
}
}



firebase/config.tsx

// 以下の情報は、Firebase-consoleから、「+アプリを追加」 > 「 </> 」を選ぶと確認できます。

export const FIREBASE_CONFIG = {
apiKey: 'XXX',
authDomain: 'XXX',
databaseURL: 'XXX',
projectId: 'XXX',
storageBucket: 'XXX',
messagingSenderId: 'XXX'
};


App.tsxの編集

srcディレクトリ配下のApp.tsxを編集し、Firestoreと接続しましょう。3

ボタン2つを配置するだけの単純なものです。


App.tsx

import * as React from "react";

import * as Boostrap from "react-bootstrap";
import "./App.css";
import Env from "./firebase/index";

export default class App extends React.Component {
public render(): JSX.Element {
return (
<div className="App">
<Boostrap.Button onClick={this.handleLogin}>Login</Boostrap.Button>
<Boostrap.Button onClick={this.insertDummyUser}>
firestore test
</Boostrap.Button>
</div>
);
}

private handleLogin = () => {
Env.instance.firebase
.auth()
.signInWithRedirect(Env.instance.providerGoogle);
Env.instance.firebase
.auth()
.getRedirectResult()
.then(result => {
console.log(result);
})
.catch(error => {
console.log(error);
});
};

private insertDummyUser = () => {
Env.instance.firestore
.collection("users")
.doc("dummy_user_1")
.set({
country: "Japan",
name: "dummyUser1"
})
.then(() => {
console.log("Success: Document has written");
})
.catch(error => {
console.error("Error writing document: ", error);
});
};
}



完成

こんな感じになっているはず

スクリーンショット 2018-10-22 13.39.50.png


動作確認

$ npm start

こんな感じの画面が出ます。

スクリーンショット 2018-10-18 16.38.43.png

Loginしていなければ、Firestoreへのコレクション追加が失敗するのを確認しましょう。(デベロッパーツールにエラーが出るはず)

また、Fireabse-consoleから、コレクションの追加を確認しましょう。


deploy!

$ npm run build && firebase deploy


4. CSS in JSをやっていく

 最後に、styled-componentsを導入し、CSSを少し書いてみます。4


まず必要なものインストール

$ npm install --save styled-components

$ npm install @types/styled-components


App.tsxにCSSを追加

styled-componentsのサンプルCSSを参考に、ボタンの色を変えてみます。


App.tsx

import * as React from 'react';

import styled, { css } from 'styled-components';
import './App.css';
import Env from './firebase/index';

export default class App extends React.Component {
public render() {
return (
<div className="App">
<Button onClick={this.handleLogin}>Login</Button>
<Button primary={true} onClick={this.insertDummyUser}>
firestore test
</Button>
</div>
);
}

private handleLogin = () => {
Env.instance.firebase
.auth()
.signInWithRedirect(Env.instance.providerGoogle);
Env.instance.firebase
.auth()
.getRedirectResult()
.then(result => {
console.log(result);
})
.catch(error => {
console.log(error);
});
};

private insertDummyUser = () => {
Env.instance.firestore
.collection('users')
.doc('dummy_user_1')
.set({
country: 'Japan',
name: 'dummyUser1'
})
.then(() => {
console.log('Success: Document has written');
})
.catch(error => {
console.error('Error writing document: ', error);
});
};
}

// styled-components
interface InterfaceMyProps {
primary?: boolean;
onClick: () => void;
}

const StyledButton = styled.button`
background: transparent;
border-radius: 3px;
border: 2px solid palevioletred;
color: palevioletred;
margin: 0 1em;
padding: 0.25em 1em;

${(props: InterfaceMyProps) =>
props.primary &&
css`
background: palevioletred;
color: white;
`
};
`
;

const Button: React.SFC<InterfaceMyProps> = ({ ...props }) => (
<StyledButton {...props} />
);


ちょっとここらへん強引な感がある...悩


完成

スクリーンショット 2018-10-20 17.08.23.png

あとはdeployするなり。





  1. 最初はGAE/GoとFirestoreで書いていましたが、とある重要なことにデプロイして初めて気づきました。 



  2. TypeScript + Reactについては、公式ドキュメントこの記事が分かりやすい。 



  3. このコードはPrettierの自動フォーマットに従ったままです。 



  4. 公式ドキュメントstyled-componentsを使ったCSS設計React + Storybook + styled-componentsをTypeScriptで動かすなどを参考にしました。