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の拡張機能や設定
- Firebase
- TSlint : tslintとtslint-reactを参考に設定する
- TypeScript Hero: importの自動修正
- styled-components
- Prettier
【Prettierについての補足】
上記のプラグインを入れた後、設定に以下を追加するだけで済む。
"[typescriptreact]": {
"editor.formatOnSave": true
},
フォーマットのルールをカスタマイズしたい場合は、.prettierrc
を作成して定義すればOK。
{
"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"にしておく。
{
"hosting": {
"public": "build",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
}
}
動作確認
$ npm start
deployしてみる
$ npm run build && firebase deploy
ここまでは特に面倒なこともなくスムーズにいける(はず)
3. Firestoreとの接続
Firestoreのルールを設定する
hoge-react-app
ディレクトリのルートに、firestore.rules
ファイルを新規作成する。
とりあえず、書き込みだけは認証が必要な設定にしてみる。
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read;
allow write: if request.auth != null;
}
}
}
Firebase関連のコードを追加
srcディレクトリ配下に、firebase
ディレクトリを作成し、以下のファイルを新規作成します。
(ディレクトリ名はわかりやすくfirebase
にしただけで、別になんでもいい)
ちょっとこの実装最高に雑ですが...おゆるしを...
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-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つを配置するだけの単純なものです。
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);
});
};
}
完成
動作確認
$ npm start
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を参考に、ボタンの色を変えてみます。
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} />
);
ちょっとここらへん強引な感がある...悩
完成
あとはdeployするなり。
-
最初はGAE/GoとFirestoreで書いていましたが、とある重要なことにデプロイして初めて気づきました。 ↩
-
このコードはPrettierの自動フォーマットに従ったままです。 ↩
-
公式ドキュメントやstyled-componentsを使ったCSS設計、React + Storybook + styled-componentsをTypeScriptで動かすなどを参考にしました。 ↩