ts-nodeを使ってlocalでTypescriptを楽に実行できるようにする

はじめに

この記事は、Typescript(.tsファイル)を直接実行できるようにする環境構築のメモです。
前提としてnodeとnpmはインストール済みとしています。

今回はnpxを使用しているのでインストールしていない場合は、インストールしておきましょう。

$ npm install -g npx

プロジェクトディレクトリの作成

$ mkdir typescript-node
$ cd typescript-node

package.jsonの生成~typescriptの追加

npm init -y
npm install typescript
npm install -D @types/node

tsconfig.jsonの作成

$ touch tsconfig.json

or

$ npx tsc --init

tsconfig.json

{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "sourceMap": true,
    "outDir": "./dist",
    "strict": true,
    "esModuleInterop": true
  },
  "include": [
    "src/**/*"
  ]
}

Typescriptファイルの作成

$ mkdir src
$ touch src/index.ts

src/index.ts

function hello(message: string): string {
  return `Hello, ${message}!`
}

console.log(hello('World'))

typescriptパッケージに同梱されているtscコマンドを実行しましょう。

$ npx tsc

するとdistディレクトリの中にindex.jsindex.js.mapが生成されます。

$ ls dist
index.js      index.js.map

生成されたindex.jsを実行してみましょう。

$ node dist/index.js
Hello, World!

ts-nodeを導入して手間を減らす

毎回.tsファイルを編集してtscコマンドでコンパイルしてnodeで実行するのは手間もかかる上に面倒なのでtsc -> nodeの実行を自動で行ってくれるts-nodeを導入しましょう。

$ npm install -D ts-node

npm installが終了したらts-nodeコマンドを実行してみましょう。

$ npx ts-node src/index.ts
Hello, World!

package.jsonのnpm-scriptにdevを追加

{
  ...
  "scripts": {
    "dev": "ts-node src/index.ts",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  ...
}

早速実行してみましょう。

$ npm run dev

> typescript-node@1.0.0 dev /Users/<username>/typescript-node
> ts-node src/index.ts

Hello, World!

golang queue処理のライブラリを作ってみた

はじめに

開発をしていると度々queueの実装が必要になることが多かったので一々実装するのが面倒になっていた。

そのため、今回jobに関数を渡してqueueを実行するライブラリを作ってみた

githubリポジトリこちら

導入

queueのライブラリをgo get

go get -u https://github.com/y-ogura/queue

dispatcherの起動

package main

import "https://github.com/y-ogura/queue"

func main() {
        // create the job queue.
    jobQueue := make(chan queue.Job, 10000)

    // start the dispatcher.
    dispatcher := queue.NewDispatcher(jobQueue, 5)
    dispatcher.Run()
}

Jobの追加

// add new job
jobQueue <- func() error {
        // 実行したいJobの関数
        err := xxxFunction(arg)
        return err
}

element ui のtableにinfinite scroll を付けてみた

はじめに

nuxt.jsでelement uiを使用したテーブルコンポーネントに下記のようなinfinite scrollを実装してみました。

今回使用したライブラリはvue-infinite-loadingを利用しました。

githubリポジトリこちら

環境構築編

$ create-nuxt-app <project-name>

$ cd <project-name>

$ npm install

$ npm install --save vue-infinite-loading element-ui

element uiのコンポーネントを使用できるようにします。

plugins/element-ui.js

import Vue from 'vue'
import 'element-ui/lib/theme-chalk/index.css'
const ElementUI = require('element-ui')

Vue.use(ElementUI)

nuxt.config.js

export default {
  ...
  plugins: [
    { src: '~/plugins/element-ui' }
  ],
  ...
}

pageの実装

次にpageを実装していきます。

pages/index.vue

<template>
  <section>
    <el-button @click="resetInfinite">reset</el-button>
    <div class="table-container">
      <el-table :data="accounts" style="with: 100%">
        <el-table-column prop="id" label="id" />
        <el-table-column prop="name" label="name" />
        <el-table-column prop="email" label="email" width="180" />
      </el-table>
    </div>
  </section>
</template>

<script>
export default {
  data() {
    return {
      accounts: []
    }
  },
  created() {
    for (let i = 0; i < 300; i++) {
      var account = {
        id: i + 1,
        name: `test_${i + 1}`,
        email: `test_${i + 1}@example.com`
      }
      this.accounts.push(account)
    }
  }
}
</script>

いよいよinfinite scrollを実装していきます。

まずはvue-infinite-loadingをimportします。

pages/index.vue

<script>
import InfiniteLoading from 'vue-infinite-loading'

export default {
  components: {
    InfinitLoading
  },
...
</script>

テーブルのはみ出した要素はscrollするようにしましょう。

pages/index.vue

<style>
.table-container > .el-table > ..el-table__body-wrapper {
  overflow: scroll;
  max-height: 480px;
}
</style>

InfiniteLoadingのコンポーネントをel-tableの一番下に追加します。 さらにテーブルで使用するデータをaccountsから変更します。

pages/index.vue

...
    <div class="table-container">
      <el-table :data="list" style="with: 100%">
        <el-table-column prop="id" label="id" />
        <el-table-column prop="name" label="name" />
        <el-table-column prop="email" label="email" width="180" />
        <InfiniteLoading
          slot="append"
          :identifier="infiniteId"
          force-use-in-infinite-wrapper=".el-table__body-wrapper"
          @infinite="infiniteHandler"
        />
      </el-table>
    </div>
...
<script>
...
  data () {
    return {
      accounts: [],
      list: []
    }
  }
}
</script>

スクロールされたら走るinfiniteHandlerを実装しましょう。

...
  data() {
    return {
      accounts: [],
      list: [],
      limit: 15,
      page: 0,
      infiniteId: +new Date()
    }
  },
  created() {
    for (let i = 0; i < 300; i++) {
      var account = {
        id: i + 1,
        name: `test_${i + 1}`,
        email: `test_${i + 1}@example.com`
      }
      this.accounts.push(account)
    }
    this.fetchList(this.limit)
  },
  methods: {
    infiniteHandler($state) {
      if (this.accounts.length && this.accounts.length > this.list.length) {
        let scrollLimit = (this.page + 1) * this.limit
        if (this.accounts.length < scrollLimit) {
          scrollLimit = this.accounts.length
        }
        this.fetchList(scrollLimit)
        $state.loaded()
      } else {
        $state.complete()
      }
    },
    fetchList(scrollLimit) {
      this.list.push(
        ...this.accounts.slice(this.page * this.limit, scrollLimit)
      )
      this.page++
    },
    resetInfinite() {
      this.page = 0
      this.list = []
      this.fetchList(this.limit)
      this.infiniteId++
      const elm = document.getElementsByClassName('el-table__body-wrapper')[0]
      elm.scrollTo({ top: 0 })
    }
  }
}

if (this.accounts.length && this.accounts.length > this.list.length) {}で現在表示されているデータよりもaccountsが多ければinfinite scrollでデータが読み込まれるようになっています。 scrollLimitには何件目までのデータを取得するかが入り、

this.list.push(
  ...this.accounts.slice(this.page * this.limit, scrollLimit)
)

で現在読み込まれているデータ+1番目のデータからscrollLimitまでのデータをlistに追加します。

Go言語コワクナイ 第4話

〜gormを使ってpostgresに接続してみよう〜

前回のあらすじ

/hello/controller/hello_controller.goに

package controller

// HelloController hello controller
type HelloController struct{}

func NewHelloController(e *echo.Echo) {
    handler := &HelloController{}
    e.GET("/", handler.Hello)
}

// Hello hello world
func (c *HelloController) Hello(ctx echo.Context) error {
    return ctx.JSON(200, "Hello, World!")
}

を記述して


main.goで

e := echo.New()
controller.NewHelloController(e)

でcontrollerの処理を実装することができました


今回はgormを使用してpostgresへ接続をしてみましょう


まずDBを用意します

createdb db名

次にdb.goを作成します

mkdir db
touch db/db.go

db.goを編集していきましょう

package db

import (
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/postgres" // import postgres
)

// Init connection postgres DB.
func Init() *gorm.DB {
    url := "postgres://user:pass@host:port/db_name?sslmode=disable"
    db, err := gorm.Open("postgres", url)
    if err != nil {
        panic(err)
    }
    return db
}

まず接続するDBのpackageをimportします 今回はpostgresを使用するので

"github.com/jinzhu/gorm/dialects/postgres" // import postgres

をimportします


gorm.Open("DBの種類", DatabaseURL)

でDBへ接続します DB接続の情報は1つ目の返り値で返却されます


main.goでInitを実行すればDBへ接続ができます

func main() {
    database := db.Init()
}

データ取得してDBに接続できているか確認しましょう

mkdir user
touch user/user.go

user/user.go

package user

import "time"

// User user struct
type User struct {
    ID        int `gorm:"primary_key"`
    Email     string
    Password  string
    LastName  string
    FirstName string
    CreatedAt time.Time
    UpdatedAt time.Time
    DeletedAt *time.Time
}

main.go

database := db.Init()
database.AutoMigrate(
    &user.User{},
)
database.LogMode(true)
u := []*user.User{}
database.Model(&u).Find(&u)

実行してみましょう

go build
./echo-sever

このようなログが出力されれば成功です

(/****/****/go/src/github.com/y-ogura/echo-server/main.go:18)
[2019-01-23 10:13:00]  [3.29ms]  SELECT * FROM "users"  WHERE "users"."deleted_at" IS NULL
[0 rows affected or returned ]

次回

〜gormを使ってCRUD処理をしてみよう〜

Go言語コワクナイ 第3話

〜echoでHTMLファイルを表示してWebサイトを作ってみよう〜

前回のあらすじ

main.goの

e.GET("/", func(ctx echo.Context) error {
    return ctx.JSON(200, "Hello, World!")
})

e.Static("/", assets)
e.File("/", "public.html")

に書き換えることでhtmlを表示させることができました。


今回はControllerの作成を行っていきます。


じつは、第1回で記述した

e.GET("/", func(ctx echo.Context) error {
    return ctx.JSON(200, "Hello, World!")
})

もControllerの書き方の一つとなっています。


しかし、main.goにひたすらControllerを増やしていくとmain.goの中身が大変なことになってしまいますね。

e.GET("/hello", func(ctx echo.Context) error {
    return ctx.JSON(200, "Hello, World!")
})
e.GET("/dog", func(ctx echo.Context) error {
    return ctx.JSON(200, "わんわん!")
})
e.GET("/cat", func(ctx echo.Context) error {
    return ctx.JSON(200, "にゃー!")
})
...

そこで、Controllerのファイルを分割して作成していきましょう。


hello_controller.goを作成しましょう。

$ mkdir hello
$ mkdir hello/controller
$ touch hello/controller/hello_controller.go

Controllerの中身を作成していきます。

package controller

// HelloController hello controller
type HelloController struct{}

func NewHelloController(e *echo.Echo) {
    handler := &HelloController{}
    e.GET("/", handler.Hello)
}

// Hello hello world
func (c *HelloController) Hello(ctx echo.Context) error {
    return ctx.JSON(200, "Hello, World!")
}

まずHelloControllerの構造体を宣言します。 今回は構造体の要素は空のままで大丈夫です。

type HelloController struct{}

Usecaseなどを使用する場合はControllerの構造体の要素を宣言します。

type HelloController struct{
    HelloUsecase: usecase.HelloUsecase
}

次にNewHelloControllerでcontrollerをmountします。

func NewHelloController(e *echo.Echo) {
    handler := &HelloController{}
    e.GET("/", handler.Hello)
}

handlerには先程宣言したHelloControllerを指定しましょう。


e.GET("/", handler.Hello)

この部分はルーティングになります。 ルーティングはグループ化することができ、

api := e.Group("/api/v1")
api.Get("/", handler.Hello)

のように記載すると/api/v1をprefixに付けることができます。


また、ルーティングにmiddlewareをかけたい場合はe.Groupの第2引数にmiddlewareを指定することによってそのグループにのみmiddlewareをかけることも可能です

auth := e.Group("/api/v2", middleware.Authorization)
auth.POST("/accounts", handler.Create)

e.メソッドの第1引数にはエンドポイント、第2引数にはContollerのメソッドを記載します。 また、この段階でもmiddlewareをかけることも可能です

エンドポイントでpathパラメータを指定することも可能です

e.GET("/hello/:name", handelr.Hello)

では、Controllerのメソッドの実装をしていきましょう。

// Hello hello world
func (c *HelloController) Hello(ctx echo.Context) error {
    return ctx.JSON(200, "Hello, World!")
}

レシーバにはHelloControllerを設定し 引数はecho.Context 返り値はerror型を指定します。 return ctx.JSONの部分は返すレスポンスによって変わってきます。 ここの部分に関しては公式ドキュメントを参照してください。


ここまで書ければ後は、main.goで呼び出せば終了です。

e := echo.New()
controller.NewHelloController(e)

それでは環境を起動してみましょう。

$ go build
$ ./echo-server

localhost:1323にアクセスすると以下のように表示されます。


次回

〜gormを使ってpostgressに接続してみよう〜

Go言語コワクナイ 第2話

〜echoでHTMLファイルを表示してWebサイトを作ってみよう〜

前回のあらすじ

main.goに

e := echo.New()
e.GET("/", func(ctx echo.Context) {
    return ctx.JSON(200, "Hello, World!")
})

port := ":1323"
e.Logger.Fatal(e.Start(port))

と書くだけで簡単にサーバーを起動することができました。


今回は前回使用したコードを使ってHTMLファイルを表示してみましょう。


今回使うもの


準備

まずHTMLファイルとCSSファイルを用意しましょう

$ mkdir assets
$ mkdir assets/css
$ mkdir public

assets/cssにcommon.cssを作成します

.text-red {
  color: red;
}

publicにindex.htmlを作成します。

<html>
  <head>
    <link rel="stylesheet" href="css/common.css" type="text/css">
  </head>
  <body>
    <h1>Hello, World!</h1>
    <div>
      <p>こんにちわ、<span class="text-red">世界</span></p>
    </div>
  </body>
</html>

class text-redがついた'世界'が赤くなるような指定ですね 次にmain.goを編集していきましょう。


前回書いた

e.GET("/", func(ctx echo.Context) {
    return ctx.JSON(200, "Hello, World!")
})

e.Static("/", "assets")
e.File("/", "public/index.html")

に書き換えるだけです


書き換え後のmain()はこのようになります

func main() {
    e := echo.New()
    
    e.Static("/", assets)
    e.File("/", "public/index.html")
    
    port := ":1323"
    e.Logger.Fatal(e.Start(port))
}

では環境を起動してみましょう。

$ go build
$ ./echo-server

localhost:1323

にアクセスするとこのように表示されます


次回

Go言語コワクナイ 第3話

〜echoでcontrollerを実装してみよう〜

Go言語コワクナイ 第1話

〜echoでサーバーを起動してみよう〜

今回使うもの


準備

はじめに$GOPATH内に開発ディレクトリを作成しましょう。

$ cd go/src/github.com/y-ogura
$ mkdir echo-server
$ cd echo-server

開発開始

まずはmain.goを作成しましょう

package main

import "fmt"

func main() {
    fmt.Println("Hello, World!")
}

$ go run main.go

で実行してみましょう

$ go run main.go
Hello, World!

このように出力されれば成功です


次にechoを使ってサーバーを起動してみましょう main.goに以下のように書き換えます

package main

import (
    "github.com/labstack/echo"
)

func main() {
    e := echo.New()
    
    port := ":1323"
    e.Logger.Fatal(e.Start(port))
}

依存パッケージをインストールします Go v1.11.1以上なら .envrcに以下を記述します

export GO111MODULE=on
$ direnv allow
$ go mod init

depを使用しているなら

$ dep init
$ dep ensure

実行してみます

$ go build
$ ./echo-server

このように表示されれば成功です


どうせなので/にアクセスしたときに'Hello, World!'を表示してみましょう

main.goのe := echo.New()の下に追記します

e.GET("/", func(ctx echo.Context) error {
    return ctx.JSON(200, "Hello, World!")
})

実行してみましょう

$ go build
$ ./echo-server

localhost:1323

にアクセスしてみます


次回

Go言語コワクナイ 第2話

〜echoでHTMLファイルを表示してWebサイトを作ってみよう〜