Shell の作業ディレクトリごとに自動で環境変数を設定する

さまざまなプロジェクトのソースコードを扱っていると、プロジェクトに応じて環境変数を切り替えたいことがあります。もし現在のディレクトリに応じて環境変数が自動的に切り替わったら?
それを実現してくれる direnv を紹介します。

The Twelve-Factor App (日本語訳) などでも取り上げられているように、アプリやシステムの設定に環境変数を使うことが多いです。

その環境変数を毎回設定するにしても手間ですし忘れがちです。また .bashrc などに全部設定しロードしておくこともできますが、プロジェクトが増えてくると煩雑になり困ります。

そのような時に使えるのが direnv です。対応しているのが “bash, zsh, tcsh, fish shell and elvish - direnv“ とのことなので、Linux/Mac そして WSL(Windows Subsystem for Linux) が中心となりますが、環境変数を自動的に切り替えてくれる素晴らしい機能を提供してくれます。

環境
本記事の開発環境は以下となります。

  • Windows 10 64bit + WSL Ubuntu 18.04.1 LTS
  • Bash 4.4.19 (WSL Ubuntu)
  • direnv/direnv 2.20.0

参考情報

direnv とは

Shell 用の環境スイッチャーで、現在のディレクトリに応じて環境変数をロードまたはアンロードしてくれます。

まさに “~/.profile ファイルを乱雑にすることなくプロジェクト固有の環境変数を使用できます - direnv“ とのこと。

もう、この一文で語りつくされているのではないでしょうか。(私の序文は長くて冗長だった。。。)

direnv の導入

WSL Ubuntu にはデフォルトで入っていないのでインストールします。
※ 各環境に合わせたインストールおよび設定は Install - direnv/direnv をご確認ください

1
$ sudo apt install direnv

~/.bashrc に以下の設定をします。
※ ただし WSL Ubuntu の場合は ~/.bashrc がデフォルトで読み込まれないので、今回は ~/.bash_profile に設定

1
2
3
# direnv configuration
export EDITOR=vi
eval "$(direnv hook bash)"

設定ファイルを記述するためのエディターを環境変数 EDITOR に設定します。今回は vi としました。続いて eval "$(direnv hook bash)" で Bash のフックに direnv を登録します。

上記設定を読み込みます。

1
$ source ~/.bash_profile

利用するプロジェクトごとに環境変数を設定

環境変数を設定したいディレクトリで .envrc ファイルを作り、export で環境変数の定義を書きます。利用しているシェルの種類にかかわらず、このファイルは Bash の書式で記述します。

direnv edit [path] でエディターを起動し、設定を保存します。

1
2
3
$ cd ~/my-brilliant-project
$ direnv edit .
export MSG=Hello

エディターを保存して終了すると、そのディレクトリに .envrc ファイルが作られます。また以下のように設定を読み込んだとのメッセージが出力されます。環境変数を確認すると、確かに読み込まれています。

1
2
3
4
5
direnv: loading .envrc
direnv: export +MSG

$ echo $MSG
Hello

ディレクトリを出ていくと、以下のようにアンロードしたとのメッセージが出力され、また入ると読み込まれます。ディレクトリに応じて自動的に環境変数が切り替わっているのがわかります。

1
2
3
4
5
6
7
8
9
10
11
12
$ cd ../
direnv: unloading

$ echo ${MSG-unloaded}
unloaded # アンロードされている

$ cd ~/my-brilliant-project
direnv: loading .envrc
direnv: export +DEBUG +MSG

$ echo ${MSG-unloaded}
Hello # .envrc が読み込まれている

あとは、必要なディレクトリごとに .envrc を用意します。

なお direnv edit 以外の方法で .envrc が作られたり変更されると、はじめて .envrc を読み込む際にエラーが表示されます。これはアーカイブや git clone などで .envrc が作られた場合も同様ですし、他のユーザーが .envrc を編集した(そのユーザーが direnv edit を使ったとしても)もエラーが表示されます。

これは自分が明示的に編集した .envrc ではない場合に、自動で読み込むと危険だからです。
エラーが表示された場合は .envrc に問題ないことを確認し、読み込む場合は direnv allow を実行します。
※ 一度 direnv allow しても、.envrc が自分の direnv edit 以外で書き変わると再エラー&確認が必要となります

1
2
3
4
5
6
$ cd ~/my-splendid-project
direnv: error .envrc is blocked. Run `direnv allow` to approve its content.

$ direnv allow
direnv: loading .envrc
direnv: export +MSG

注意
.envrc に秘匿情報がある場合は、Git などのソースコード管理の対象にしないよう注意が必要です。


Shell のディレクトリ移動に応じて環境変数の定義を切り替えてくれる direnv、一度設定すれば後は無意識に切り替えてくれるので助かります。

Nuxt.js で Vue コンポーネントの利用とコンポーネントの相互呼出しをする

Nuxt.js を使うことで JAMStack なアプリを高速に構築できます。それに加えて Vue.js のフレームワークであるため Vue コンポーネントが使えるというメリットがあります。UI のパーツをコンポーネントとして切り出すことで実装をシンプルにし、また再利用性を高めることができます。

これまで、Nuxt.jsPWA with TypeScript として、ベースとなるアプリを作ってきました。このままページを追加していくことで簡単にアプリ画面を増やしていけますが、その前に Nuxt.js (というか Vue.js 系フレームワーク) の、強力な機能である「Vue コンポーネント」を使い実装をシンプルにしたいと思います。

説明の都合により下記シリーズのソースを使いますが一般的な Vue コンポーネントの使い方ですので、下記 “開始時のアプリソース” ではなくても大丈夫です。

シリーズの記事

環境
本記事の開発環境は以下となります。

絵文字ボタンを Vue コンポーネントにする

以下はページ(/pages/index.vue) へ追加した絵文字ボタンに関連するコードです。絵文字に応じた tada などの文字列が異なるだけで、ほぼ同じコードの繰り返しとなっています。

/pages/index.vue (該当箇所のみ抜粋)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<div class="actions">
<a @click="addTada" class="button--action">🎉 {{ tada }}</a>
<a @click="addSparkles" class="button--action">✨ {{ sparkles }}</a>
<a @click="addThumbsup" class="button--action">👍 {{ thumbsup }}</a>
<a @click="addHeart" class="button--action">🧡 {{ heart }}</a>
</div>

<script lang="ts">
export default Vue.extend({
data() {
return {
tada: 0,
sparkles: 0,
thumbsup: 0,
heart: 0
}
},
methods: {
addTada: function(): void {
this.tada++
},
addSparkles: function(): void {
this.sparkles++
},
addThumbsup: function(): void {
this.thumbsup++
},
addHeart: function(): void {
this.heart++
}
}
})
</script>

これを Vue コンポーネント化して、再利用可能な絵文字ボタン・コンポーネントにします。
まず、ボタン1つとして表現される /components/EmojiButton.vue を作ります。ボタン1つ分なので <a> タグが1つ、汎用的なメソッド名、変数名にします。絵文字は、親コンポーネントから渡された絵文字を使いたいので props: { emoji: String } として受け取るようにします。

/components/EmojiButton.vue (コード全文)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<template>
<a @click="add" class="button--action">{{ emoji }} {{ counter }}</a>
</template>


<script lang="ts">
import Vue from 'vue'

export default Vue.extend({
props: {
emoji: String
},
data() {
return {
counter: 0
}
},
methods: {
add: function(): void {
this.counter++
}
}
})
</script>


<style scoped>
.button--action {
display: inline-block;
border-radius: 4px;
border: 1px solid #3b70d0;
color: #3b70d0;
text-decoration: none;
margin: 0 2px;
padding: 10px 10px;
cursor: pointer;
}

.button--action:hover {
color: #fff;
background-color: #3b70d0;
}
</style>

絵文字ボタンを利用するページ側(/pages/index.vue) では、ハードコードしていた絵文字ボタンをコンポーネントの利用に変更します。コンポーネントのタグは <emoji-button> で、 data() { emojis } の配列を使った v-for の繰り返しで作ります。また古いハードコードしていた絵文字ボタンのコードは削除します。

/pages/index.vue (該当箇所のみ抜粋)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<template>
<section class="container">
<div>
<div class="actions">
<emoji-button v-for="e in emojis" :key="e" :emoji="e" />
<a @click="clear" class="button--grey">Clear</a>
</div>
</div>
</section>
</template>


<script lang="ts">
import Vue from 'vue'
import EmojiButton from '~/components/EmojiButton.vue'
import Logo from '~/components/Logo.vue'

export default Vue.extend({
components: {
Logo,
EmojiButton
},
data() {
return {
emojis: [ '🎉', '✨', '👍', '🧡' ]
}
},
computed: {
counter(): number {
return 0
}
},
methods: {
clear: function(): void {
}
}
})
</script>

これにより絵文字ボタンがコンポーネント化され、再利用可能なボタンとなりました。
それぞれのボタンに絵文字が表示され、クリックするとクリックされたボタンのカウンターが増えます。似たようなコードがなくなりスッキリしました。

子コンポーネントから、親コンポーネントにイベントを送る

絵文字ボタンのコンポーネントはできましたが、トータルのカウンターは機能しなくなりました。絵文字ボタン・コンポーネントのカウンターの合計だけロゴ(/components/Logo.vue) コンポーネントを回転する機能がありましたが、現在は回転しません。

これまではページ側(/pages/index.vue) に、すべての情報があったのでボタン・クリック数の合計をロゴ・コンポーネントに送れました。しかし各カウンターが絵文字ボタン・コンポーネントへ移動してしまったため、カウンターの合計がページ側では作れなくなりました。

そこで、絵文字ボタン・コンポーネント(子コンポーネント)はクリックされたことを、ページ(親コンポーネント)へ伝えるようにします。ページ側では、その各絵文字ボタン・コンポーネントから伝えられたクリックの回数をカウントして合計としてロゴ・コンポーネントへ送るようにします。

そのクリックされたことを伝えるために「イベント」を使います。絵文字ボタン・コンポーネント(子コンポーネント)から、ページ(親コンポーネント)へ「イベント通知」をすることで、クリックされたことを伝えます。

子コンポーネント「絵文字ボタン・コンポーネント」を修正

絵文字ボタン・コンポーネントのカウントアップ処理にイベント通知 this.$emit('countup') を追加します。

/components/EmojiButton.vue (該当箇所のみ抜粋)

1
2
3
4
5
6
7
8
9
10
11
12
<script lang="ts">
import Vue from 'vue'

export default Vue.extend({
methods: {
add: function(): void {
this.counter++
this.$emit('countup')
}
}
})
</script>

$emit は、Vue コンポーネント間でイベントを通知するための仕組みです。今回は絵文字ボタン・コンポーネントが子コンポーネントなので、親コンポーネントであるページへイベントを通知します。

イベント通知は $emit('イベント名', [...引数]) の書式です。引数は可変長配列で、イベントの通知先へ渡されます。今回は countup という名前のイベント名で引数無しの通知を行っています。

参考情報

親コンポーネント「ページ」を修正

親コンポーネントであるページ側で、子コンポーネントである絵文字ボタン・コンポーネントからのイベント通知を受け取ります。

/pages/index.vue (該当箇所のみ抜粋)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<template>
<section class="container">
<div>
<div class="actions">
<emoji-button v-for="e in emojis" :key="e" :emoji="e" v-on:countup="add" />
<a @click="clear" class="button--grey">Clear</a>
</div>
</div>
</section>
</template>


<script lang="ts">
export default Vue.extend({
data() {
return {
total: 0,
emojis: [ '🎉', '✨', '👍', '🧡' ]
}
},
computed: {
counter(): number {
return this.total
}
},
methods: {
add: function(): void {
this.total++
},
}
})
</script>

<emoji-button> タグに v-on:countup="add" 属性を追加し、絵文字ボタン・コンポーネントの countup イベントを受け取ります。属性値 add は、メソッド呼出しで add() メソッドを呼び出すという定義です。これにより子コンポーネントのイベントを受け取って、親コンポーネントで処理をするという形が作れます。

上記定義で呼び出されるメソッドを <script> に追加します。これは通常のメソッド定義と同様です。今回は data() { total } をインクリメントするメソッドとします。

これにより各絵文字ボタン・コンポーネントがクリックされると、ページ側に countup イベントが伝わります。そのイベントの回数を total にインクリメントしていくことで、全絵文字ボタン・コンポーネントのカウンター合計が作れます。

そして totalcomputed: { counter() } につなぐことで、これまで機能していたロゴの回転が復旧します。

参考情報

親コンポーネントから、子コンポーネントにイベントを送る

最後に [Clear] ボタンを復旧します。[Clear] ボタンは絵文字ボタンと異なり1つだけですし、すべての絵文字ボタン・コンポーネントのカウンターをリセットする特別な役割があります。そのため親コンポーネントに残しました。

[Clear] ボタンの機能であるリセットですが、親コンポーネント内の total0 にリセットすることはできます。それによりロゴの回転を止めて、カウンターのリセットもできます。

しかしながら子コンポーネントのカウンターは直接リセットできません。こちらもイベント通知を使いリセットします。先ほどと逆なり、親コンポーネントから子コンポーネントへイベントを通知します。

親コンポーネント「ページ」を修正

ページ側はイベントを通知する先の子コンポーネントである、全絵文字ボタン・コンポーネントを特定してイベント通知します。今回は絵文字ボタン・コンポーネントしかないので(正確には、ロゴ・コンポーネントも子コンポーネントですが)、送り先を意識しにくいですが多数のコンポーネントを抱えている親コンポーネントであるからこそ、どのコンポーネントへイベント通知するか考える必要があります。

/pages/index.vue (該当箇所のみ抜粋)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
<section class="container">
<div>
<div class="actions">
<emoji-button v-for="e in emojis" :key="e" :emoji="e" v-on:countup="add" ref="EmojiButtons" />
<a @click="clear" class="button--grey">Clear</a>
</div>
</div>
</section>
</template>


<script lang="ts">
export default Vue.extend({
methods: {
clear: function(): void {
this.total = 0;
(this.$refs.EmojiButtons as Vue[]).forEach((value: Vue) => value.$emit('clear'))
}
}
})
</script>

<emoji-button> タグの ref="EmojiButtons" 属性は、EmojiButtons の文字列でタグを参照されるための設定です。ref 属性は通常の HTML タグと、子の Vue コンポーネント・タグのどちらにも使用できます。

参照する側は $refs.[ref 属性の値] で行います。今回は EmojiButtons で登録したので $refs.EmojiButtons でアクセスします。clear() メソッドでは EmojiButtons で登録された全絵文字ボタン・コンポーネントを取得し、$emit('clear')clear というイベント名で引数無しの通知を送っています。$emit() の使い方は、子コンポーネントからイベントを送った時と同じです。

参考情報

子コンポーネント「絵文字ボタン・コンポーネント」を修正

絵文字ボタン・コンポーネントで clear イベントの通知を受けます。

/components/EmojiButton.vue (該当箇所のみ抜粋)

1
2
3
4
5
6
7
8
9
10
11
<script lang="ts">
import Vue from 'vue'

export default Vue.extend({
created: function() {
this.$on('clear', () => {
this.counter = 0;
})
},
})
</script>

Vue コンポーネントのライフサイクル created で、$on を使い、イベント受け取りの登録をしておきます。今回は、イベント名 clear で引数無しです。イベントを受けたらコンポーネント内の counter をリセットします。これにより、各絵文字ボタン・コンポーネントのカウンターがクリアできます。

参考情報

ソースコード

今回作成した部分までのソースを GitHub へアップしました。(Tag: 0.0.5)

GitHub Pages にホスティングもしました。動作している状態を確認する場合は、こちらへアクセスしてください。
(公開サイトは1つのため記事公開に合わせて変わり、本記事の内容とは異なることがあります)


似たようなコードをコンポーネント化し再利用できるようにしました。Vue コンポーネントを使うことで、画面内のコードもスッキリさせることができます。(同じようなものは集約してプログラムで処理したいところですよね、0.0.4 までのソースはサンプル用とはいえ心苦しかった)

一方でコンポーネント間の連携は意外と難しいところがあります。まずは親子間のイベント通知が基本です。

今回のサンプルは、スタータープロジェクトにボタンを付けたり、ロゴを回したりと地味な感じではありますが、2種類の子コンポーネント間を親コンポーネントがつなぐ形となっています。まさにコンポーネント間連携の基本なので、実装を確認いただければと思います。

[Clear] ボタンが子コンポーネントになると、兄弟間の連携となり、また一歩踏み込むことになりますが次の機会に!

httpstat.us で、簡単 HTTP クライアントのテスト

Web API などを利用するコードを書くとき、異常系の動作確認はどのようにしていますでしょうか。
サービス側でテスト用のエンドポイントが用意されているとよいのですが常にあるとは限りませんし、想定していないステータスコードもあるかもしれません。何よりレスポンスが遅い場合の確認などは難しいでしょう。そんな時に便利なサービス httpstat.us を紹介します。

httpstat.us とは

httpstat.us は、多様な HTTP Status Code をレスポンスしてくれるだけのシンプルなサービスです。

https://httpstat.us/200 のように httpstat.us の URL に欲しいステータスコードの番号を付けてアクセスするだけで、そのステータスコードのレスポンスを返してくれます。https://httpstat.us/200 なら 200 OK のステータスコード。https://httpstat.us/404 なら 404 Not Found

3桁の数字であれば 001999 のように、Hypertext Transfer Protocol (HTTP) Status Code Registry に定義されていないコードも画面表示こそ Unknown Code ですが、ステータスコードはしっかり返してくれます。

なお対応しているのは3桁のみで、2桁以下や4桁以上でリクエストするとナイスなティーポット画像が楽しめます。(ステータスコード 418 I’m a teapot - HTTP | MDN のジョークにかけているのかな?https://httpstat.us/418418 I'm a teapot と、あっさりな実装だから)

一応最後に “WE DON’T CAPTURE OR STORE ANY DATA ABOUT THE REQUESTS YOU MAKE.” とメッセージされていますが、大事なデータは送らないようにしましょう。

遅延応答

クエリーパラメーター sleep で、ミリ秒単位の遅延応答をリクエストできます。プログラム側のタイムアウトを先に起こさせたい場合などに使えます。(遅延なしでもレスポンスに2秒かかってる)

1
2
3
4
5
6
7
$ SECONDS=0; curl https://httpstat.us/200; run_time=$SECONDS; echo -e "\n"$run_time
200 OK
2

$ SECONDS=0; curl https://httpstat.us/200?sleep=5000; run_time=$SECONDS; echo -e "\n"$run_time
200 OK
7

JSON レスポンス

ヘッダーに Accept: application/json を付けると JSON でレスポンスを返してくれる、らしいのですが "200 OK" とダブルクォーテーションで囲ってくれるだけのようです。({ "status": 200, "message": "OK" } などを期待したかった)

1
2
3
4
5
$ curl https://httpstat.us/200
200 OK

$ curl -H 'Accept: application/json' https://httpstat.us/200
"200 OK"

簡単ながら HTTP Status Code をいろいろと試せるサービスの紹介でした。

実開発のテストに組み込むことはさすがにできないでしょうが、新しいライブラリの利用方法の確認だったり、エラーハンドリングの確認などを行う場合に便利です。

JSON レスポンスは期待値と異なるので OSS-Friday 案件 としてプルリクエストを出したいと思います。

共有:

ブログメンティふりかえり10週目

カック@ブロガー / k9u(@kakakakakku)さん に、ブログメンターについていただき10週間。ふりかえりの中間ポスト最終回です。いろいろ下書きしているうちに思いが詰まってきて、卒論(論文ではない)っぽくなりそうだったので、今回は軽めのサマリーにして最終回へ回します。

いよいよブログメンティー、最終月となりました。まだやり切れていないことが多々残っていますが、悔いのないブログメンタリングの日々を過ごしたいと思います。

前回の ふりかえり で書きましたが5月は激動でした。6月に入ったところでいったん落ち着きを取り戻したところですが、感動!?のフィナーレを目指してテンションを上げていきます!

シリーズの記事

ブログメンティーとしての目標設定

技術系記事を以下のペースで公開する(※ このシリーズの記事は記載するがカウント外)

  • 週1回を必達とする
  • 週2回を目標として設定する

以下の記事を書き目標を達成することができました。

9週目

10週目

各種メトリクスの推移と考察

毎週日曜日に以下のメトリクスを取得しています。こちらは達成数値のノルマとかではなく、推移を見ていただいています。

記事数

ブログメンタリング開始時からの記事数の推移です。

開始時1週目2週目3週目4週目5週目6週目7週目8週目9週目10週目
トータル2125283133363840434649
投稿数-3232222323

週間 PV

Google Analitycs で取得しています。

開始時1週目2週目3週目4週目5週目6週目7週目8週目9週目10週目
全体2324783552763051713094207001,772958
/articles82241242199205138185181271785439
@lulzneko78203225174191126168160241660397

はてなブックマーク数

サイト内の合計はてブ数を表示するツール|はてブチェッカー で取得しています。

開始時1週目2週目3週目4週目5週目6週目7週目8週目9週目10週目
全体2929303030303031314042
/articles1010111111111112121618
@lulzneko1010111111111112121618

Twitter フォロワー数

lulzneko (ラルズネコ)(@lulzneko) | Twitter を見ています。

開始時1週目2週目3週目4週目5週目6週目7週目8週目9週目10週目
@lulzneko158169170171172174176183184199206

OSS-Friday 活動

GitHub から、活動をピックアップしました。
こちらは少ないので月単位でまとめています。(一部金曜日でないけど OSS 貢献ってことで)

プルリクをたくさん出している場合は、メンターのカックさん記事「2018年のプルリクエストを振り返る - kakakakakku blog」に検索の方法があります。
また、金曜日に限定してよい場合は「オープンソース フライデー」に登録すると、ユーザーサマリーを「lulzneko | オープンソース フライデー」みたいな感じで作ってくれます。(自分リポジトリへの push も含まれてしまいますが)

開始時4月5月6月
プルリク1134

気づき、学び

タスク管理、大事

「活動量が増える=タスクも増える」ということ。やることが増えると、どうしても管理が難しくなります。
私はこの管理がすごく苦手で、ここまで増えてくると厳しくなって「Asana を導入」しましたが、まったく管理できてない💦
ToDo 管理としては、やりたかったことが列挙できているので初歩にはなったと思います。でも、まったくなってなくてツライ。

たとえば、先日書いた「Git の設定をリポジトリごとに自動で使い分ける」の記事は、思いついて設定しているうちにブログを書きたくなって、すぐに書いた流れでした。予定では Nuxt.js の続きでしたが。。。(そして次回作も、新たな思い付きに流れそうな予感)

この思い付きに振り回されていて管理できてないなぁというのを改めて気づきました。気づいたところで、どう管理するのか。。。

何事も続けるにはムリなく着実にとは思います。そのためにもスケジュールやタスク管理が必要なのだなと。とはいえ「いいこと思いついた!」的な幼児の発想力は私の原動力であり、何事にも挑戦する力になっているのでバランスしていきたいと思いました。

まだまだチャレンジすることが、たくさん

まだできていないこととしては大きく2つ。「書籍紹介、書評」と「Tips 的な記事」。

「書籍紹介、書評」はブログメンタリング期間中に確実に挑戦したいです。6月初めに挑戦したのですが、ちょっとブログを書くには難しい本(自分のレベルとして)で別の本に切り替え中です。自分のためだけのインプットとして読むのとは異なり、アウトプットを考えて読むのは難しいですね。時間切れにならないように気を付けねば。(何を読んで断念したのかは、初書籍紹介ができた時に書きます)

「Tips 的な記事」は、コンパクトな記事をイメージした表現です。ブログを書いてて文章が長いなぁと自分で思っていたりもします。その中でも伝えたいことをが増えてしまって脱線している部分もあると思うので、Tips 的な小さくて目的をはっきりした内容を作れるようになりたいです。そうすることで、どうしても長くなる記事でもスッキリできるのかなと考えています。(その Git 記事は短くしようとして結果迷走しカックさんのチェックが入りました。難しい。)

たぶん、これで技術関連ブログとしてのジャンル的にはひとおりブログに書くことの体験をできたと思うけど、どうかな🤔

IoT というか、ハードウエアやってないかな。初夏のJavaScript祭の発表 で、マイクロビットをいただいたので、こちらは調べてしっかり書きたいと思います。


残り3週間、良い習慣を身につけることの最終化と、良いアウトプットを出す品質を上げていくことをしっかりやっていきたいです。

Git の設定をリポジトリごとに自動で使い分ける

Git で開発をしている中でリポジトリによって設定を変えたいことがあります。たとえばコミット時の名前やメールアドレスなどを使い分けたいといったケースです。このような場合に有用な Git の Conditional includes を使った自動切り替えの方法について紹介します。

Git でコミットする際の名前やメールアドレス、多くの場合は全体設定 git config --global にしているかと思います。通常は問題ないのですが、リポジトリによって設定を変えたいこともあります。そのような場合は git config --local を使いリポジトリ単体の設定ができます。

しかしながら、そのようなリポジトリが増えてくるとクローンするたびごとに設定が必要となり手間です。場合によっては設定忘れでエラーになったり、悪い場合はアカウント名を間違えてコミットすることもあり得ます。できればリポジトリをまとめるディレクトリ単位などで設定したいところです。

今回は特定のパスに配置したリポジトリへ設定をインクルードする Conditional includes を使い、設定をリポジトリごとに自動で使い分けるような仕組みを紹介します。

環境
本記事の開発環境は以下となります。

  • Windows 10 64bit + WSL Ubuntu 18.04.1 LTS
  • Git 2.21.0.windows.1 (Windows 10 64bit)
    Git 2.17.1 (WSL Ubuntu 18.04.1 LTS)

参考情報

Git Conditional includes とは

バージョン 2.13.0 から追加された機能で、条件へマッチした場合に指定された設定ファイルをインクルードします。

条件は gitdirgitdir/i で指定します。
どちらも glob パターンでパスを指定して、現在のディレクトリがパターンにマッチするかで判定されます。違いは gitdir/i が大文字小文字を区別せずに判定します。

自動切り替えの設定例

設定は git config –global includeIf.”<条件>”.path “<設定ファイル>” のコマンドを実行します。
(とはいえコマンドは分かりにくいので、設定ファイルを直接編集してます)

たとえば、ホームディレクトリ以下の reposworkoss を作り、その下に関連するリポジトリを配置しているとします。

1
2
3
4
5
6
~/repos
|-- work
| `-- wondrous-product
`-- oss
|-- astounding-software
`-- local-config-service

それぞれのディレクトリ名をインクルードするファイル名の一部に使い以下のようにしました。
※ 末尾が / で終わる場合は、暗黙的に /** の glob パターンになります

1
2
$ git config --global includeIf."gitdir:~/repos/work/".path ".gitconfig_work"
$ git config --global includeIf."gitdir:~/repos/oss/".path ".gitconfig_oss"

上記コマンドを実行した際の設定ファイル ~/.gitconfig は以下のようになります。(必要箇所のみ抜粋)
※ 今回はユーザー名とメールアドレスを切り替える想定なので useConfigOnly = true でデフォルトのユーザー名を無効にしています

1
2
3
4
5
6
7
[user]
useConfigOnly = true

[includeIf "gitdir:~/repos/work/"]
path = .gitconfig_work
[includeIf "gitdir:~/repos/oss/"]
path = .gitconfig_oss

続いてインクルードされるファイル ~/.gitconfig_work~/.gitconfig_oss を作ります。

~/.gitconfig_work

1
2
3
[user]
name = Formal account name used at work
email = my-work@example.com

~/.gitconfig_oss

1
2
3
[user]
name = Cool account name used at OSS activities
email = my-oss@example.org

自動切り替えの確認

それぞれのリポジトリ用ディレクトリ ~/repos/work/~/repos/oss/ の下にリポジトリを配置して設定を確認します。どの設定ファイルが使われたかわかるように git config --show-origin --get user.name を実行します。

~/repos/work

1
2
~/repos/work/wondrous-product$ git config --show-origin --get user.name
file:/home/username/.gitconfig_work Formal account name used at work

~/repos/oss

1
2
~/repos/oss/astounding-software$ git config --show-origin --get user.name
file:/home/username/.gitconfig_oss Cool account name used at OSS activities

設定が切り替わっていること、また参照しているファイルも異なることが確認できます。
今回はユーザー名とメールアドレスを切り替えましたが、他の設定項目も同様に切り替えることができます。

注意点

  • ローカルの設定が優先される
    設定ファイルの優先度は、そのまま適用されるので globallocal では local が優先されます。今回の設定は global にしているので、local の設定がある場合はそちらが優先されます。

    1
    2
    ~/repos/oss/local-config-service$ git config --show-origin --get user.name
    file:.git/config Hot account name configured in local
  • シンボリックリンクの場合は両方設定しておく
    現在のディレクトリのパスが判定されているので、シンボリックのパスと、オリジナルのパスで有効にするには両方設定しておきます。

    私の環境は Windows 10 64bit + WSL Ubuntu 18.04.1 LTS で、Visual Studio Code のターミナルは WSL です。
    しかしながら Windows の Eclipse でも作業することがあり、リポジトリの実態は Windows 側にあり /mnt/c/develop/repos/~/repos にシンボリックリンクして使っています。(特殊なケースではありますが。。。)

    Visual Studio Code でターミナルを開くとオリジナルパスの /mnt/... が使われますが、自分でコマンドを打っているときは cd ~/repos/... のようにシンボリックリンクから移動することが多いです。このような場合にマッチするパスが変わるので両方指定しておかないと切り替えが機能しません。

    余談ですが、Eclipse は 2019年6月現在 543171 – Support for includeif in git config が上がっており includeif に対応していません。

  • Windows の場合は、パスの大文字小文字を区別したくないので gitdir/i を使う
    これはドライブレターの C:c: のレベルですでに大文字小文字の違いが出てしまうので区別しないようにします。またパスの区切りは Windows の \ ではなく、Linuxt などで使われる / です。

    1
    2
    3
    4
    5
    6
    7
    [user]
    useConfigOnly = true

    [includeIf "gitdir/i:C:/develop/repos/work/"]
    path = .gitconfig_work
    [includeIf "gitdir/i:C:/develop/repos/oss/"]
    path = .gitconfig_oss

これで作業環境ごとに git config --local で設定を追加する必要がなくなりました。
とくにアカウント名やメールアドレスは、複数の作業グループがある時に間違えコミットしないように注意が必要です。そのために useConfigOnly = true を設定しますが、そうするとリポジトリごとに設定が必要となります。その際に、今回の設定をしておくと特定のディレクトリ以下に配置しておくだけで設定が反映されるので便利です。

最近は「OSS-Friday 活動 - 2019年5月まとめ」に書きましたように、わずかながら OSS への貢献活動も始めたのでリポジトリのクローンをすることが増え、今回のようにディレクトリで自動に切り替わってくれるのは助かります。

OSS-Friday 活動 - 2019年5月まとめ

2019年5月中頃に OSS-Friday を始めてみます宣言から最初の1ヶ月が経ちました。初月の活動についてまとめます。

ブログのメンタリングを受けている中で、メンターの カック@ブロガー / k9u(@kakakakakku)さん から、使っている OSS への貢献について話がありました。使わせてもらっている以上、プロダクトやコミュニティへしっかり貢献しましょうということですね。もちろん「同意!」です。
(本件とは関係ないけど「ブログのメンタリング」って、ブログに限らず幅広く見ていただいているので実態としては何と言うとマッチするんだろ🤔)

そうした中から、どのような活動をしようかと考えていたところ、以前 IT 関連の記事で「オープンソース フライデー | 今週の金曜日は、利用しているお気に入りのソフトウエアを数時間助けてみよう。」が取り上げられていたことを思い出し、せっかくなので金曜日を OSS について考える日にしてみることにしました。

サマリー

OSS-Friday のページで GitHub のアカウント連携すると自分のページが作られます。

このページの中に GitHub での「過去3ヶ月間&過去1,000イベント」から金曜日の活動をサマリーしたものがあります。(下図、重複を取り除いてキャプチャ)

自分のところの push も出てますが、メインは以下の3つです。

ということで、最初の OSS-Friday 活動は3件でした!
以降、プルリクエストを出した背景など。

gridsome/gridsome-starter-default #10

こちらのプルリクは、2019年6月1日の「初夏のJavaScript祭 in メンバーズキャリア」で Gridsome のデモアプリを作る際に Lighthouse のスコアをとったところ <meta name="description" /> がないだけでオール 100点にならなかったので出しました。

せっかく[SEO-friendly - Gridsome]を特徴として謳っているので 100点にしておきたいところです。これは設定ファイルにデフォルト値をセットしておくだけで 100点になります。

なにより設定にデフォルトが入っていないと、設定箇所がないように見えるので開発者が気づかない、または調べるのを後回しにして設定忘れが放置される可能性もありえます。デフォルト値は意味のない値とはいえ設定が明示的に入っていることで開発者に意識を向けさせることができるのではないでしょうか。

本質的ではないですが、気になったのでプルリクを出すことにしました。

関連コンテンツ

hexojs/hexo-theme-landscape #134

こちらのプルリクは、Hexo のデフォルトテーマ landscape の Twitter 共有リンクを開いたときに URL のみだったのを、タイトルも含めるようにしたものです。

カック@ブロガー / k9u(@kakakakakku)さん に指摘されるまで気づきませんでした。。。自分が使っているものをしっかり把握しておかないとですね 😓

この共有リンクはテーマのデフォルトではダイアログに入っているのですが、本ブログでは展開して記事の一部に表示する改造をしています。そのため単純な差分が取れずに、よくコードを確認する必要がありましたが勉強になりました。また最新のコードを本ブログのテーマに取り込むきっかけにもなりよかったです。(さりげなく本家からマージした LinkedIn の共有ボタンが入ってる)

テーマ周りでも Issues が上がっていたりするので、引き続き貢献ポイントを探して活動していきたいです。

関連コンテンツ

sfarthin/ga-analytics #2

こちらのプルリクは、本ブログの開発環境を Node.js v8 から v10 にバージョンアップしたところエラーが発生したので修正したものになります。

この sfarthin/ga-analytics は、Google Analytics からレポートデータを取得するもので、本ブログでは Hexo で人気記事のリストを実現する tea3/hexo-related-popular-posts Plugin が使っています。エラーが発生しているので修正が必然だったものになります。

関連コンテンツ


5月は3件のプルリクを出せました。

まだ、どれもマージされてないのが寂しいですが、最新の2件はプロジェクトテンプレートやテーマですし内容も優先度が高くないので、じっくり待ち。

3つ目の sfarthin/ga-analytics #2 は、エラー修正なのでマージされると嬉しいな。最終更新が 2014年と5年前なのがちょっと心配。。。

気づいたところを少し修正しただけですが、結構楽しいです。
今後とも OSS へ貢献する活動をしていきたいと思います。

🚲 Let’s enjoy OSS-Friday !!

OSS-Friday 参考情報

初夏のJavaScript祭にて発表した Gridsome のサンプルアプリ実装解説

2019年6月1日の「初夏のJavaScript祭 in メンバーズキャリア」で『Gridsome で作る JAMStack なサーバーレス Web Front』の発表をした際にデモしました Gridsome のアプリについて実装を紹介します。

今回の発表用に作ったのは Gridsome を使って、Instagram から画像をとってきて並べるだけの簡単なサンプルアプリです。実装が小さいながらも GraphQL を使い、入力ソースが簡単に扱えて、それでいて画像が出るので表現がわかりやすいかと思います。具体的な実装について聞いてくださった方がいらっしゃったので実装手順を紹介します。

今回 Instagram からの入力に使っている Gridsome の Plugin @zefman/gridsome-source-instagram は、”Currently only supports grabbing the latest photos from a user’s public instagram profile. - README.md“ とのことで、ちょっとデータを取ってこれるだけのアプリになります。ご注意ください。

発表資料で扱ったサンプルアプリの紹介スライド

環境
本記事の開発環境は以下となります。

  • Windows 10 64bit + WSL Ubuntu 18.04.1 LTS
  • Visual Studio Code
  • Node.js 12.2.0
  • Yarn 1.15.2
  • Gridsome 0.6.3
  • @zefman/gridsome-source-instagram 0.1.2

Gridsome プロジェクトの初期構築

まずは @gridsome/cli でプロジェクトの初期構築をします。今回は [project name] を samples-gridsome-instagram としました。

1
$ npx @gridsome/cli create [project name]

この時点でローカルサーバーを起動して、初期状態のアプリを確認できます。
下記コマンドを実行し Gridsome が起動したら、ブラウザで http://localhost:8080/ へアクセスします。

1
2
$ cd samples-gridsome-instagram
$ yarn develop

シンプルな初期画面が表示されます。[Home] と [About] の間で高速にページの表示切替ができます。

この時点で Lighthouse(Simulated throttling (faster)) は以下のスコアを出します。(キャプチャは、GitHub Pages へデプロイして計測しています)

SEO が 91点なのは <meta name="description" /> タグがないからで、プロジェクト直下 /gridsome.config.js ファイルに siteDescription を追加することで 100点です。サイトのタイトルは siteName なので、あわせて適切な名前と説明を設定します。(以下、設定項目の全文を抜粋)

1
2
3
4
5
module.exports = {
siteName: 'Gridsome',
siteDescription: 'My Gridsome project',
plugins: []
}

デフォルト値を入れていおくプルリクを出しましたが、本質的ではないのでマージされるのは難しいかな。。。

Gridsome Plugin の導入とクエリー構築

続いて @zefman/gridsome-source-instagram を導入します。
プロジェクトのディレクトリで下記コマンドを実行します。

1
$ yarn add -D @zefman/gridsome-source-instagram

/gridsome.config.js ファイルにプラグインの設定をします。(以下、設定項目の全文を抜粋)

  • username は、取得したいインスタグラムのユーザー名です。(現在のところタグは対応していないのでユーザー名が必要で、今回は公式の instagram さんにしました)
  • typeName は、GraphQL のクエリーで、このプラグインと設定を示すのに使う文字列です。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    module.exports = {
    siteName: 'Gridsome',
    siteDescription: 'My Gridsome project',
    plugins: [
    {
    use: '@zefman/gridsome-source-instagram',
    options: {
    username: 'instagram', // Instagram username
    typeName: 'InstagramPhoto' // The GraphQL type you want the photos to be added under. Defaults to InstagramPhoto
    }
    }
    ]

この状態で yarn develop でローカルサーバーを再起動します。
起動したら http://localhost:8080/___explore へアクセスします。
GraphQL の Playground が表示されるので、左側のクエリーエディターに以下を入力して画面中央の [▷ (再生)] ボタンをクリックします。

  • photos: allInstagramPhoto は、Plugin で指定した typeName の文字列 allInstagramPhotophotos の名前で使うという指定です。
  • iddisplay_url が Instagram から取得した ID と、画像の URL です。
  • text は、Instagram のコメント(一番最初のだけ)です。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    query {
    photos: allInstagramPhoto {
    edges {
    node {
    id
    display_url
    edge_media_to_caption {
    edges {
    node {
    text
    }
    }
    }
    }
    }
    }
    }

右にある [DOCS] や [SCHEMA] タブを確認しながら欲しいデータが取得できるクエリーを作っていきます。(たとえば shortcodehttps://www.instagram.com/p/[shortcode の値] でページを表示するための文字列が返ります。)

ページの作成

/src/pages ディレクトリにページ用のファイルを作ります。URL に対応するアッパーキャメルケース(パスカルケース)の文字列でファイル名 + .vue を作ります。
今回は InstagramPhotos.vue としました。URL としては slug 化されて /instagram-photos となります(Pages - Gridsome)。
ここからはローカルサーバーを立ち上げておき http://localhost:8080/instagram-photos へアクセスした状態で作業を進めます。ホットリロードでブラウザが自動更新するので確認が容易です。

コードは下記で、基本的に Vue.js です。<page-query> タグが Gridsome 特有の GraphQL のクエリーを書くための場所になります。
また画像も Gridsome 特有の <g-image> タグで、これにより最適化されます(Images - Gridsome)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<template>
<Layout>

<h1>Instagram Photos</h1>
<span v-for="edge in $page.photos.edges" :key="edge.node.id">
<a :href="'https://instagram.com/p/' + edge.node.shortcode" target="_blank" rel="noopener">
<g-image :src="edge.node.display_url" :alt="'Instagram Photo: ' + edge.node.edge_media_to_caption.edges[0].node.text" class="photo" />
</a>
</span>

</Layout>
</template>

<page-query>
query {
photos: allInstagramPhoto {
edges {
node {
id
shortcode
display_url
edge_media_to_caption {
edges {
node {
text
}
}
}
}
}
}
}
</page-query>

<style>
.photo {
width: 144px;
margin: 0 4px;
}
</style>

レイアウトにリンクを追加

ページが作れたら、そのページへアクセスするためのリンクを作ります。(以下、テンプレート部分のみ抜粋)
[Home] と [About] のリンクがあるのは /src/layouts/Default.vue です。
サイト内のページ遷移は Gridsome 特有の <g-link> タグを使います。これによりプリフェッチが効いてページ遷移を高速化できます(Linking - Gridsome)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<div class="layout">
<header class="header">
<strong>
<g-link to="/">{{ $static.metaData.siteName }}</g-link>
</strong>
<nav class="nav">
<g-link class="nav__link" to="/">Home</g-link>
<g-link class="nav__link" to="/about">About</g-link>
<g-link class="nav__link" to="/instagram-photos">Instagram Photos</g-link>
</nav>
</header>
<slot/>
</div>
</template>

完成!

GitHub Pages にホスティングもしました。動作している状態を確認する場合は、こちらへアクセスしてください。
(公開サイトは1つのため記事公開に合わせて変わり、本記事の内容とは異なることがあります)

また、今回作成した部分までのソースを GitHub へアップしました。

発表資料

当日の発表資料と、サマリーの記事はこちらです。
もしよかったら、ご参照ください。

Gridsome で作る JAMStack な サーバーレス Web Front』の発表資料はこちらになります。(下記、スライド埋め込み)

また発表のサマリー記事は、こちらになります。


Gridsome アプリの実装例になります。

GraphQL で簡単にデータソースの内容にアクセスできるのを感じていただけたでしょうか。このように Gridsome は Source 系 Plugin を使うことでさまざまなデータソースに容易にアクセスすることができ、GraphQL として画一的に扱うことができます。いろいろなデータソースを扱っておもしろいサイトが作れそうです。

初夏のJavaScript祭 in メンバーズキャリアにて「Gridsome で作る JAMStack なサーバーレス Web Front」の発表をしました

2019年6月1日に開催された「初夏のJavaScript祭 in メンバーズキャリア」で『Gridsome で作る JAMStack なサーバーレス Web Front』と題して、JAMStack の世界と、Gridsome 導入について発表しました。その発表サマリーです。

“JavaScript祭” 概要

発表したイベント 初夏のJavaScript祭 in メンバーズキャリア は、Web デザイナー、フロントエンドエンジニア、サーバーサイドエンジニアまで JavaScript に関わるすべての人を対象にした JavaScript 好きのコミュニティー、Javascript祭り が開催するイベントです。初夏と秋の年2回開催されています。

会場は メンバーズキャリア さん。”もう迷わない!五反田駅からメンバーズキャリア本社への推奨ルート | メンバーズキャリアNOW“ が公開されていて安心の道筋です。が、迷いました。ぐるりと一周して、サイトを見直して、ようやくたどり着きました。なんと。。。

発表資料

Gridsome で作る JAMStack な サーバーレス Web Front』の発表資料はこちらになります。(下記、スライド埋め込み)

サマリー

発表の主旨は「JAMStack は JavaScript 祭り!、JavaScript から JAMStack を広めよう!!」です。

「JAMStack、好きだよね」と言われそうなほど JAMStack で発表させていただいていますが、前回の Serverless Meetup Tokyo 12 にて「サーバーレスなウェブフロントを実現する JAMStack」について発表 でふれました通り、「フロントも含めて、まるっとサーバーレスにしたい」のです。それを実現できるのが JAMStack です。

JAMStack とは

では、JAMStack とは何でしょうか。

「クライアントサイド JavaScript」「再利用可能な API」「構築済みのマークアップ」で構築されたサイトのことで、ざっくり言うと HTML に静的化されたされたサイトで、動的要素はブラウザ上の JavaScript から Web API を呼び出す形にしましょうというものになります。

これによって、すべてを CDN に配置できるので、素晴らしいパフォーマンスとスケーラビリティを手に入れることができます。そして HTML が CDN にあるだけなので攻撃対象を局所化できセキュリティを高めることができます。
また開発者の視点として、サーバー内のロジックとテンプレートエンジンが分離できます。これは表示部分とデータについて役割を明確に分離できます。役割が明確なのは開発において重要です。

そんな JAMStack なサイトを作るには「構築済みのマークアップ」を用意します。これは Static Site Generator(SSG) を使います。メジャーな Static Site Generator は StaticGen | Top Open Source Static Site Generators から探すことができます。さまざまな Static Site Generator があるので、開発言語やフレームワークに合わせて選べます。

その中でも私たちがよく使っているのは以下です。

  • Nuxt.js - Vue.js ベース、アプリのフレームとして使いやすい
  • Gridsome - 同じく Vue.js ベースで、完全に静的化した情報発信サイトに向いている

JAMStack の “J“ は、JavaScript の “J”。そして API も、Markdown も、JavaScript 作ることができるので、まさに JAMStack = JavaScript だったりします。そんなお話から、JavaScript 好きの皆さんと JAMStack で盛り上がりたいとのことで今回の発表に至りました。

アーキテクチャ紹介

Gridsome で、情報発信サイトを作るパターンです。

ソースコードのセットにある Markdown ファイルを記事として取り込む情報発信サイト、ブログのようなサイトを作る場合のアーキテクチャになります。ホスティングは AWS の CloudFront/S3 を使うことでスケールさせています。これは完全に静的なサイトとして作られているので、他にも NetlifyGitHub Pages などにもデプロイできます。

また、このアーキテクチャ図は Markdown ファイルをソースとしていますが、Gridsome はさまざまなソースを取り扱えるので、ここを変えていくとおもしろいシステムが作れます。Gridsome の Plugin は、こちら Plugins - Gridsome で、source とついているものが入力を担う Plugin です。WordPress や、ヘッドレス CMS の Contentful、Google 系などさまざまな入力ソースに対応しています。

ここのでのポイントは、HTML とは異なるソースを Static Site Generator と組み合わせることで HTML 化してデプロイするという点です。あらかじめ HTML 化してしまうので、実行時に変換する必要がないので高速に動作させることができます。

Gridsome で作る JAMStack サイト

アーキテクチャ図で出てきた Gridsome について、具体的な使い方を紹介します。

Gridsome は、Vue.js ベースのモダンで高速なウェブサイトを構築するためのフレームワークです。
とにかく高速で “builds ultra performance automatically”, “almost perfect page speed scores by default.” と公式で謳っているほどです。ウルトラ・パフォーマンスやパーフェクト・スコアと明言してくるあたりスゴいです!

そして大きな特徴として GraphQL をデータ管理の中心として持ってきているところです。これにより、さまざまなデータソースを画一的に取り扱うことができます。いろいろな組み合わせを作ることができますし、異なるデータソースを簡単に組み合わせてページを構築できることが魅力です。

サイト構築の開発も簡単です。
npx @gridsome/cli create <project name> で、スタータープロジェクトを使って初期構築。
プロジェクトのディレクトリで yarn gridsome develop でローカルサーバーを起動して、http://localhost:8080/ へアクセス。あとは Vue.js のページやコンポーネントを追加していくだけです。ホットリロードが効いているのでコードを変更するたびにブラウザがリフレッシュされるので確認も容易です。

重要な GraphQL も Vue.js と組み合わせて簡単に扱えます。何よりも http://localhost:8080/___explore へアクセスすることで GraphQL のクエリーやスキーマを確認できるのが素晴らしいです。これによりデータソースの確認が容易に行えます。

下図は Instagram をソースとして取り扱う zefman/gridsome-source-instagram と、その GraphQL のクエリーの例です。こんな感じで簡単にソースが取り扱えますし、クエリやスキーマの確認は http://localhost:8080/___explore から確認できます。

※ 猫の写真は アメショっす! さんの Instagram をお借りしました。私の SNS アイコンの猫さんも アメショっす! さんに許可をいただいて使わせて頂いているものになります。ありがとうございす 😸

JAMStack の可能性

基本的には、どのようなサイトでも JAMStack で作れると考えています。
ただし、どうにもならないのが1つ、SEO/OGP 重視で変化の激しいコンテンツ。これは JAMStack では、どうにもならないです。SEO/OGP は HTML で <meta> タグを設定する必要があります。JAMStack では HTML を事前ビルドする必要があるので、変化が激しいとビルドが回り切らない。この場合は Server Side Rendaring(SSR) にしざるを得ないです。
とはいえ、すべてがすべて SEO/OGP 重視で変化が激しいわけではないので、まずは JAMStack で作ることを考えるとよいでしょう。

まとめ

QA

Nuxt.js でも SSG できるし、また他にもツールがあるが一番早いのは Gridsome でしょうか

「どれが最速か?」となると、ベンチマークしないと、ちょっとわからないです。すみません。

ただ、たとえば Gridsome はリンクのプリフェッチの機能があります。Nuxt.js は最近導入されました。ちょっと前であれば Gridsome のが速いといえたでしょう。しかしながら、よい技術はどのツールにも取り込まれていくので「最速が必須!」とかでなければ、スキルセットなどに合わせるとよいと思います。
それは Vue.js / React のベースをどちらにするかといったところなどがあるかと思います。

GraphQL のサーバーは別途立てますか

Gridsome は GraphQL を内蔵しているので別途サーバーを用意する必要はありません。
gridsome develop を起動すると GraphQL サーバーも同時に起動するので http://localhost:8080/___explore へアクセスするだけで利用できます。また GraphQL サーバーを使うのはビルドするまでで、ビルドしたら HTML ができるので GraphQL のサーバーは不要です。

他に確認したいことなどありましたら、ぜひ[lulzneko | Twitter]へ DM 他、気軽にいただけましたら幸いです。


JavaScript のコミュニティで、お話させていただきました。

さまざまなツールやライブラリが登場する中で、JAMStack の話は緊張しました。とくに Gridsome の話は、コミッターさんの前の時間で発表という(それでいてブログメンティーの先輩でもある)💦

そんな大先輩 もっと@GatsbyJSとNetlify推し(@mottox2)さんSSRを検討する際にSSGも検討しませんか? / ssr or ssg - Speaker Deck の発表。より具体的に SSG の紹介と、SSG で困ったときに “Gatsby => Next.js、Gridsome => Nuxt.js” と移行のパスも説明されています。
こちらのスライドも必見です!

そして Javascript祭り | Doorkeeper。今回、はじめて参加させていただきましたが、登壇者さんの発表がスゴイのに加えて LT が熱い!とてもすごいイベントです。次回は秋。また参加したいです。

Serverless Meetup Tokyo 12 にて「サーバーレスなウェブフロントを実現する JAMStack」について発表をしました

2019年5月27日に開催された「Serverless Meetup Tokyo #12」で『サーバーレスなウェブフロントを実現する JAMStack』と題して、ウェブフロントをサーバーレスで実現する世界について発表をしました。その発表サマリーです。

Serverless Meetup Tokyo 概要

発表したイベント Serverless Meetup Tokyo #12 は、サーバーレス・アーキテクチャや周辺技術に関するコミュニティ Serverless のイベントで「東京」「大阪」「札幌」「福岡」で定期的に、また「沖縄」でも開催されました。

会場は Speee さん。六本木一丁目駅近くのステキな場所&素晴らしいオフィスです!

発表資料

サーバーレスなウェブフロントを実現する JAMStack』の発表資料はこちらになります。(下記、スライド埋め込み)

サマリー

発表の主旨は「フロントも含めて、まるっとサーバーレスにしよう」です。

最近 JAMStack な話でプレゼンする機会が多いのですが、私が得意としている領域はサーバーレスなサーバーサイドの開発で、フロント系はハッカソンなどで使うための必要最小限スキルセットになります。そんな私が、なぜフロントに関する JAMStack の話をするのかというと、今回の主旨「フロントも含めて、まるっとサーバーレスにしよう」を広めたいからです。

発表の背景

その「フロントも含めて、まるっとサーバーレスに」を広めたい理由を説明したく、今回の発表の背景となるスライドを作りました。

この図の下にあるスライドのキャプチャですが、左側は私たちが開発している IoT のプラットフォーム概要で、右側がアーキテクチャ概略図です。(もっとキャッチーな製品名があるのですが、資料公開の都合上とても分かりにくい名称で申し訳ない💦)

工場、販売、配送の各機能からバッチによるデータ連携や、Web API からも同様のデータ投入される機能があります。そして、それらのデータを加工して IoT 機器がアクセスする機能や、IoT のサービス・プロバイダーへデータ提供を行っています。
サーバーレス、とくに AWS Lambda の FaaS を中心とした実装になっています。

ここに関連機能としてウェブサイトを持つことになり環境構築依頼がきました。「AWS だし、ちょっと簡単に 💎 サーバー立てておいてよ。そんで運用もヨロー」と。私たちは AWS を使っていますが、FaaS を中心に DynamoDB や SNS、SQS といったフルマネージドのサービスを使っているチームです。EC2 はおろか、コンテナーさえも持っていないし運用していません。持ちたくないから FaaS にこだわって開発をしているのです。

そのチームに環境構築はともかく、運用をさせるというのは難しいものがあります。一概に AWS といっても、機能はたくさんあるわけで必ずしもすべてを使いこなせるというわけではないということです。

では、どのような形だったら良かったのか。それが JAMStack になります。

JAMStack とは

では、JAMStack とは何でしょうか。

「クライアントサイド JavaScript」「再利用可能な API」「構築済みのマークアップ」で構築されたサイトのことになります。要素だけだと分かりにくいですが、ざっくりいうと HTML に静的化されたされたサイトで、動的要素はブラウザ上の JavaScript から Web API を呼び出す形にしましょうという考え方になります。

そうすることで、さまざまなメリットが生まれます。
HTML として静的化されているので、すべてを CDN に配置することができパフォーマンスに優れ、スケールも CDN に任せることができます。そして、ただの HTML で動的要素がないので攻撃対象を局所化できてセキュリティを高められます。
また、開発者の視点としても開発対象が分離できるので役割分担が明確化します。テンプレートエンジンを使っていると、ちょっとした修正もフロントの担当なのか、サーバー側が修正するのかといった部分が出てきます。JAMStack ではフロントはフロントの担当です。サーバー側のロジックは Web API として分離しているので Web API のレスポンスまでになります。そのデータが適切でなければサーバーサイド(Web API)の担当です。役割責務が明確です。これは、とても大事なことです。

そんな JAMStack のサイトを作るには、Static Site Generator(SSG) を使います。代表的な Static Site Generator は StaticGen | Top Open Source Static Site Generators で知ることができます。利用している開発言語やフレームワークに合わせて選べます。

その中でも私たちがよく使っているのは以下です。

  • Nuxt.js - Vue.js ベースで、アプリを作る時によく使います。とても使いやすく入門しやすいです。
  • Gridsome - こちらも Vue.js ベース。完全に静的化して情報発信サイトを作るのに向いています。

アーキテクチャ紹介

Nuxt.js で、アプリを作ったパターンになります。

Nuxt.js を Static Site Generator として動作させて静的サイトを構築します。ホスティングは CloudFront/S3 になります。これにより CDN によるパフォーマンスとスケーリングのメリットを出します。

動的な要素としては、API Gateway/Lambda で JSON を返す REST な Web API を提供します。こちらはサーバーレスでシステムを構築する場合に使われるパターンと変わりはありません。私たちが REST API を作ることが多いだけで、ここは GraphQL などで API を作っても問題ありません。ここでのポイントはデータを返すことであり、HTML を生成して返すわけではないということです。

このような形にすることで、ウェブフロントもマネージドサービスだけで構築できます。サーバーレスのアーキテクチャを崩さずに済みます。

JAMStack の可能性

JAMStack は、情報発信サイトをもっとも得意としますが、上記例のようにアプリのフレームとしても活用できます。アプリを Web API 呼出しのベースとすることで、さまざまなパターンで JAMStack は適用できます。

ただし唯一苦手な領域があります。SEO 重視で変化の激しいコンテンツには向かない です。
SEO というと検索エンジン向けの話になりますが、ここでは SEO ヘッダー、埋め込み用の情報として考えてください。(OGP と言ったほうがよいのかな。)

たとえば Twitter のようなサイトを想像してください。CGM(Consumer Generated Media) で、とてつもない量の情報が作られています。そして、それぞれの情報にはツイートの埋め込みができるように SEO ヘッダーが必要となります。SEO ヘッダーは HTML の必要があり JavaScript からは設定できません。

JAMStack は、HTML を作る場合は事前ビルドする必要があります。もし Twitter を JAMStack にすると、ツイートするたびにビルドして HTML を生成する必要があります。それではツイートしてから表示するまでに時間がかかってしまいますし、ツイート数が多すぎてビルドが回らないかもしれません。

このようなケースでは Server Side Rendering(SSR) が必要となります。
とはいえ、リアルタイムの膨大なソーシャルでなければ JAMStack でサイトを作るメリットは多くあるでしょう。

まとめ

QA

US で JAMStack Conf がありました、日本でも広がるでしょうか

はい。JAMStack は急速に広がっています。日本でも広がると思います。むしろ JAMStack という用語が広がっていないだけで、実際には JAMStack なサイトを作っているケースがたくさんあると考えています。用語が認知されるだけで広がるのではないでしょうか。
また Serverless WordPress の Shifter さんと、JAMStack や Static Site Generator を広めていくことをしたいとお話をしていています。これからも JAMStack について情報発信していきたいと思います。
JAMStack Conf は、私も参加したかったのですが個人では難しかったです。。。(あと、英語力もね)

アトミックなデプロイは難しそうですが、どうしていますか

アトミックといわれると難しいイメージがありますが、私たちは AWS の CloudFormation に任せています。
現在のところ複数のビルドが走っていても、問題が発生していないので大丈夫でしょう。

認証はどうしますか、すべて HTML でしょうか

API の呼出しは制限されていませんし、認証後のプロフィール画面が外部サイトの情報の場合は API から取得した情報で構築できます。内部でしたら HTML へ静的化しておくとよいですが、HTML ファイル名ベースでの URL アクセスをされないような工夫が必要です。
JAMStack は「静的化」にフォーカスしているので、すべてを静的化(=HTML化)するように感じますが、ブラウザから JavaScript を使って Web API を呼び出すことを禁止していません。引用させていただいている資料 The JAM Stack に下図のスライドがあります。動的なシステムを Web API で呼び出して活用します。その際に必ずしも静的化する必要はありません。(どうしても静的化のメリットの話が中心になるので、誤解させてしまったかもしれません。すみません。説明の塩梅が難しい 😅)

他に確認したいことなどありましたら、ぜひ [lulzneko | Twitter] へ DM 他、気軽にいただけましたら幸いです。


本業でお世話になっているサーバーレスのコミュニティで発表させていただきました。
みなさんの集中力がすごく、ビシッとした視線に緊張しましたが、発表しきることができ良かったです。

サーバーレスというと、やはり FaaS などが話題の中心となりますが、ウェブサイトまで含めて「まるっとサーバーレス」として JAMStack への注目が高まるきっかけになったら幸いです。

ブログメンティふりかえり8週目

カック@ブロガー / k9u(@kakakakakku)さん にブログメンターについていただき8週間。隔週予定のふりかえりが遅れてしまいましたがまとめます。

最初のころのふりかえりは「日々学び」でしたが、最近は激動の1ヶ月になってきたように感じます。#ブログメンタリング、人生をも変えてしまうのか!?(大袈裟なw)

シリーズの記事

ブログメンティーとしての目標設定

技術系記事を以下のペースで公開する(※ このシリーズの記事は記載するがカウント外)

  • 週1回を必達とする
  • 週2回を目標として設定する

以下の記事を書き目標を達成することができました。

5週目

6週目

7週目

8週目

各種メトリクスの推移と考察

毎週日曜日に以下のメトリクスを取得しています。こちらは達成数値のノルマとかではなく、推移を見ていただいています。

記事数

せっかくなので追加しました。(投稿数は目標設定カウント数のみ)

開始時1週目2週目3週目4週目5週目6週目7週目8週目
トータル212528313336384043
投稿数-32322223

週間 PV

Google Analitycs で取得しています。

開始時1週目2週目3週目4週目5週目6週目7週目8週目
全体232478355276305171309420700
/articles82241242199205138185181271
@lulzneko78203225174191126168160241

はてなブックマーク数

サイト内の合計はてブ数を表示するツール|はてブチェッカー で取得しています。

開始時1週目2週目3週目4週目5週目6週目7週目8週目
全体292930303030303131
/articles101011111111111212
@lulzneko101011111111111212

Twitter フォロワー数

lulzneko (ラルズネコ)(@lulzneko) | Twitter を見ています。

開始時1週目2週目3週目4週目5週目6週目7週目8週目
@lulzneko158169170171172174176183184

気づき、学び

習慣化と継続性

ブログを書くというのはとても大変。だからこそ習慣化して継続することが大事なんだなと改めて気づきます。
そうした中で、最初に20個のテーマを考えて、また新しいことがあったらテーマを追加していくこと、リストを更新し続けることが大切です。それによって、いつでも書くことができる状態をキープできます。基本的なことですが、テーマリストを持っていないと書き始めるハードルが上がってしまい、書く手も止まりがちになるので重要なんだなと。

また、今月は仕事が忙しく、加えてハッカソン、発表とスケジュールが厳しい状況でした。そうした中で重量級な記事だとつらくなるので状況に合わせた記事を考えることなども教わりました。継続していくにはどうするのか、記事を書くだけでなく考えることも大事だと気づかされます。こういった状況に合わせた記事のテーマを考える宿題をいただいているのですが、まだ考え中。。。難しい。

また、お話(DM)していると自然と話を膨らませてくださり、テーマリストがスゴイ量になっていきます。このような発想の膨らませ方、考え方をもっと身に付けたいです。

プレゼンについても教わる!

カック@ブロガー / k9u(@kakakakakku)さん、登壇歴もスゴくプレゼンについても色々と教えてくれました。SPAJAM 2019 東京A予選 に参加した際には少しは実践できたかなと思いますが、教えていただいた内容を振り返りつつ、この後の発表に臨みたいです。

教えていただいた資料

そして、カックさんのプレゼンが見れるのはこちら!

OSS 活動

これは前回までのふりかえりでも「コミュニティへの貢献」と書きましたが、OSS などのプロダクトを利用させていただいているなかで貢献していきましょうというのは、お話をしている中でとてもメッセージを感じます。

メンターについていただいた当初からプルリクを出してみようや、ブログで使っている Hexo の SNS 共有リンクに記事タイトルを入れる では、記事の改修部分をオリジナルへ還元することの話も上がりました。

そうしたことから、せっかくなので OSS 活動について考えて行動すること始めてみようかなと。
日中に OSS の活動をすることは難しいので多くのことはできないかもしれませんが、まずは意識する日を明確に設けるということで Open Source Friday をやってみます。

書評をやってない

書評というと硬い感じですが、書籍紹介をやっていない。本を読むのは好きなのですが最近なかなか時間が取れていない。どんどん積読してしまっています。これはテコ入れをして、ブログメンティー中にしかりと書きたいです。カックさんより「書評は書く人によって全然良さが違いますもんね!」とのことで、しっかり見てもらいたいです。テーマは決まっているので「時間を作る」をしっかりやっていきます。


以上、8週目の振り返りです。

わずかとはいえ OSS 活動に手を出し始める宣言となり、まったく考えてなかったような活動まで始めるとは、まさに冒頭で書きました “#ブログメンタリング、人生をも変えてしまうのか!?” ですね。

新しいことに挑戦するきっかけをいただいたり、自分の可能性を広げたりとブログを通じて、とても良い変化が起きていると思います。引き続き良い変化を良い活動、良いアウトプットへつなげていけるように頑張ります。