ゆっくりのんびり。

いの (@inox_ee) です

【JavaScript】async constructor がしたい

はじめに

卒論で書いたコード(JavaScript SPA)があまりにも汚かったので、最近オブジェクト指向 & モダンなJSを使って書き直してます。 そんな中での一幕。

async constructor() ができない

例えば以下のようなクラスを書いたとします。

import * as THREE from "THREE"

class Hoge {
  constructor() {
    this.scene = new THREE.Scene();
  }

  addCamera() {
    this.scene.add(new THREE.Camera());
  }
}

function main() {
  const hoge = new Hoge();
  hoge.addCamera();
}

一見大丈夫そうですが、これでは Uncaught TypeError: Cannot read property 'add' of undefined と言われてしまいます。
addCamera() が非同期に実行されたため THREE.Sceneインスタンス生成が終わらぬ間に呼び出されたと推測できます。

それなら、と以下のコードを書いてみる。

class Hoge {
  async constructor() {
    this.scene = await Promise.resolve(new THREE.Scene());
  }
  // 以下略
}

これも残念ながら Uncaught SyntaxError: Class constructor may not be an async method と言われてしまいます。コンストラクタにはasyncがつけられない模様。

現状の対応

とりあえずこんな感じで書いてる。

class Hoge {
  constructor() {
    this.scene = null;  // 当然だが無くても動く。プロパティを明示するために書いたが、TypeScript使えやと言われそう。
  }

  static async build() {
    const hoge = new Hoge();
    hoge.scene = await Promise.resolve(new THREE.Scene())
    return hoge;
  }

  addCamera() {
    this.scene.add(new THREE.Camera());
  }
}

async function main() {
  const hoge = await Hoge.build()
  hoge.addCamera()
}

自分の思いつく範囲では、「インスタンスをPromiseで返す」か「コンストラクタ単体でのインスタンス生成を諦める」かの2択になる。前者はさすがに気持ち悪い(instance.then(...) は違和感しかないだろ…)ので、後者を選択。コンストラクタ以外ならクラスメソッドもインスタンスメソッドでもasync構文が使えるようなので、 new THREE.Scene() を待ってプロパティに格納する。

私はJSょゎょゎなので、これ以外の方法があればご教授ください。

あとがき

最近オススメのVTuberは、断然にじさんじ所属の葉加瀬冬雪(通称 はかちぇ)。先日遂にメンバーシップに加入してしまった...。
ゲームがそれほど上手いわけじゃないけど、「指示厨殺し」だけど いつも楽しそうに配信している姿は元気もらえます。

youtu.be

実は歌も上手いんですよねぇ…。この空奏列車のカバーを初めて聞いたときは本当に心が震えました。今日公開のオリ曲にも期待。

Kubernetesの勉強

はじめに

ネットワーク研にいるのに、k8s も知らないのはなんかダメだなぁと思ったので勉強してみる。

参考

www.shoeisha.co.jp

kubernetes とは?

Kubernetes とは、オープンソースコンテナーオーケストレーションツールである。

そもそもコンテナとは

コンテナとは、ホスト OS 上に論理的な区画を作り、あるアプリケーションを動作させるのに必要なモジュール(ライブラリとかアプリケーションとか)を一つにまとめたもの。

なぜ他の仮想化技術に比べて軽量?

コンテナは Linux の通常のプロセスとほぼ同じ処理らしいが、それぞれのプロセスを 1 つのグループとして管理する(Linux で言えば namespace や cgroups などのカーネル機能とか) ことで、名前空間やリソースを他のプロセスやコンテナから隔離することができる。

  • ホスト型
    • Oracle VM VirtualBox など
    • ゲスト OS over 仮想化ソフトウェア over ホスト OS over ハードウェア
  • スーパバイザ型
    • Windows Hyper-V など
    • ゲスト OS over ハイパーバイザー over ハードウェア

Docker の特徴

Docker は、「コンテナ型仮想化」の代表例。

Docker が出来ることは、

  • コンテナの作成
  • コンテナの実行
  • コンテナ内でファイルシステムとして使われるイメージの作成・管理

逆に出来ないことは、

  • ネットワークのルーティング
  • 複数コンテナの連携
  • 複数台のサーバを対象としたコンテナの横断的な管理

コンテナオーケストレーションツールの必要性

コンテナオーケストレーションツールとは、すなわちコンテナを統合管理できるツールのこと。

シングルホストでは手軽なコンテナも、マルチホストで運用する際は、以下のような要求を満たさなければならない。

  • コンテナの操作(起動、停止、削除)
  • ホスト間のネットワーク接続
  • ストレージ管理
  • コンテナ-ホスト間のスケジューリング機能

Kubernetes

特徴

  • 複数サーバでのコンテナ管理(グルーピング)
  • コンテナのデプロイ
  • コンテナ間のネットワーク管理
  • コンテナの負荷分散
  • コンテナの監視
  • コンテナのアップデート
  • 障害発生時の自動復旧

アーキテクチャ1

k8s アーキテクチャ概要図 (https://github.com/kubernetes/kubernetes/blob/release-1.3/docs/design/architecture.md)

k8s-arch

コンポーネント

k8s は、1) マスターコンポネント と 2) ノードコンポネント により成る。

  • Master
    • k8s クラスタ全体を管理
    • コンテナを起動する Node を自動的に選択する
    • API Server
      • k8s のリソース情報を管理するための API
      • コンポーネントからのリソース情報を受け取り、データストア上に格納する
      • kubectl コマンドを使って操作する
    • Scheduler
      • Pod をどの node にデプロイするかを制御
    • Controller Manager
      • クラスタの状態を監視し、あるべき状態を維持する
    • データストア etcd
  • Node
    • コンテナアプリケーションを動作させるサーバ群
    • ノードは複数台でクラスタを構成
    • kubelet
      • Pod の定義ファイルに従ってコンテナを実行したり、ストレージをマウントしたり。
      • Node のステータス管理も行う

リソース

  • Pod
    • 複数のコンテナをまとめたもの
    • アプリケーションのデプロイの単位となる。
    • 同じ Pod のコンテナは、同じ Node 上に構築される。
  • ReplicaSet
    • クラスタ内で指定された数の Pod を起動しておく仕組み
  • Service
    • Kubernetes のネットワークを管理。
    • コンテナアプリケーションへのアクセス方法を決めるリソースのこと。
    • ポート番号やプロトコル、負荷分散のタイプなどを設定。

コンセプト

インフラ構成管理

今まで これから
オンプレ クラウド
メンテナンス 仮想化
長期運用 Immutable Infrastructure
システム構築の手順や変更履歴を管理 宣言的設定
  • Immutable Infrastructure
    • 一度構築したインフラは変更を加えない。
    • 変更または不要となった場合は、破棄して新しいものを作る。
  • 宣言的設定
    • システムの状態を管理
    • 自己修復が可能

Kubernetes を支える仕組み

  • スケジューリング
    • アプリケーションを適切なところにデプロイする仕組み
  • サービスディスカバリー
    • デプロイされたアプリケーションがどこに(サーバまたはノード)あるか見つけ出す
  • 構成レジストリ
    • サービスディスカバリーに用いる、インフラとサービスを動的に紐づけるもの。

Azure

リソースグループ

  • Azure が管理する、論理的な単位。
  • Azure ユーザが使うレジストリもこのグループで分割管理してそう。

Azure Container Registry

コンテナイメージの共有サービス。

  • 複数リージョン間でのレジストリ管理
  • セキュリティと CI/CD 管理
  • コンテナイメージの自動ビルド

Azure Kubernetes Service

Kubernetes クラスタを管理するパブリッククラウドのサービス。

サービスプリンシパル

ACR 内のコンテナイメージを取得するためのアクセス権限を、AKS に与えるために用いる。

作業

[ACR] コンテナイメージの作成

  1. リソースグループの作成
    $ az group create --resource-group $ACR_RES_GROUP --location japaneast
  2. レジストリの作成
    $ az acr create --resource-group $ACR_RES_GROUP --name $ACR_NAME --sku Standard --location japaneast
  3. サンプルコード(コンテナイメージ)の clone
    $ git clone git@github.com:ToruManabe/Understanding-K8s
  4. イメージのビルド
    $ az acr build --registry $ACR_NAME --image photo-view:v1.0 v1.0/

これを k8s クラスタ上で pull して動かす。

[AKS] 連携

  1. サービスプリンシパルの作成
    $ az ad sp create-for-rbac --name $SP_NAME --role Reader --scopes $ACR_ID --query password --output tsv
  2. クラスタの作成
    $ az aks create --name $AKS_CLUSTER_NAME --resource-group $AKS_RES_GROUP --node-count 3 --kubernetes-version 1.11.4 --node-vm-size Srandard_DS1_v2 --generate-ssh-keys --service-principal $APP_ID --client-secret $SP_PASSWD

ここでエラー発生…

Operation failed with status: 'Bad Request'. Details: The VM size of AgentPoolProfile:nodepool1 is not allowed in your subscription in location 'japaneast'. The available VM sizes are ...

とのこと。

仕方ないのでポータルの方を見に行く。確かに、利用できる VM のサイズは限られており、「汎用」ファミリは使えないよう。なんでや。

未指定も怖いので、とりあえず一番安い Standard_F2s_v2 にしてみる。

また怒られた。

Operation failed with status: 'Bad Request'.
Details: Provisioning of resource(s) for container service testAKSCluster in resource group testAKSCluster failed.
Message : Operation could not be completed as it results in exceeding approved Total Regional Cores quota.

Additional details - Deployment Model: Resource Manager, Location: japaneast, Current Limit: 4, Current Usage: 0, Additional Required: 6, (Minimum) New Limit Required: 6.
...

よく分からないが、作成したリソースグループの容量の都合上、作成できるノード数が 2 つまでだったらしい。CLI だとこういう問題の同定がしづらいよな…
以下でようやくクラスタが作成できた。なお、2020/04/02 現在、既定の k8s version は、1.15.10であった。

$ az aks create \
    --name $AKS_CLUSTER_NAME \
    --resource-group $AKS_RES_GROUP \
    --node-count 2 \
    --node-vm-size Srandard_F2s_v2 \
    --generate-ssh-keys \
    --service-principal $APP_ID \
    --client-secret $SP_PASSWD

アプリケーションのデプロイ

  • マニフェストファイルの作成
    • クラスターにどのようにアプリケーションをデプロイし、クライアントからのアクセスをどう処理するかの構成情報を定義する。
    • misc
      • どのようなアプリケーションを起動したいのか
      • どのくらいの CPU やメモリなどのコンピューティングリソースが必要か
      • ネットワークアドレスはどう割り当てたいか
    • service の設定も
      • K8s クラスター上で動作させた Pod に、クライアントからアクセスするためのサービスの設定
      • P.53 の図が分かりやすい。

【Scala】勉強ログ(更新一時停止)

追記(2020/04/10)

sbtを操作すると頻繁にPCが落ちるようになった(なんで?)ので一旦やめ。

まえがき

ただの個人用勉強ログです。
COVID-19 の おかげ せいで N 予備校の講座が無料で見れるのでやっていく。

Scala とは?

環境

  • WSL1
  • Open JDK 11.0.3(?) for Linux (以前入れたっぽい)
  • sbt 1.3.8 (Scala Build Tool?)
  • VSCode
  • Scala (Metals) : VSCode の拡張。これだけで補完と format が効くっぽい。2020?年から ENSIME から Metals へ移行したよう。

REPL 立ち上がらない

sbt console
>>> [warn] No sbt.version set in project/build.properties, base directory: /$CURRENT_DIRCTORY/Go-Tutorial
>>> [error] java.nio.file.AccessDeniedException: /$HOME/.cache/coursier
>>> [error] Use 'last' for the full log.
>>> Project loading failed: (r)etry, (q)uit, (l)ast, or (i)gnore? r

なぜか ~/.cache の所有者が root だったので自分に変更。

sudo chown [username]:[groupname] ~/.cache

数値表現

値型 範囲 記述例
Byte 1 Byte 符号付き整数 1.toByte
Short 2 Byte 符号付き整数 1.toShort
Int 4 Byte 符号付き整数(-214748368 ~ 2147483647) 1
Long 8 Byte 符号付き整数 1L
Float 4 Byte 浮動小数点数 1.0F
Double 8 Byte 浮動小数点数(-1.7976931348623157E308 ~ 1.7976931348623157E308) 1.0

Map()(連想配列) の更新

今までのイメージ

// JavaScript
aaa = { a: 1, b: 2 };
aaa["a"] = 3;
console.log(aaa) >>> { a: 3, b: 2 };

Scala

// 更新というか新規作成
val aaa = Map(2->1, 3->2)
val aaa2 = aaa + (3 -> (aaa.getOrElse(3, 0) + 1))  // 二重かっこにするのを忘れないように。
println(aaa2)
>>> Map(2 -> 1, 3 -> 3)

文字列検索

索引型検索

  • 文章のなかから予め単語の文字列を抜き出して、その単語ごとに索引を作っておく
  • 単語ごとに、対象の文章の中の頻度や場所に応じてスコアが計算される
  • 例)検索エンジンなど

非索引型検索

  • 与えられた文字の情報のみで検索
  • 検索のたびに、対象の文章データを全て走査

文字列String

  • Scala の String 型は、Java の String 型を踏襲。APIJava 11 String を参考。
  • 基本的にダブルクォーテーションを使う。シングルクォーテーションは Char 型。

ビット演算

計算 演算子 記述例 結果 補足
ビット単位 AND & -1 & 2 2
ビット単位 OR | -1 | 2 -1
ビット単位 XOR ^ -1 ^ 2 3
ビット単位補数 ~ ~0 -1 全ビットを反転させる
右ビットシフト(MSB 埋め) >> -1 >> 31 -1
右ビットシフト(0 埋め) >>> -1 >> 31 1
左ビットシフト(0 埋め) << 1 << 1 2 2 のべき乗

ビット演算を使ってアルゴリズムを考えられるようになりたい

用語

用語 説明
構文(Syntax) class, val, if プログラムが構造を持つための規則
式(Expression) 1, 1+1, "hoge" 評価することで値となるもの
評価 Scala の式をコンパイルすること
文(Statement) val i = 1 評価しても値にならないもの。

Unit

ifwhile といった式は()を返す。これはUnit と言われる型のオブジェクトの値である。

C 言語や Java でいうところの void にあたる。

クラスとオブジェクト

クラス

簡単に言うと、「複数のオブジェクトを作るためのひな形」。

クラスから作られるオブジェクトを「インスタンス」、状態を「フィールド」、振る舞いを「メソッド」と言う。またフィールドとメソッドを合わせて「メンバー」という。

ケースクラス

ふつうのクラスとほぼ一緒。
ケースクラスは不変なデータを作るのに適しており、パターンマッチングで有用である。

例えば変数宣言におけるパターンマッチは、タプルによる分割代入のような値の取り出しのことを指す。

case class CPoint(x: Int, y: Int)

val cp1 = CPoint(5,6)
val CPoint(a, b) = cp1

>>> a: Int = 5
>>> b: Int = 6

一瞬、val CPoint() って何やと思うけど、ここで大事なのはa, bの方。

その他、sealed classを用いることで enum を実装できる。逆に Java にはあるのになんで Scala はこれなんだろうか…

なお上記で「ほぼ一緒」と言ったが、通常のクラスと「同値性」が異なる。

簡単に言えば、ケースクラスではインスタンスが異なる場合であっても持っているフィールドが同じであれば同値と見なされる。値っぽい挙動。

ちなみに hashCodeequalsというメソッドをオーバーライドすれば通常のクラスにおいてもこの同値性を変更することが出来る。

オブジェクト

数あるオブジェクトの中でも、object キーワードを使って作成したオブジェクトは、他と異なりたったひとつのインスタンス(これを「シングルトンオブジェクト」という)しか持たない。Scala では「オブジェクト」という単語が、一般的なオブジェクト全般を指す場合と、シングルトンオブジェクトを指す場合とがあるので注意。

ユースケースとしては

  • グローバルな状態やユーティリティメソッドを表現するため
  • オブジェクトを作り出すためのメソッドを提供するため
  • アプリケーションなどのシングルトンオブジェクトをつくるため

があげられる。

コンパニオンオブジェクト

コンパニオンオブジェクトとは、クラス名と同じ名前を持つオブジェクトのこと。 applyメソッドを定義することで、new演算子を利用せずにインスタンスを作ること(これを「ファクトリメソッド」という)ができる。

なんでコンパニオンオブジェクトがあるの?(めっちゃ重要)

なんでclassだけじゃなくてobjectでコンパニオンオブジェクトを書かなきゃいけないのか全く分からなかったが、以下の記事を読んで納得できた。

https://qiita.com/geshi/items/0a789724b2419bd56204

意識しなければいけないのは、Scala は静的型付け言語であること。
先のブログの文章を引用すると、

しかし、静的型付き言語ではクラスに型を定義する必要があるので(Ruby と違うところ)、 型を定義されたクラスと、クラスを生成するものが必要となります。

ということになる。なので Scala で書くクラスには大概 object が必要となる(多分)。そしてその機能としては initialize メソッドとほぼ同じと考えていてよさそう。

ちなみにクラスに対して定義するものはコンパニオンオブジェクト、インスタンスに対して定義するものはクラスに書く。

【WSL】Windowsファイルの権限変更(+VSCode Remote Developmentの実行)

TL;DR

  1. WSLからマウントしたWindowsファイルシステム群のデフォルトパーミッションを変更した備忘録
  2. 脳死でファイルのパーミッション644 にすると、VSCode Remote Development が実行できなくて死ぬ
  3. 誰か適切な権限教えて乁(˙꒳˙乁)クレヨ......

WSLのパーミッション変更

デフォルトパーミッション

WSLからマウントしたWindowsファイルシステム群 (以下WSL-WinFS)は、デフォルトではパーミッションが777(= -rwxrwxrwx)とされています。つまり「『所有者・所有グループ・その他』が『読み込み・書き込み・実行』可能」ということ。さすがに気持ち悪いので、変更しましょう。

やり方

Linuxコマンド umask により変更することも可能ですが、WSLを立ち上げるたびに設定が初期化されてしまう(らしい)ので、/etc/wsl.conf に設定を書き込む*1 ことでこれを保持しましょう。初期状態ではおそらく存在しないので、新規作成します。

# /etc/wsl.conf の中身 <- comment
[automount]
enabled = true
root = /mnt/
options = "metadata,fmask=133,dmask=022"

権限に関するオプションを以下に抜粋。

  • fmask
    • すべてのファイルに対して除外するアクセス許可の 8 進数のマスク
  • dmask
    • すべてのディレクトリに対して除外するアクセス許可の 8 進数のマスク
  • umask
    • すべてのファイルとディレクトリに対して除外するアクセス許可の 8 進数のマスク

上記confファイルにより、dmask=022は777 - 022 = 755、すなわち drwxr-xr-xfmask=133は777 - 133 = 644 すなわち -rw-r--r-- となります。

補足1: 権限記号読み方

権限記号は、

  • 先頭1文字目がディレクトリorファイルの識別(dor-)
  • 以降3文字区切りで「所有者」「所有グループ」「その他」ごとの権限

を表現しています。

また権限は以下の表にもとづいて、数値で表されます。

記号 権限 数字
r 読み込み 4
w 書き込み 2
x 実行 1
- 権限なし 0

これより、-rwxrwxrwx777(= 4+2+1 / 4+2+1 / 4+2+1)、-rw-r--r--644(= 4+2+0 / 4+0+0 / 4+0+0)というように8進数表記に変換されます。

補足2: /etc/fstab

マウントに関する設定としては/etc/fstabを作成する方法が一般的(?)と思われますが、上記URLでも述べられているように

注: これらのオプションは、自動的にマウントされたドライブすべてのマウント オプションとして適用されます。 特定のドライブのみのオプションを変更するには、代わりに /etc/fstab を使用します。

という使い分けがなされるようです。自分の場合はCドライブしかないのでwsl.conf を用いました。

ちなみに、bashzshの場合 .profileumask 022 と記述する方法もありますが、Rails等で自動生成されるファイルはそれに従ってくれないらしいです(要検証)。

VSCode Remote Developmentの起動

VSCode Remote Development(以下VS-RD) により、WSLを利用した開発がかなり快適になりました。WSL2が実装されればもう言うことなしです(それもうUbuntuで良くない?)。

さて、VS-RDを起動してみましょう。前述のパーミッション変更により、当然Permission Denied と言われ、接続に失敗します。しかたないのでWarningのポップアップの隙間から見える $HOME(多分)/.vscode/extensions/ms-vscode-remote.remote-wsl-0.42.3/scripts/wslCode.sh をchmodで644->755に変更します。

しかしまだ起動せず……。
エラーログも見えないのでどのファイルを実行しているかもよく分かりません。うーむmm…。

結局

fmaskとdmaskで各々権限を設定せず、umask=022で一括755にして現状対処することに。このあたりの "Linux感" がまだ身についてないのでこのままで良いか怪しいところ…。

変にいじってパーミッション破壊を起こしたくもないので放置。書きながらユーザ・権限周りの知識が怪しいことに気づいたので再度OSの授業を復習しようと決めました。以上。

【latex】overleaf(uplatex) でディレクトリ構造の図を書く

まえがき

latexでツリー図を書こうと思ったが、Overleafでは tree.sty が使えない1ので、代替packageを探した。 意外と記事がヒットしなかったので簡単にまとめる。

描画したい図

一般的な木構造に加え、ディレクトリ構造も描画できると嬉しい。

結論: forest package

個人的にはforest が最適だったのでこれを紹介する。ちなみに公式docでもお気持ち紹介されている2

www.ctan.org

Tikzをベースにしているので、オプション等は共通した文法である。例) grow'=0

描画可能な図(一例)

f:id:puyobyee18:20191224132545p:plainf:id:puyobyee18:20191224132550p:plain
tree & dirctories

書き方

上述の図のソースコードは以下の通り。

% main.tex
\documentclass[11pt, uplatex]{jsreport}
\usepackage[edges]{forest}

% 場合によっては以下も必要かもしれない。自分の環境では不要だった。
% \usepackage{tikz}
% \usetikzlibrary{trees}
% tree

\begin{forest}
 [VP, for tree={parent anchor=south, child anchor=north}
 [DP[John,tier=word]]
 [V’
 [V[sent,tier=word]]
 [DP[Mary,tier=word]]
 [DP[D[a,tier=word]][NP[letter,tier=word]]]
 ]
 ]
\end{forest}
% directory

\begin{forest}
 for tree={grow'=0,folder,draw}
 [/
  [home
   [saso
    [Download]
    [TeX]
   ]
   [alja]
   [joe]
  ]
  [usr
   [bin]
   [share]
  ]
 ]
\end{forest}
% 念のためlatexmkrc
$latex = 'uplatex';
$bibtex = 'pbibtex';
$dvipdf = 'dvipdfmx %O -o %D %S';
$makeindex = 'mendex %O -o %D %S';
$pdf_mode = 3; 

詳細は http://ftp.jaist.ac.jp/pub/CTAN/graphics/pgf/contrib/forest/forest-doc.pdf を参照されたい。

注意

上述のdirectory を描画する際、コードにインデント(スペース1つで良い)をつけないと以下のように、Package pgfkeys Error: I do not know the key '/tikz/grow' というエラーが発生した。latexのブロック定義ってインデントだっけ?

f:id:puyobyee18:20191224132549p:plain
Package pgfkeys Error: I do not know the key '/tikz/grow'


  1. overleaf で使えるパッケージのリスト(公式Doc) に含まれていない。

  2. Using the forest package to create trees in LaTeX - Overleaf, Online LaTeX Editor

【GitHub】草、生やしていますか?

はじめに

いの です。
とある事情で2月までデスマ状態なのですが、VTuberを見ながらどうにか精神を保っています。

GitHubのContributionについて

いわゆる「草」です。
最近までインターンもやっており、研究の進捗もgit管理しているのできっと大草原になっていることだろう…と思ったものの、

f:id:puyobyee18:20191011130650p:plain
gh_pre_contribution

砂漠地帯ですね…
さすがにもう少し進捗を産んでいるのでは?と思い、公式doc*1を見直してみました。

曰く、

  • The email address used for the commits is associated with your GitHub account.
  • The commits were made in a standalone repository, not a fork.
  • The commits were made:
    • In the repository's default branch (usually master)
    • In the gh-pages branch (for repositories with Project Pages sites)

このうち自分は1つ目の「メールアドレスの設定」を見逃していたようです。早速修正しましょう。

contributionに関連するメールアドレス

今回登場するメードアドレスには以下の2種類があります。

  • GitHubのアカウントに登録されているメアド
  • commitに紐付いているメアド

一つずつ見ていきましょう。

GitHub

これは GitHubに紐づく メアドです。
Github > Settings > Public profile > Public email」から適当なメールアドレスを選択します。自分の場合、そもそもメアドをpublicにしていなかったので、「Settings > Emails」内の Keep my email addresses private のチェックを外しました。

Git側

ローカル の設定も確認しましょう。
該当するディレクトリで git config user.email コマンドを打つことで確認できます。先程GitHub側で設定したメアドと一致しているか確認しましょう。
なお、 --global オプションをつけることでグローバルの設定を一括で変更できますが、どうやらcontributionに反映させるには各ディレクトリからpushしないといけないようです。

おわり

以上の操作が済んだらprofileページで確認してみます。きっとcontributionに草が生い茂っていることでしょう。

f:id:puyobyee18:20191011130643p:plain
gh_contributions

まぁまぁだな…

あとがき

先日はVsingerの花譜を紹介しましたが、今回紹介するのはにじさんじ所属の「健屋花那(すこやかな)」さんです。

youtu.be

デビューから数週間にもかかわらず、登録者数は8万人越え。見た目はもちろんのこと、滲み出る博識さも気に入っています。 まぁなにより可愛いんですけど。

なにかと魅力的なナース姿であることもあってか、ファンアートも充実しています(ハッシュタグ #いらすこや で検索!)。
けろりらさん作のアニメーション(https://twitter.com/kerorira1/status/1182243727219163136)もかなりの人気度。本人のことを知らない人でも思わず手を止めてしまうのではないでしょうか…

【Node.js】Webpack でバンドルしたファイル群を Heroku にデプロイしたときに環境変数を適切に使いたい

タイトルながい

あらすじ

Github Pages をはじめ、シンプルな HTML と JS で構成された web ページなら無料で公開できるサービスは五万とあります。

ただ今回自分の作ったものには API key が含まれていたため、Heroku にデプロイすることにしました。
Heroku なら設定も楽だし大丈夫っしょ~~なんて思ってたら 1 日溶けました。つらい。
つらいのでブログにまとめました。誰かの 1 日を守れたら幸いです。

構成

<project>
|_ app/
    |_ index.html
    |_ src/
        |_ index.html
        |_ index.js
    |_ dist/
        |_ bundle.js
|_ .env(git管理外)
|_ webpack.config.js
|_ package.json
|_ app.js

やりたいこと

node ./app.js でexpressを用いたサーバを立て、src/ 以下の index.htmlindex.js を読み込む静的ページを構成。
この js ファイル内で API key を使用するため、.env環境変数を入れておきます。
また index.js は他モジュールを読み込んでいるので babel で es5 へ変換しつつ webpack でバンドルさせます。

1. dotenv

ググったらいっぱい出てくるので説明は割愛。

環境変数.env ファイルで管理するときに用いられるモジュールとして有名なものですが、webpack でバンドルしてしまうとバンドル後の js ファイルに直接書き込まれてしまうっぽい。secure じゃないので却下。

2. dotenv-webpack

上記の問題を解決した(?)モジュールが dotenv-webpack
これは dotenvWebpack.DefinePlugin をラップしたもので、環境変数の呼び出し方はほとんど dotenv と相違ありません。

github.com

dotenv は js ファイル内で require('dotenv').config() と呼び出していましたが、dotenv-webpackwebpack.config.js 内に諸設定を書き込みます(以下参照)。

/* webpack.config.js*/
const Dotenv = require('dotenv-webpack');
module.exports = {
  // 中略
  plugins: [new Dotenv()],
  // 中略
};

これで OK。 あとは呼び出したいところで process.env.SAMPLE_API_KEY と書けば API key が使用できます。

2. 余談

ちなみに .env: でなく = なので注意。

# .env
SAMPLE_API_KEY="hogehoge"

3.Heroku へのデプロイ

Heroku で環境変数の管理をするなら heroku-config をインストールしましょう。楽です。説明は割愛。

ローカルでも動くしあとはdeployだけすればおっけー!なーんて思ってたら

f:id:puyobyee18:20190714120431p:plain

うーん

結論

ローカルなら動く、さらに言えば手元でバンドルしてからデプロイしたらAPIが正しく設定されるようのでHeroku側でwebpackを動かしたときに config vars が読み込めていないっぽい。

一行一行設定を変えつつデプロイして、を繰り返した結果、 webpack.config.js に以下の設定を加えることで解決した。

plugins: [
  new Dotenv({
    systemvars: true,
  }),
],

公式のREADME曰く、

load all the predefined 'process.env' variables which will trump anything local per dotenv specs.

ということらしいのだが、なぜこの設定で行けるようになるのかは謎。

とりあえずデプロイできてよかった。

私の webpack.config.js

諸事情によりレポジトリは公開できませんが、package.jsonwebpack.config.js だけ公開しておきます(一部改変)。参考にしてください。

/* package.json */
{
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node ./app.js",
    "deploy": "git push heroku staging:master",
    "build": "npx webpack",
    "heroku-postbuild": "webpack -p"
  },
  "devDependencies": {
    "dotenv-webpack": "^1.7.0",
    "eslint": "^5.16.0",
    "eslint-config-prettier": "^4.3.0",
    "eslint-plugin-prettier": "^3.1.0",
    "prettier": "^1.17.1",
  },
  "dependencies": {
    "webpack": "^4.35.3",
    "webpack-cli": "^3.3.5",
    "@babel/core": "^7.5.4",
    "@babel/preset-env": "^7.5.4",
    "babel-loader": "^8.0.6",
    "@babel/polyfill": "^7.4.4",
    "express": "^4.17.1",
  }
}
/* webpack.config.js */
const path = require('path');
const Dotenv = require('dotenv-webpack');

module.exports = {
  // メインとなるJavaScriptファイル(エントリーポイント)
  // aync/await を使うには `@babel/polyfill` を以下のように設定する
  entry: ['@babel/polyfill', './app/src/index.js'],

  // ファイルの出力設定
  output: {
    //  出力ファイルのディレクトリ名
    path: path.resolve(__dirname, 'app/dist'),
    // 出力ファイル名
    filename: 'bundle.js',
  },

  node: {
    fs: 'empty',
  }, // これもよく分からないけどとりあえずemptyにしておけば動いた。
  mode: 'development',
  plugins: [
    new Dotenv({
      path: path.resolve(__dirname, './.env'), // いらないかも。
      systemvars: true,
    }),
  ],
  module: {
    rules: [
      {
        // 拡張子 .js の場合
        test: /\.js$/,
        use: [
          {
            // Babel を利用する
            loader: 'babel-loader',
            // Babel のオプションを指定する
            options: {
              presets: [
                // プリセットを指定することで、ES2019 を ES5 に変換
                '@babel/preset-env',
              ],
            },
          },
        ],
      },
    ],
  },
};

あとがき

最近、Vsinger の 花譜 ちゃんにめちゃくちゃハマっています。
15 歳と思えぬ力強い歌声、カンザキイオリさんの楽曲の魅力を持て余すことなく歌い切る表現力 ――――― 。

今後も、もっともっと活躍してほしいです。
8/1 の初の単独ライブ『不可解』、院試のせいで行けないので泣いてる。2nd LIVE に期待。

youtu.be

ラプラスかわいい