Go + Vue.js + Docker でSPAを作るまで - 第2章 Vue CLI でアプリケーション開発環境を準備する(TypeScript, Stylus使用) -

Vue CLIでプロジェクトを作成(アプリケーション開発環境を準備する)には サブコマンドの createを使用する。
※ 2.x系ではvue initを使用していたが、3.x系ではvue createなので注意
基本的には公式の情報こそ正義だと思っているので、まずはそれをみるといいと思います。

cli.vuejs.org

ここでは手順の確認を行うだけなので適当な名前のプロジェクト名の開発環境をセットアプする。

vue create test-project

すると以下のような選択を求められる。defaultを選択すると基本的なBabel + ESLintセットアップと、
付属のデフォルトプリセットでプロジェクトが開始される。
後からTypeScript等を導入することも可能らしいが、自動でセットアップしてもらったほうが安心なので、
今回はManually select featuresを選択する

 Vue CLI v3.0.4
? Please pick a preset:
  default (babel, eslint)
❯ Manually select features

すると以下のような選択画面に移行する。
英語で書いてある通り、キーで選択の on/offができる(カーソルを移動させれるとその説明が消えるので注意)
ここでは TypeScriptCSS Pre-processorsを追加で選択する。 Vue RouterやVuexが必要な場合はそれも選択。

Vue CLI v3.0.4
? Please pick a preset: Manually select features
? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection)
❯◉ Babel
 ◉ TypeScript
 ◯ Progressive Web App (PWA) Support
 ◯ Router
 ◯ Vuex
 ◉ CSS Pre-processors
 ◉ Linter / Formatter
 ◯ Unit Testing
 ◯ E2E Testing

すると以下のように追加の設定を求められる。
特にPick a CSS pre-processorでは今回はStylusにするのを忘れないように。。。

? Use class-style component syntax? (Y/n) Y
? Use Babel alongside TypeScript for auto-detected polyfills? Y
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): (Use arrow keys)
  Sass/SCSS
  Less
❯ Stylus
? Pick a linter / formatter config: (Use arrow keys)
❯ TSLint
  ESLint with error prevention only
  ESLint + Airbnb config
  ESLint + Standard config
  ESLint + Prettier
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)
❯◉ Lint on save
 ◯ Lint and fix on commit
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? (Use arrow keys)
❯ In dedicated config files
  In package.json
? Save this as a preset for future projects? (y/N) N

それらの設定が完了するとセットアップが進行し、最終的に以下のような内容がターミナルに出力する。

🎉  Successfully created project test-project.
👉  Get started with the following commands:

 $ cd test-project
 $ npm run serve

あとは指示の通りnpm run serveを実行して起動できればとりあえずのセットアップは完了です。

Go + Vue.js + Docker でSPAを作るまで - 第1章 Vue CLI を導入する -

まずはフロント部分で使用するVue.jsの環境構築をVue CLIを使って行うため、ライブラリを導入する。 なお、node.jsとnpmについては入っている前提で進める。

npm --version
> 6.4.1

node --version
> v8.11.1

1. Vue CLIの導入

Vue CLIはバージョン3を使います。

npm install -g @vue/cli

作成時点では3.04が最新のバージョン

vue --version
> 3.0.4

特別必要というわけではないが以下のライブラリもインストールすると簡単にプロトタイプがつくれます。

www.npmjs.com

 

npm install -g @vue/cli-service-global
echo '<template><h1>Hello!</h1></template>' > App.vue
vue serve

それについては以下のサイトに説明を任せます。

FN1807003 | Vue CLI 3入門 03: プロトタイプを簡単につくる | HTML5 : テクニカルノート

 

Goのio.Writer と標準出力、標準エラー出力についてちょっと深掘りしてみた

1. 導入

io.Writerインターフェースは馴染み深いところでいうとFprintFprintlnなどのfmtパッケージの関数の第一引数に指定され、 それぞれのメソッド内ではw.Write(p.buf)(w は io.Writer型のレシーバ)を呼び出したりする。
このFprintlnもまた、おなじみのfmt.Printlnの内部で第一引数にos.Stdoutを取って呼び出されている。

また、io.Writerを満たす構造体としては、os.Create("test.txt")の返り値として返される*Fileなどがio.Writerインターフェースを満たしてる。
(*FileWriteメソッドを定義しており、ファイルへの書き込みを行う)

2. io.Writerの実装

io.goにおけるio.Writerインターフェースの定義は以下の通りとてもシンプルである。

// Writer is the interface that wraps the basic Write method.
//
// Write writes len(p) bytes from p to the underlying data stream.
// It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
// Write must return a non-nil error if it returns n < len(p).
// Write must not modify the slice data, even temporarily.
//
// Implementations must not retain p.
type Writer interface {
    Write(p []byte) (n int, err error)
}

実装側が満たすべき仕様はバイト配列pを引数とし、書き込んだバイト数nと、エラーが発生した場合はその内容を返すといった程度である。
(コメントを見ると、書き込みバイト数nとバイト配列の長さが一致しない場合はnil以外のエラーを返す必要がある、と記載されている)

このようにインターフェースがシンプルなのでWriteメソッドを実装している型次第で、標準出力・ファイル、バッファ、HTTPリクエスト等への 書き込み処理をWriteメソッドを通して実現することができる。

3. 標準出力、標準エラー出力の定義調査

導入 に書いたfmtパッケージの関数FpintFprintlnを使う場合、一般的には標準出力os.Stdout標準エラー出力os.Stderrに流したり、テストのためにbytes.Bufferに書き込んだりして使用することが多い。
では標準出力os.Stdout標準エラー出力os.Stderrと一体なんなのか調べて見るためにosパッケージのStdoutStderrについて深く見ていくと
file.go(osパッケージ)

// Stdin, Stdout, and Stderr are open Files pointing to the standard input,
// standard output, and standard error file descriptors.
//
// Note that the Go runtime writes to standard error for panics and crashes;
// closing Stderr may cause those messages to go elsewhere, perhaps
// to a file opened later.
var (
    Stdin  = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
    Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
    Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr")
)

syscall_unix.go(syscallパッケージ): macの場合

var (
    Stdin  = 0
    Stdout = 1
    Stderr = 2
)

file_unix.go(osパッケージ): macの場合

// NewFile returns a new File with the given file descriptor and
// name. The returned value will be nil if fd is not a valid file
// descriptor.
func NewFile(fd uintptr, name string) *File {
    return newFile(fd, name, kindNewFile)
}

という実装になっており、標準入力os.Stdin、標準出力os.Stdout標準エラー出力os.Stderrも結局はファイルの作成os.Createやオープンos.Open同様に*Fileを返すようになっている。
*FIleWriteメソッドの呼び出しを追っていくと、最終的にpollパッケージのfd_unix.goのWriteメソッドに行き着き、

// Write implements io.Writer.
func (fd *FD) Write(p []byte) (int, error) {
    if err := fd.writeLock(); err != nil {
        return 0, err
    }
    defer fd.writeUnlock()
    if err := fd.pd.prepareWrite(fd.isFile); err != nil {
        return 0, err
    }
    var nn int
    for {
        max := len(p)
        if fd.IsStream && max-nn > maxRW {
            max = nn + maxRW
        }
        n, err := syscall.Write(fd.Sysfd, p[nn:max])
        if n > 0 {
            nn += n
        }
        if nn == len(p) {
            return nn, err
        }
        if err == syscall.EAGAIN && fd.pd.pollable() {
            if err = fd.pd.waitWrite(fd.isFile); err == nil {
                continue
            }
        }
        if err != nil {
            return nn, err
        }
        if n == 0 {
            return nn, io.ErrUnexpectedEOF
        }
    }
}

syscall.Writeの第一引数で指定したファイルディスクリプタに対して書き込むようにシステムコールをしていることがわかります。
(本当はsyscall.Writeの定義元へとさらに潜れるがここでは割愛)
ここで出てくるファイルディスクリプタfd.Sysfdの値はNewFileの第一引数で指定した値と一致し(詳しくはfile_unix.goのnewFile関数参照)、 前述の通り標準入力os.Stdin、標準出力os.Stdout標準エラー出力os.Stderrにおいてはそれぞれ0, 1, 2になる。
これは0: 標準入力Stdin、1: 標準出力Stdout、2: 標準エラー出力Stderrの3つについてはOSが最初にファイルディスクリプタとして割り当てるためである。
ちなみにos.Createos.Openの場合はともにsyscall.Openが呼び出され、syscall.Openの第一戻り値がファイルディスクリプタに設定される。

といった感じでGoでは比較的簡単に低いレイヤーについて深掘りできるので大変学びが深い。
Goならわかるシステムプログラミングは良書。

GCPでCloud SQL に Cloud SQL Proxy で接続できるようにする

プログラマのためのGoogle Cloud Platform入門(https://www.amazon.co.jp/dp/B0721JNVGT) を読み進めながら備忘録として書く。
文章の推敲はあとでする(多分しない)。実行環境はGCEでlinuxならどれでもいけるはずです。
実際GCPの変更で危殆化する可能性あるんですが、そうなる前に必要になる可能性もあるんで書きます。
本家: https://cloud.google.com/sql/docs/mysql/external-connection-methods?hl=ja

1. Cloud SQL Admin API を有効化する。

[ナビゲーションバー]
->[APIとサービス]
->[ライブラリ]
->[Cloud SQL Admin API]
有効化する。プログラマのためのGoogle Cloud Platform入門だと「Cloud SQL API」ってなってるけど
名前が変わったぽい。

2.データベースの作成

割愛(create database hoge_db; とか)。
ついでにroot以外のユーザも作っておくとイイ(grant all privileges on hoge_db.* to hoge_user@"%" identified by 'password' with grant option; とか)。

3.Cloud SQL Proxy のインストール

Cloud SQL Proxy のダウンロード

wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 -O cloud_sql_proxy

プロキシを実行できるようにします。

chmod +x cloud_sql_proxy

プロキシ ソケットを格納するディレクトリを作成する(Unix ソケットを使う場合)。

sudo mkdir /cloudsql; sudo chmod 777 /cloudsql

プロキシを開始する。サービスとして登録し、自動起動すると便利。

./cloud_sql_proxy -dir=/cloudsql -instances=<Cloud SQL におけるインスタンス接続名>

4.MySQL セッションを開始。

mysql -u <USERNAME> -p -S /cloudsql/<Cloud SQL におけるインスタンス接続名>

何やかんややっぱり公式情報が一番だと思う。(https://cloud.google.com/sql/docs/mysql/connect-compute-engine?hl=ja)

GCEでインスタンスを立てる時の手順、設定あれこれ

プログラマのためのGoogle Cloud Platform入門(https://www.amazon.co.jp/dp/B0721JNVGT) を読み進めながら備忘録として書く。
文章の推敲はあとでする(多分しない)。

1.プロジェクトを作成

[ナビゲーションバー]
->[ホーム]
->[プロジェクト設定]
->[リソースを管理]
->[プロジェクトを作成]
適当な名前をつけてプロジェクトを作成。ここら辺は勘でいける

2.VMインスタンスを作成

[ナビゲーションバー]
-> [Compute Engine]
-> [VM インスタンス]
-> [作成]

  • 名前(インスタンスの名前) : 任意
  • リージョン・ゾーン : 任意
  • マシンタイプ(スペック) : 任意(用途による、デフォルトはvCPU x 1)
  • ブートディスク : 好きなOSを選ぶ (CentOS, Ubuntuももちろんある)
  • ID と API へのアクセス : VMで実行されるアプリケーションはサービスアカウントを
    使用して各Google Cloud API を呼び出す。[各 API にアクセス権を設定]を
    選ぶとAPIごとに権限設定ができる。任意
  • ファイアウォール : デフォルトではSSH, RDP, ICPM以外の外部ネットワークから受信する全てのトラフィックがブロックされる webサーバとして使用する際に外部IPを固定する場合は、[管理、セキュリティ、ディスク、ネットワーキング、単一テナンシー]から [ネットワーキング]のタブをクリックし、
    [ネットワーク インターフェース]
    -> [外部 IP]
    -> [IPアドレスを作成]
    で名前、説明(任意)を入力し予約(ネットワーク サービス階層は東京リージョンだとプレミアム固定)

上記の設定が完了したのち、[作成]ボタンをクリックしインスタンスを作成する。