あさた研メモ

主に私が気づいたこととか困った時のメモとか書き留めとく用。

自分のホームページを作った話

概要

紆余曲折を経て、自分の音楽活動用のホームページを作った。
https://www.asatake.com

その苦労した箇所を適当に書きなぐっておく。

事の発端

流石にTwitterだけじゃ自分の今までの活動をまとめきれないと思い、 せっかく技術的にアプローチできるのだから自サイトを立ち上げることを決意した。

あと流行りの技術とか使ってみたかったので、いいきっかけだった。

使用技術

frontend

React.js + Material-UI

どこの勉強会いってもReactがVueの話が出てくるので、せっかくだし使ってみようと思って1から勉強。

せっかくだしついででTypescriptで書くことを決意。

backend

まだガワしか作ってないからAPIもクソもないが、そのうち作る。 じゃないと機能拡大ができない。

いまのところElixir(Phoenix)かNode使うかって考えている。

DevOps

Travis-CIによるテスト&デプロイを利用。 ここが一番大変だった。後述。

苦労したところ・わからないところ

React.js

そもそもちゃんとjsとかts書いたことなかったので、かなり基礎的なところを書きながら勉強した。

結局 create-react-apps があったので、これを利用して開発を開始。

未だに正解がわからないが、コンポーネントとかstateの管理とかは「それっぽく」動くようになった。

Typescriptで書くチュートリアルがないため、しょっちゅうエラーをはいていた。 特にPropsやStateの型関連?

interface IProps {};
interface IState {
  value: number
};

class Hoge extends React.Components<IProps, IState> {
  ...
}

結局上記のように書いて解決できることを知ったが、なんで型引数が必要なのかわかってない。

constructorで暗黙的に呼び出しているからなのかな…?

一応エラーは解消できたので書き方としては正しいんだと思う。

しかしここは完全に勉強不足なので、他のReactで構成されたOSSとかを覗いてみるのもいいかもしれない。

Reactのテストについて

どういうことを検証するためにどんなテストをしていいのかわからなかった。

単純にメソッドのインプット・アウトプットを見るだけのテストならわかるが、 多分それだけじゃ不足しているっぽい。

どうやらスナップショットテストというのがあるらしいのは分かったが、それによって何がわかって嬉しいのかがわからずじまい。

もう一回ドキュメント読むなりして解決しないといけない。

Travis-CI

大きく苦戦したのがこいつ。

計画として、下図のような構成を考えていた。

f:id:asataken:20190208200206p:plain
構成図

このうち、masterへのpushをトリガーにテストするのはとても簡単だったのだが、 デプロイがなかなかうまくいかずにだいぶ時間をかけた。

Travis上でbuildまでして、buildが成功したらそれをrsyncでサーバにデプロイしようと考えた。

一応ドキュメントを読んで秘密鍵の暗号化とかはできていたのだが、何故か入れない。

結局何が行けなかったかというと、サーバ側に置く公開鍵の所有者問題だった。

開発ローカル上で作った鍵をサーバに送って配置したのだが、 所有者が自分のPCになってしまっていたため、動いていなかったのである。

要するに、chownでデプロイ用ユーザに所有権を移したら動いた。

そしてデプロイ。
サーバ上のホームページルートにデプロイ先のシンボリックリンクを貼ってみたが、動かなかった。
403 Forbidden が出るのだ。

しかしこれも調べたら非常に単純で、権限問題だった。

Nginxがデプロイ先のディレクトリにアクセスできていなかっただけだった。

参考:

lv4.hateblo.jp

書いてみるとあっけないが、これをすべて解決するのに丸3日かかった。

完全に調査力不足だったと思う。

今後

ガワはひとまず動くものが作れたので、今後やるべきは以下のこと。

  • DB設計
    • 自分の曲や曲の詳細、曲につけるタグ、更新情報、DiscographyなどをDBでしっかり管理できるようにしなければ
  • API作成
    • PhoenixかNode,js、もしくはDeno…?
    • Microserviceにも挑戦してみたいが、サーバ代が…
  • 管理画面作成
    • このままだと1曲追加するのにわざわざコードいじらなきゃいけないので、DBだけ変更できるように自分用管理画面を作らないとこの先が辛い
  • Reactのテスト
    • そもそもフロントエンドに関しての知識が壊滅的に足りないので、フロントエンドでは何がテストできていれば安心できるのかをちゃんと知る必要がある
  • Reduxの導入
    • State周りが結構つらいのを、どうやらある程度解決できるらしい…?流行ってるし使って見る価値アリだと思う
  • monitoring
    • 一応現状Mackerelを使っているが、せっかくならPrometheus + Grafana もやってみたい
  • デザインの見直し
    • 圧倒的にデザインできないので、かっこいいUIにしたい、でもこれは後回し

雑な感想

まずは形になるものができてよかった。

だが、圧倒的に勉強不足が目立った。

わからないけど動いてる、みたいなのがあまりに多すぎるので、継続的に開発を続ける中で解決していきたい。

react-router v4 でホームディレクトリだけを表示したい

概要

react-router で ルーティングをする際、ホームディレクトリ("/")だけを表示したいのに、他のページ("/hoge")なども一緒に描画される

解決策

ホームディレクトリ("/")のRouteのプロパティに exact={true} を入れる

class App extends React.Component {
  public handleState(item: number) {
    this.setState({item});
  }

  public content() {
    return (
      <div>
        <Route
          exact={true}
          path="/"
          render={props => <Top handleState={this.handleState} />}
        />
        <Route path="/hoge" component={Hoge} />
        <Route path="/fuga" component={Fuga} />
      </div>
    );
  }

  public render() {
    return (
      <BrowserRouter>
        {this.content()}
      </BrowserRouter>
    );
  }
}

Phoenix Frameworkでお手軽にAPI作成

環境

プロジェクト作成

表示関連はいらないのでオプションで指定する。

$ mix phx.new api_project --no-html --no-webpack

DBでMySQLを使いたいときは --database=mysql も必要。

その後は表示に従って、

$ cd api_project
$ mix ecto.create

を実行する。

データモデル作成

今回はjsonを返すAPIを作るので、そのためのデータモデルを作成する。

phx.gen.json – Phoenix v1.4.0

$ mix phx.gen.json Blog Article articles title:string body:text

表示に従って、ルーティングの追加とマイグレーションをする。

defmodule ApiProject,Router do
  use ApiProjectWeb, :router

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/api", ApiProjectWeb do
    pipe_through :api

    # 以下を追加
    resources "/articles", ArticleController, except: [:new, :edit]
  end
end

上記を変更したらマイグレーション

$ mix exto.migrate

実行

$ iex -S mix phx.server

http://localhost:4000/api/articles へ以下のようにPOSTするとデータが登録できる。

{
  "article": {
    "title": "記事のタイトル",
    "body": "記事の本文"
  }
}

レスポンスで以下のようなものが帰ってきたら成功。

{
  "data": {
    "title": "記事のタイトル",
    "id": 1
    "body": "記事の本文"
  }
}

http://localhost:4000/api/articles をGETすると一覧が見れる。(データは上のレスポンスの内容と一致してるはず)

tips

resources "/articles", ArticleController, except: [:new, :edit]

上記の except: [:new, edit] の箇所でHTTPメソッドの制限ができる。

例えば表示だけにしたければ

resources "/articles", ArticleController, only: [:index, :show]

とかやるとGETだけ受け付けるようになる。

ルーティングがどうなってるのか知りたければ、

$ mix phx.routes

で一覧を見れるので、そこを見ながらやると良さそう。