あいつの日誌β

働きながら旅しています。

Nginx + Node.js + React.js. + Mongodb を Docker で構築する

あらすじ

Nginx + Node.js + React.js + Mongodb で Web Application の構築手順を説明する必要があるのですが、Dockerfile をドキュメントとして扱う事になりました。

% docker --version
Docker version 17.06.2-ce, build cec0b72

% node -v
v8.1.0

% create-react-app --version
1.4.0

% mongo --version | head -n 1                                                                           MongoDB shell version v3.4.9

準備

一応 Todos アプリのような感じの Web API を backend で用意して React がそのデータを描画する、までの簡単なサンプルアプリを作成しつつ Docker について説明します。

先ずは以下のコマンドを実行して雛形を作っておきます。

cd 
mkdir practice-docker-provision && cd $_
mkdir backend mongodb mongo_seed nginx
create-react-app front
touch docker-compose.yml

mongodb

create docker-dompose.yml

version: "3"
services:
  mongodb:
    image: mongo:latest
    environment:
      - MONGO_DATA_DIR=/data/db
      - MONGO_LOG_DIR=/dev/null
    ports:
      - 27017:27017
    command:
      - mongod

docker-compose run --build を実行して mongod を起動します。起動したらアクセスできる事を確認します。

% mongo --quiet                                                                                                                   > show dbs
admin  0.000GB
local  0.000GB
> exit

mongo_seed

次に mongod を起動する度に database へ初期データを import するようにします。

mongod を起動した後、mongod へ初期データをインサートします。

mkdir mongo_seed/json
touch mongo_seed/Dockerfile mongo_seed/json/todos.json

create mongo_seed/json/todos.json

[
  { title: "todo 1", done: false},
  { title: "todo 2", done: false},
  { title: "todo 3", done: false}
]

create mongo_seed/Dockerfile

FROM mongo:latest

COPY json json

CMD mongoimport --host mongodb --db myapp --collection todos --drop --jsonArray --file ./json/todos.json

edit docker-compose.yml

     command:
       - mongod
+
+  mongo_seed:
+    build: mongo_seed
+    links:
+      - mongodb
+    depends_on:
+      - mongodb

docker-compose up --build を実行してから動作確認をします。

% mongo --quiet
> show dbs
admin  0.000GB
local  0.000GB
myapp  0.000GB
> use myapp
switched to db myapp
> db.todos.find()
{ "_id" : ObjectId("59d1fd6e73e8aa5ae594a04c"), "title" : "todo 1", "done" : false }
{ "_id" : ObjectId("59d1fd6e73e8aa5ae594a04d"), "title" : "todo 3", "done" : false }
{ "_id" : ObjectId("59d1fd6e73e8aa5ae594a04e"), "title" : "todo 2", "done" : false }
> exit
%

Node.js

cd ~/practice-docker-provision/backend
yarn init -y
yarn add express mongoose --save
touch app.js models.js

create app.js

var express = require('express');
var app = express();
var mongoose = require('mongoose');
var databaseUrl = process.env.MONGO_DATABASE || "mongodb://localhost/myapp"
var Todo = require('./models').Todo;

mongoose.connect(databaseUrl, {useMongoClient: true});

app.get('/api/todos', function(req, res) {
  Todo.find().exec((err, todos) => {
    if (err) {
      res.send(err)
      return
    }   
    res.json(todos)
  })  
});

app.listen(3000);

edit models.js

var mongoose = require('mongoose');

const Todo = mongoose.model('Todo', {
  title: {
    type: String,
    default: "", 
  },  
  done: {
    type: Boolean,
    default: false
  }
});

module.exports = { Todo: Todo }

edit backend/Dockerfile

FROM node:8

WORKDIR /usr/src/app

COPY package.json .
RUN yarn install

COPY . .

edit package.json

{
  "name": "backend",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "start": "node app.js"
  },  
  "dependencies": {
    "express": "^4.16.1",
    "mongoose": "^4.11.14"
  }
}

edit docker-compose.yml

version: "3"
services:
  mongodb:
    image: mongo:latest
    environment:
      - MONGO_DATA_DIR=/data/db
      - MONGO_LOG_DIR=/dev/null
    ports:
      - 27017:27017
    command:
      - mongod

  mongo_seed:
    build: mongo_seed
    links:
      - mongodb
    depends_on:
      - mongodb

  backend:
    build: "backend"
    environment:
      - NODE_ENV=production
      - MONGO_DATABASE=mongodb://mongodb/myapp
    ports:
      - "3000:3000"
    links:
      - mongodb
    depends_on:
      - mongodb

docker-compose up --build を実行してから動作確認をします。

% curl -s http://localhost:3000/api/todos | jq .                                                 [
  {
    "_id": "59d201da7e61015c1651b11f",
    "done": false,
    "title": "todo 1"
  },
  {
    "_id": "59d201da7e61015c1651b120",
    "done": false,
    "title": "todo 3"
  },
  {
    "_id": "59d201da7e61015c1651b121",
    "done": false,
    "title": "todo 2"
  }
]

React.js + Nginx

React.js を build します。

cd practice-docker-provision/front
yarn run build

front/build にファイルが生成されている事を確認して下さい。

次に Nginx の config と Dockerfile を準備します。

create nginx/nginx.conf

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    # include /etc/nginx/conf.d/*.conf;

    server {
      listen 80;

      # server_name localhost;

      gzip on;
      gzip_types *;

      location /api/ {
        proxy_pass http://backend:3000/api/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection ‘upgrade’;
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
      }

      location / {
        root /app;
        index index.html;
        try_files $uri $uri/ /index.html;
      }

   }
}

create nginx/Dockerfile

FROM nginx:1.13.0

RUN mkdir /app

COPY ./nginx.conf /etc/nginx/nginx.conf

CMD ["nginx", "-g", "daemon off;"]

edit docker-compose.yml

       - mongodb
     depends_on:
       - mongodb
+
+  nginx:
+    build: "nginx"
+    ports:
+      - "8080:80"
+    volumes:
+      - ./front/build:/app:ro

React.js から backend の API への通信をする

すでに Docker の設定は完了していますが、最後に React.js を修正します

cd ~/practice-docker-provision/front
yarn add axios --save

edit src/App.js

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import axios from "axios";

class App extends Component {

  constructor() {
    super();
    this.state = {
      todos: []
    };
  }

  async componentDidMount() {
    const res = await axios.get("/api/todos")
    this.setState({todos: res.data || []})
  }

  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to React</h1>
        </header>
        <p className="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
        <ul>
        {this.state.todos.map((todo, index) => (
          <li key={index}>{todo.title}</li>
        ))}
        </ul>
      </div>
    );
  }
}

export default App;

再度 yarn build して動作確認で終了です。

Docker で Nginx を起動して proxy させようとしたら host not found in upstream と言われる件

この書き方だとそうなった

FROM nginx:1.13.0

RUN mkdir /app

COPY ./nginx.conf /etc/nginx/nginx.conf

RUN service nginx start

正しくはこう。service は Docker の中で使ったらダメ、絶対。

FROM nginx:1.13.0

RUN mkdir /app

COPY ./nginx.conf /etc/nginx/nginx.conf

CMD ["nginx", "-g", "daemon off;"]

こちらからは以上です。

福岡へ4泊5日で働きながら旅をしてきた(3) その他

カフェと柳川と糸島とお土産。これで旅の報告はおしまい。

カフェ

今回は主にカフェで作業しましたので内訳を紹介します。

お店 働いた回数 作業のしやすさ
FUK COFFEE 0回 ×
スターバックスコーヒー メディアモール天神店 2回
スターバックスコーヒー 福岡赤坂門店 0回
スターバックスコーヒー 天神西通り店 1回
スターバックスコーヒー IWATAYA本店本館店 0回 ×
manu coffee 大名店 1回
manu coffee 春吉店 0回 ×
CARBON COFFEE 0回 ×

FUK COFFEE

おしゃれな外観のコーヒー屋さん小さい机が3つとあとは椅子だけの小さな店舗なので残念ながら作業には向きませんが酸味のあるコーヒーが好きな私が飲んでも酸味強いなと感じました。美味しかったです。フォトジェニックな店なので写真とコーヒー好きな人におすすめです。と言いながら外観を撮り忘れました。

f:id:okamuuu:20170924152650j:plain

スターバックスコーヒー

早朝の散歩などでお手洗いに行きたい時はスターバックスについ頼ってしまいます。そんなわけでスターバックスの入店回数が多いです。

実際に作業したのはメディアモール天神店、天神西通り店で午前中のみですが、両方とも席に余裕がありました。ただ、メディアモール天神店は席数が広いのですが、天神西通り店では席がやや少ないので時間帯によっては席がないかも。福岡赤坂門店は作業はしてないのですが席数もそこそこあるので作業しやすいんじゃないかと思います。

manu coffee

ここはなかなかお洒落なカフェなのですが午前中に行くとコーヒーブラックが200円です。福岡はちょいちょい価格がおかしい(?)店があります。

大名店は朝8:00から営業していてお洒落な空間をしばらく独り占めしていました。席数もそこそこあるのでもし福岡でノマドするならおすすめです。

春吉店はコンパクトな作りなので作業には向いていませんが一度行かれる事をおすすめします。柳橋連合市場という魚屋ばかりの商店街のような通りの端っこ一軒だけお洒落なカフェが存在していて、そのコーヒーを商店街で働くおばちゃんがテイクアウトして仕事場に向かうという、なかなか東京では見られない光景が見れました。

あとここも外観がすごいイケてます。うまく言えないんですが店内でコーヒー飲んでいるお客さんも絵になってしまうような、そんな感じの店です(撮影してこい)

CARBON COFFEE

ここも大名にあるお洒落なカフェです。作業には向いてないですがここもお洒落なカフェでした。

f:id:okamuuu:20170927123412j:plain

カフェまとめ

というわけで作業しながら旅をしていた関係上スタバ頻度が高いのですが、もしこの中で一軒だけノマドするなら私は manu coffee 大名店がおすすめです。ノマドしなくてもクリエイターの人とかにもおすすめです。うまく言えないんですが福岡で流行に敏感な人たちがふらっと入ってくる店、みたいな感じですたぶん。

柳川

f:id:okamuuu:20170925175112j:plain

滞在期間が割と長いので少し遠出することにしました。で、川下りをしたかったのと柳川のうなぎを食べたかったので行ってきました。

なんですが到着時間が結構遅れて最終の17:00 の船に乗ることになりました。結果的に日差しがなくて良かったです。ちなみに平日だったこともあって船頭さんとマンツーマンです。船頭さんは川を下りながら地元にちなんだ話をしてくれます。

川といってももともとは柳川城の掘だったので立花宗茂の話をしてくれます。地元の人たちは彼を主役にした大河ドラマを熱望しているそうです。ちなみに父親が武名の高い高橋紹運で母親の父親が立花道雪だそうです。血統がすごいしなんだか実現しそう。

というわけで無事川下りを楽しんでうなぎを食べて帰りました。

糸島

f:id:okamuuu:20170926160031j:plain

どこまでも続く青い海と空を求めてレンタカーを借りて行って参りました。本来でしたら福岡市内で車を借りるのですが、私はペーパードライバーだったので筑前前原駅まで電車で移動してそこから車をレンタルしました。目的はただ一つ PALM BEACH RESTAURANT に行って来て、無事帰ってくる事です。観光も目的ですが今度に関わるのでこの機会に運転の練習がしたい(東京だと通行人が多すぎて練習するの嫌だ)

というわけで車を借りて北上するとイオンがあります。私はここで駐車の練習をしてから先に進みました。同じ境遇の人が居たらそうするとよいでしょう。ここにセルフ式の GS があるので帰りが遅くなる場合はここで給油する事をおすすめします。帰宅ラッシュの時間帯だと駅前がかなり渋滞するので駅前の GS へ入るのと出るのが結構大変でした。

糸島では制限速度が大体時速40km の場所がほとんどなので初心者でも割と運転しやすかったです。

で、 PALM BEACH RESTAURANT に行ってご飯を食べました。ちなみにこういうスポットがあります。

そして帰りが遅くなってしまい(帰りもイオンの駐車場で練習に励んだ)、帰宅ラッシュの最中 GS を目指しました。なんですが途中でカーナビが転倒してしまい、GS の場所を確認できない。今手を離したら死ぬどうしよう。と混乱した私は一方通行の道に迷いこみます。

そうすると地元のおじさんたちがここから先は通れないですよと教えてくれました。狼狽する私は「あの、東京から来た運転初心者なんですけどGSに行くにはどうしたらいいですかあうあう..」と助けを求めました。おじさんは「そこの駐車場でUターンすれば良か。GS はすぐそこ」と教えてくれました。礼を述べ、駐車場で気を落ち着かせているといつまでも発進しない私を心配したのか、先ほどのおじさんがわざわざ駆けつけてくれてもう一度丁寧に道順を教えてくれました。

糸島の人は優しかったとです...おかげさまで無事生きて帰れました。

おみやげ

f:id:okamuuu:20170928215838j:plain

冷凍の明太子を買って帰りました。飛行機で荷物預けるのが面倒なので機内持ち込みでお土産を買って帰りたい。おいしい明太子は一度も冷凍しないものでぷりぷりというかぷちぷちした食感があって美味しいのですが冷凍でもかなり美味しいので冷凍の明太子を機内に乗り込む前に購入しました。私は博多駅のマイングというお土産がいっぱい置いてあるエリアで買いました。

福岡へ4泊5日で働きながら旅をしてきたまとめ

福岡にはチャンスがいっぱいあって、精力的に活動している人や支援する人がたくさんいる事が分かりました。ごはんもおいしいし、お洒落なカフェもたくさんあります。あと自然までの距離も近いですし、住んでいる人も優しかったです。

街自体はコンパクトですがその分魅力が濃縮されていると思います。空港までの距離も近いので海外滞在をするにも便利な拠点だと思います。

また、視察するために現地で働きながら旅行をする、というのは結構楽しかったです。また近々どこかの街で働きながら旅をする、に挑戦したいと思います。

こちらからは以上です。

福岡へ4泊5日で働きながら旅をしてきた(2) ご飯篇

福岡へ旅行行った時のごはんをまとめました

食べたもの

ざっくり説明するとこのような感じです。

お店 住所 食べたもの
博多天ぷらたかお 福岡県 福岡市博多区 住吉 1-2-1 キャナルシティ博多 4F シネマストリート 天ぷら、昆布明太、白ご飯、浅漬け
炉ばた しんがり 福岡県福岡市中央区舞鶴1-9-3 胡麻鯖の刺身、あぶり明太子、白ご飯、厚焼き卵、味噌汁
天神わっぱ定食堂 福岡県福岡市中央区今泉1丁目11-7 今泉KYビル 博多定食
うなぎ料理 古蓮 福岡県柳川市三橋町下百町31-6 せいろ蒸し
博多魚がし 市場会館店 福岡県福岡市中央区長浜3丁目11-3 海鮮丼
中州屋台橫丁 福岡県福岡市博多区中洲 那珂川 通り ラーメン、焼き鳥
おおやま KITTE博多 福岡県福岡市博多区博多駅中央街9-1 KITTE博多B1F もつ鍋
柳橋食堂 福岡県 福岡市中央区 春吉 1-10 Aセット(ミニ海鮮丼+あら煮込み)

博多天ぷらたかお

キャナルシティ内の天ぷら屋さん。福岡初のごはんはこの店。揚げたての天ぷらを都度運んでくれるお店。昆布明太と浅漬けがお代わりし放題。白いご飯と昆布明太の組合せが美味しい。

f:id:okamuuu:20170924143948j:plain f:id:okamuuu:20170924142715j:plain

ちなみに東京にもあります。

炉ばた しんがり

親不孝通りにあるおしゃれな外観のお店。一人分の注文がちょっとしづらいメニューだったので量が少なそうなものを少しづつ注文しました。胡麻鯖の刺身美味しかったです。

f:id:okamuuu:20170924192537j:plain

この店のあぶり明太子はちょっと辛めだったのでビールだけでは太刀打ちできませんでした。ということで白いご飯をお願いしました。結果、明太子、白ご飯、ビールの無限ループ。最後は厚焼き卵のコンボを決めて福岡初日の夜を終えました。

f:id:okamuuu:20170924193654j:plain

天神わっぱ定食堂

二日目のお昼。食堂で博多定食を注文。豚汁が美味しい。そしてここでも明太子が。東京にいると明太子はたまにしか食べないのですが博多にいるとものすごい頻度で食べる事になります。うちの近所にもこういう定食屋が欲しいなあ。

f:id:okamuuu:20170925134823j:plain

うなぎ料理 古蓮

柳川へ川下りを体験しに行った後、船頭さんにおすすめされたお店。ちなみに柳川で消費されるうなぎの量は、年間100万匹以上だそうです。

f:id:okamuuu:20170925182106j:plain

あと歴史好きで立花宗茂を知っている人ならわかると思いますが、そのうち大河ドラマで放送されるようになるかも知れないのでそうなったら柳川はちょっとした人気スポットになるかも?

博多魚がし 市場会館店

中央卸売市場鮮魚市場の中にあるお店。市場で水揚げされたネタを用いた寿司や海鮮丼などを提供するお店が揃っています。複数店舗があるのですが博多魚がしを選択しました。海鮮丼美味しい。玄界灘のポテンシャルを味わいました。

f:id:okamuuu:20170926082712j:plain

ちなみに魚がし以外にもお店があって地元の人は他のお店をチョイスしていたのでもし次回行くときは他の店にも行ってみたいと思います。

中州屋台橫丁

f:id:okamuuu:20170926195940j:plain

ラーメンと焼き鳥を堪能しました。味に関しては美味しいですがお値段がちょっと観光価格かな?天気も良かったので気持ちよくお酒を飲めました。

f:id:okamuuu:20170926200726j:plain

お客さんの割合は中国人と韓国人と日本人が1:1:1 ぐらいかな?

おおやま KITTE博多

もつ鍋を一人で食べたいので一人向けのお店に行きました。モツがぷりぷりしてて柔らかいです。おおやまは他にも福岡市内に何店舗かありますがお一人様向けかどうかは店舗によって異なるかも?ちなみに東京にもあります。

f:id:okamuuu:20170927173724j:plain

柳橋食堂

柳橋連合市場という博多の台所的な地域があるのですが、ここにも海鮮丼を食べられるお店があります。宿泊場所によっては海鮮市場まで距離がある場合はこちらを利用するのも良いと思います。

f:id:okamuuu:20170928085126j:plain f:id:okamuuu:20170928095701j:plain

まとめ

というわけで行って来たお店を五月雨式にまとめました。また福岡に行ったらまとめたいと思います。

福岡へ4泊5日で働きながら旅をしてきた

あらすじ

私は現在東京でフリーランスのエンジニアをしていますが、いつか海外を旅しながら働きたいという願望があります。拠点を日本に残しつつ、労働ビザではなく、観光ビザで3ヶ月ごとに旅する国を変えたい。

なんですが拠点を東京に残した場合は維持費が結構かかります。東京以外の選択肢が必要なので福岡を視察をする為に4泊5日で行って参りました。

旅の概要

ざっくり説明するとこのような感じです。

日程 天気 内容
9月24日(日) 成田->福岡、チェックイン、市内を散策
9月25日(月) 快晴 4h作業、太宰府、柳川、STAND BY ME
9月26日(火) 快晴 2h作業、糸島
9月27日(水) 曇り時々雨 4h作業、市内を散策、awabar
9月28日(木) 晴れ チェックアウト、お土産購入、福岡->成田

旅の目的は3つ

  • 実際に旅行しながら稼働を確保するのはどこまで可能なのか?
  • 地方で車を運転する
  • 福岡は移住先として検討するための情報を入手する

実際に旅行しながら稼働を確保するのはどこまで可能なのか?

週3程度の勤務の場合、この日程だと16時間稼働すればOK。なんですが仕事の状況がそこまで切迫していなかったので今回は10時間程度の稼働に切り上げました。意外と作業に集中できたので旅行先で稼働するのはアリだと思いました。

地方で車を運転する

車を運転したかったのは私が地方への移住を検討しているにも関わらずペーパードライバーだからです。去年ぐらいから移住を検討していて2016年の8月ごろに免許を取得していたのですが運転をしたのは夏らしさを求めておじさん2人が南伊豆へ旅した記録 2017の一回だけです。

色々ありましたが無事生きて帰ることができました。

福岡は移住先として検討するための情報を入手する

まったく福岡に人脈がないので「立ち飲み BAR に行ってなんか話しかけてみるか」ぐらいの気持ちでしたので、正直あまり成果を期待していなかったのですが、意外にも色々な情報を入手する事ができました。

飛行機と宿泊先

飛行機と宿泊を計画。日程に関してはいつ、どれぐらい滞在するか特に決めていなかったので、安い航空会社を検索。3週間後の成田、福岡間のジェットスターが安かったのでこれにしました。金額は17440円です。

宿泊先は Airbnb を利用しました。Airnbn を利用するのは初めてです。4泊で25602円です。内訳は以下の通りです。

内訳 金額
¥ 4900 × 4 泊 ¥ 19600
清掃料金 ¥ 3000
Airbnbサービス料(VAT込み) ¥ 3002

利用した部屋はこちらです。利用した理由は金額が安すぎず高すぎず、相場にマッチしていると感じたこととレビューには非常に便利な立地であるとの記述があったからです。実際にその通りで素晴らしい立地でした。おすすめです。お値段はシーズンによっては上記の金額と違うと思います。

www.airbnb.jp

事前に調査した事

以下の動画、記事を見ました

あとは現地で高度の柔軟性を維持しつつ臨機応変に対応する事にしました。

TOPICS

自分の為に細かい事を色々と買いて備忘録を残したいのですが、それをすると長くなってしまうので主要な情報だけ紹介します。ごはんに関しては別の記事にまとめたいと思います。

STAND BY ME

おしゃれなホテルと立ち飲み BAR のお店です。

ホテルに関しては当初はここに泊まる事も考えたのですが、予定していた日程では連続して宿泊できなかったので今回は Airbnb を利用する事にしました。

立ち飲み BAR に関しては地元の人と出張にきた人が半々ぐらいかな?と思いました。ここは1000円でチケット4枚と交換するシステムです。大体のお酒とおつまみがチケット1枚と交換です。例えばよなよなビールですと4杯飲めます。

博多は何故かところどころで価格破壊が発生しています。私は結構東京で呑んだくれていますが本当に千円でべろべろになるせんべろの店には出会った事がありませんでした。

でも福岡ではせんべろのお店に簡単に出会えてしまいます。

f:id:okamuuu:20170928212119j:plain

働いている女の子にお願いしてポーズをとってもらいました。ブログへの掲載許可を頂いております。

awabar

福岡のコワーキングスペース、スタートアップカフェを見て来ました。ここは小学校を再利用した施設でコワーキングスペースの他にカフェや立ち飲み BAR が運営されています。

f:id:okamuuu:20170928212352j:plain

働いている女の子にお願いしてポーズをとってもらいました。ブログへの掲載許可を頂いております。

この BAR でお店の人に「東京から来た福岡に移住を検討中のエンジニアです」と伝えたところ、福岡のIT事情やら生活水準などを色々な事を教えてくれました。

そして偶然なのですが私が旅行前に参考に読んだブログのライターさんがそこで働いているというミラクルが発生。実際に東京から福岡に移住してみた感想などを色々質問。有益な情報がいくつか得られました。

  • 福岡ではエンジニアが不足している(東京もそうだけど)
  • 単価の基準が東京と異なる為スキルがある人材は流出する
  • 福岡で一番お金があるクライアントは行政
  • 福岡では PHP が多い
  • 福岡では割とレガシーなプログラムが多い*1

というわけで福岡に移住する時に一番ネックになりそうなのがクライアントとの報酬を交渉する部分だと思います。震災を機に福岡へ移住したライターさんを紹介してもらいそのあたりの話を聞く事ができました。単価についてはかなりの温度差が推測されるので福岡で仕事を探すのは得策では無いのかも。福岡で仕事を得るには自身で雇用を作り出す気概が必要になりそうです。

  • 福岡の家賃は安い
  • 福岡の食事は安くてうまい
  • 福岡には適齢期の女性が多い

福岡の家賃はとても安く、市の中心エリアでも家賃4万円もあれば十分だそうです、食事も安くて美味しいです。報酬が減ったとしても生活水中が上回る可能性もあります。

また若い女性が多いという話は良く言われているのですが、実際に行政側がIT企業を福岡に誘致したがっているらしいです。IT系の企業は大体男子の比率が高いのでそうなると色々な人たちの問題が一斉に解決するでしょう。そんなわけで今後は福岡でプログラマの求人が増える可能性もあると思います。

ちなみに福岡で一番家賃が高い地域は西新だそうです。これは学区が関係していて自分の子供を良い学校に入れたい場合は住所が関係してくるからだそうです。

  • 佐賀県唐津スイッチという施策がある
  • 住居・オフィス提供します
  • 利用者は7日以上、3カ月以内の滞在期間中、同市南城内のシェアオフィスで仕事をすることが条件

またまた紹介された別の人から聞いたお話。福岡の人はやたらと人を紹介する習慣があるとかないとか。ちなみに彼はその唐津スイッチという施作を行政と一緒に行っていて、狙いとして地元のクリエイターを刺激するために、外部のクリエイターを誘致したいという思惑などからこのような施作が生まれている模様。

などなど awabar では有益な情報がたくさん聞けました。なんでも福岡のスタートアップの情報が全部この awabar に集まっているとかいないとか。

ちなみに私に色々な人を紹介してくれたスタッフさんは私が旅行前に参考に読んだブログのライターさんでした。彼女のブログは福岡に来る前に一読しておくと良いでしょう。

f:id:okamuuu:20170927193714j:plain

まとめ

ということで週3で働く在宅ワークのエンジニアは働きながら旅をすると色々な知見が得られるのでオススメです。もし福岡に行く場合はSTAND BY ME と awabar に立ち寄るのをおすすめします。

こちらからは以上です。

*1:文脈的にPHPがレガシーみたいな感じになっていますが私は PHP を否定しておりません。

i18next を使って国際化してみる

github.com

あらすじ

とあるサイトの開発に携わっているのですが、将来的に国際化して海外ユーザーもターゲットとしたい。という話なので予め国際化する準備をしておきたい。

最初は react-intl を試そうとしましたが、どうやら react-helmet との相性があんまり良くなさそう。使えるんだけどインターフェースが複雑。

そんな訳で次に react-i18next を試そうと思ったのですが、そもそも i18next の使い方を覚えたほうがいいなと思ったので練習しました。

やりたい事

  • 日本語、英語に切り分けたい
  • `{t('key')} と書いたらいい感じになる
  • {t('key', 引数)} のように引数を渡したい
  • t('some.key)}` のよう書きたい

将来的に国際化したいのですがいきなりそこまで頑張りたくもないです。なんですが Form Validation のところだけは最初から国際化したいのでそこだけ頑張りたいです。

どうせサーバーサイドとのやりとりでエラー文言は英語になるだろうし...

just do it

create-react-app practice-i18next && cd $_
mkdir -p locales/{en,ja}
touch locales/{en,ja}/translation.json
yarn add i18next --save

create locales/en/translation.json

{
  "hello": "hello",
  "world": "world",
  "welcome": "welcome, {{name}}!!",
  "validation": {
    "isNotEmail": "{{email}} is not valid email."
  }
}

create locales/ja/translation.json

{
  "hello": "こんにちは",
  "world": "世界",
  "welcome": "ようこそ, {{name}}さん!!",
  "validation": {
    "isNotEmail": "{{email}} は正しい形式ではありません"
  }
}

edit src/App.js

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

import i18next from 'i18next';
import enLocalesTranslationJson from './locales/en/translation'
import jaLocalesTranslationJson from './locales/ja/translation'

i18next
  .init({
    fallbackLng: 'ja',
    debug: true,
    resources: {
      en: {
        translation: enLocalesTranslationJson
      },
      ja: {
        translation: jaLocalesTranslationJson
      }
    }
  });

class App extends Component {
  render() {
    return (
      <div className="App">
        <div className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h2>Welcome to React</h2>
        </div>
        <p className="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
         <h2>{i18next.t('hello')}</h2>
         <h2>{i18next.t('world')}</h2>
         <h2>{i18next.t('welcome', {name: "田中"})}</h2>
         <h2 style={{color: "red"}}>{i18next.t('validation.isNotEmail', {email: "tanaka@"})}</h2>
      </div>
    );
  }
}

export default App;

動作確認

yarn start

f:id:okamuuu:20170922194126p:plain

まとめ

react-i18next という公式な react 向けの wrapper があるようですが、なんだか i18next で事足りる気がする。react-i18next を使ったほうがいいのかは後々考える事にします。

Gatsby.js の Tutorial で Error: Unable to find plugin "gatsby-plugin-typography" と言われる場合

結論

プロジェクトのディレクトリに移動して npm install --save gatsby すると良いでしょう。issue あげたら npm の問題であるとの事ですが、gatsby 側からは特に対応しないようです。とはいえ tutorial 試して見て動かないから使うのやめた、という人達が出てきてしまう気がするのでちょっと気になる。まあ Gatsby.js が結構バギーな状態の気がするので初学者が何かするにはそもそも敷居が高い気がするのでしょうがないのかな。*1

Error: Unable to find plugin "gatsby-plugin-typography" in Gatsby.js Tutorial Part Two · Issue #1989 · gatsbyjs/gatsby · GitHub

問題

I tried Gatsby.js Tutorial Part Two but I found the error message.

環境

% node -v
v8.1.0

% sw_vers
ProductName:    Mac OS X
ProductVersion: 10.12.6
BuildVersion:   16G29

再現方法

I typed the following commands.

% cd 
% npm install --global gatsby-cli
% gatsby --version
1.1.6
% gatsby new tutorial-part-two https://github.com/gatsbyjs/gatsby-starter-hello-world
% cd tutorial-part-two

At this point, I can run the gatsby develop. But I found the error message when I create the gatsby-config.js.

% cat << EOT > gatsby-config.js
module.exports = {
  plugins: ["gatsby-plugin-typography"],
}
EOT
% npm install --save gatsby-plugin-typography 

the error

% npm run develop

> gatsby-starter-hello-world@ develop /Users/okamuuu/tutorial-part-two
> gatsby develop

success open and validate gatsby-config.js — 0.005 s
(node:76343) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Error: Unable to find plugin "gatsby-plugin-typography"
(node:76343) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

解決策?

Looks like node_modules/gatsby is almost empty.

% ls -al node_modules/gatsby
total 0
drwxr-xr-x   3 okamuuu  staff   102  9  1 23:51 .
drwxr-xr-x  94 okamuuu  staff  3196  9  1 23:51 ..
drwxr-xr-x   3 okamuuu  staff   102  9  1 23:51 node_modules

So I tried to type npm install --save gatsby. It looks good to me.

%  ls node_modules/gatsby/
README.md       cache-dir       node_modules    yarn.lock
bin             dist            package.json

*1:個人的には結構気に入っていて最近ずっと触っています