edy hub

プログラミングやライフスタイルについて書き綴っています

Typescript学習〜『プロを目指す人のためのTypeScript入門』を読んでみて第3章〜

はじめに

業務で使うことのあるTypeScriptを本格的に勉強し始めたところです。

現在絶賛『プロを目指す人のためのTypeScript入門』を読み進めており、その際のメモを備忘録として残しております。

前回の記事 www.edyhub.com

書籍はこちら

第3章

第3章は「オブジェクトの基本とオブジェクトの型」について。

オブジェクトとは

TypeScriptのオブジェクトは、連想配列ですと。

ハッシュや辞書などとも呼ばれますが、ここでは「いくつかの値をまとめたデータ」としておきます。

この世界は先の章で扱った文字列、数値などのプリミティブ型だけで表現できるほど単純には出来ていませんよね。

ひとりのユーザーを表現したい場合にも「名前」「年齢」「画像」「住所」など関連するデータは多様に存在します。

これら複数のデータをまとめてユーザーを表現したいときにオブジェクトという単位でまとめることが必要になります。

※とはいえ実運用を加味すると「ユーザー」というオブジェクトだけでシンプルに運用するには限界が訪れて、「プロフィール」オブジェクトなど更に階層構造が生まれていくと思います。

オブジェクトの省略記法

オブジェクトリテラルには、省略記法があります。

例えば、以下のオブジェクトの代入を例にあげます。

最終的にユーザーの姓名を足して、ユーザー名として出力しています。

const family_name = '田中'
const given_name = '太郎'

const user = {
  family_name: family_name,
  given_name: given_name
}

const user_name = family_name + given_name
console.log(`ユーザー名: ${user_name}`)
 

今回取り上げる「省略記法」というのは、プロパティ名と変数名が同一の場合に活用できます。

変数定義で family_namefirst_name が用いられていますが、userオブジェクト内でも同様のプロパティが出現しています。

その場合、コーディングの効率を上げるために、以下のように書き換えることが出来ます。

const family_name = '田中'
const given_name = '太郎'

const user = {
  family_name,
  given_name
}

const user_name = family_name + given_name
console.log(`ユーザー名: ${user_name}`)

userオブジェクトの family_name: family_name given_name: given_name がそれぞれ対応する変数名だけで表現できるようになりました。

コンパクトな記述ができるため、利用できる際にはどんどん活用していけると良いですね。

スプレッド構文

オブジェクトリテラル中ではスプレッド構文と呼ばれる別オブジェクトからプロパティをコピーできる構文を利用できます。 既存のオブジェクトを拡張した別オブジェクトを作りたいときに有効に活用できます。

const userName = {
  family_name: '田中',
  given_name: '太郎',
}

const userProfile = {
  age: 20,
  ...userName
}

console.log(userProfile)

// 結果
// { age: 20, family_name: '田中', given_name: '太郎' }

注意点として、プロパティをコピーしているため、コピー元のオブジェクト側のプロパティ変更は反映されません。 一方、コピー元のネストしたプロパティに関しては依然として同一オブジェクトとみなされます。 オブジェクトのコピーと同一性は正しく理解しないと思わぬ破壊的変更を生む可能性があるので注意しましょう。

const foo = {
  obj: { num: 1234 }
}
const bar = { ...foo }
bar.obj.num = 0
console.log(foo.obj.num)

// 0 が返る

type文

TypeScript特有でJavaScriptには存在しない文としてtype文があります。

これは型名を宣言をする構文です。

type 型名 = 型;

まずtype文でFooBarObjという型名を作成します。続けて行う変数宣言では作成したFooBarObj型でオブジェクトを定義します。 それを表したのが以下のコードです。

type FooBarObj = {
  foo: string;
  bar: number;
};
const obj: FooBarObj = {
  foo: 'Hello, World',
  bar: 2022,
}

console.log(obj);

// { foo: 'Hello, World', bar: 2022 }

ちなみに、typeによる型名作成は interface宣言 でも可能です。

interface FooBarObj {
  foo: string;
  bar: number;
};
const obj: FooBarObj = {
  foo: 'Hello, World',
  bar: 2022,
}

console.log(obj);

// typeの場合と結果は変わらない
// { foo: 'Hello, World', bar: 2022 }

※書籍の筆者の見解はtype文のみを使用すれば困ることはないという意見

部分型関係

  • 部分型は2つの型の互換性を表す概念
  • 型Sが型Tの部分型であることは、S型の値がT型の値でもあることを示す
  • TypeScriptは構造的部分型(プロパティの実際の比較により部分型かどうか決定される)
  • 他言語は名前的部分型(明示的に宣言されて初めて部分型になる)
  • TypeScriptにも名前的部分型が導入されることは要望として上がっているが現状は仕組みとして存在しない

型引数(type parameters)

型定義の際に、パラメータを伴って型定義の幅を増やしてくれるのが「型引数」です。 型引数を持つ型はジェネリック型とも呼ばれます。

例えば型引数ParentとChildを持つ Family<Parent, Child> を宣言すると以下のようになります。

ジェネリック型のFamily<Parent, Child>

type Family<Parent, Child> = {
  mother: Parent;
  father: Parent;
  son: Child;
  daughter: Child;
}

配列型

プログラミングをやっていれば頻出の配列(Array)に対しても型の構文が存在しています。

例えば、 number[] という型は number 型の値を要素に持つ配列を表現します。

以下の例だとarr1はOKですが、arr2はコンパイルエラーになります。

const arr1: number[] = [1, 10, 100];

const arr2: string[] = [1, 10, 100];

まとめ

第3章も内容は「オブジェクトとは?」についてでした。

オブジェクト

プロを目指す人のためのTypeScript入門を読んでみて〜第五章〜

はじめに

業務で使うことのあるTypeScriptを本格的に勉強し始めたところです。

現在絶賛『プロを目指す人のためのTypeScript入門』を読み進めており、その際のメモを備忘録として残しております。

第五章は「TypeScriptのクラス」を扱っています。

書籍はこちら

型引数を持つクラス

クラスも型引数を持てます。

これまで登場したのは「型そのもの」や「関数」が型引数を持つケース。

「クラスの型引数」は両方を合体させたような性質を持つと。

イメージを付けるためにコードを参照します。

class User<T> {
  name: string;
  #age: number;
  readonly data: T;

  constructor(name: string, age: number, data: T) {
    this.name = name;
    this.#age = age;
    this.data = data;
  }

  public isAdult(): boolean {
    return this.#age >= 20;
  }
}

const taro = new User<string>("taro", 21, "日本人です")
const data = taro.data;
const john = new User("John Smith", 15, { num: 123 })
const data2 = john.data;

特徴としてはクラス宣言でUserと型引数リストが書かれています。クラス名の後のTには方が入ります。 結果、UserやUserなどのインスタンスが生成可能になります。

コンストラクタの呼び出し時に型引数を指定できます。

例: new クラス<型引数リスト>(引数リスト)

これでインスタンスの data に対して型の指定ができるようになりました。

ちなみにdata2の方では型の指定がありません。この場合、型推論{ num: number; } 型であることが推論されます。

最終的にjohnがどんな型のインスタンスになるかというと

User<{ num: number; }> 型であるといえます。

クラスの継承

TypeScriptでも継承が出てきましたね。

  • 他言語と同様あるクラスに機能を追加・拡張した別クラスを作成する「継承」の機能を持つ
  • キーワードは extends
  • class クラス名 extends 親クラス { ... } で継承を表現する

先程と同様にソースコードで具体イメージを掴んでみましょう。

class User {
  name: string;
  #age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.#age = age;
  }

  public isAdult(): boolean {
    return this.#age >= 20;
  }
}

class PremiumUser extends User {
  rank: number = 1;
}

const taro = new PremiumUser("taro", 21)
console.log(taro.rank); // 1が表示される
console.log(taro.name); // "taro"が表示される
console.log(taro.isAdult()); // trueが表示される

User クラスを継承した PremiumUser クラスが宣言されています。 つまり PremiumUser クラスも User クラスの全機能を備えます。 加えて rank プロパティを持つため taro.rank を呼び出せました。

また多言語と同様に子クラスでは親機能を上書きする「オーバーライド」も可能です。

例外処理

5章ではTypeScriptでの例外処理にも言及されていました。

エラーの基本としてはエラーを発生させる「throw文」が登場します。

throw 式; の構文があり、式部分でErrorオブジェクトを指定します。 例えば以下のような例外発生方法があります。

console.log('エラー発生させます')
throwError();
console.log('エラーを発生させました')

function throwError() {
  const error = new Error("エラーが発生しました!")
  throw error;

}

この場合「エラーを発生させました」は実行されずエラーのthrow時点で処理は中断されます。 エラーを補足しながら処理を継続する場合は try-catch 文を用います。

try {
  // エラーが発生しうる処理
} catch {
  // エラー発生時に発火する処理
}

エラーが発生してもしなくても実行する処理を書きたいときは finally ブロックを用います。

まとめ

第5章ではクラスに触れました

  • クラスに型を適用できる
  • クラスの継承が可能
  • thisや例外処理も含めたTypeScriptの追加機能の紹介

M1 Macbook air でherokuを使う

方法

brew で heroku をインストール

公式のCLImacOSにあるコマンドを実行します。

devcenter.heroku.com

brew tap heroku/brew && brew install heroku

command not found になった場合

自分の場合はbrew実行時に以下のエラーが発生しました。

% brew tap heroku/brew && brew install heroku      
zsh: command not found: brew

以下の記事を参考にトラブルシューティングしていきます。 【M1 Mac】zsh: command not foundと出た時の解決策。 - Qiita

zenn.dev

まずはbrewのインストールを行います。

% /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 

完了後、パスを通していきます。

~/.zshrc に以下を追加。

export PATH=/opt/homebrew/bin:$PATH
source ~/.zshrc

再びチャレンジ

brew tap heroku/brew && brew install heroku

その後、 heroku login ができるか検証します。

% heroku login         
 ›   Warning: Our terms of service have changed: 
 ›   https://dashboard.heroku.com/terms-of-service
heroku: Press any key to open up the browser to login or q to exit:

任意のキーを押すとブラウザが立ち上がり、以下の画面に遷移します。

heroku login

後はサインイン or サインアップすれば使用可能になります。

ログイン完了後

Typescript学習〜『プロを目指す人のためのTypeScript入門』を読んでみて第2章〜

はじめに

業務で使うことのあるTypeScriptを本格的に勉強し始めたところです。

現在絶賛『プロを目指す人のためのTypeScript入門』を読み進めており、その際のメモを備忘録として残しております。

前回の記事 www.edyhub.com

書籍はこちら

第2章

第2章は「基本的な文法・基本的な型」について。

変数宣言

変数宣言の際の型注釈の構文は以下になります。

const 変数: 型 = 式;

例として書くと、

const greeting: string = "Hello, world"

書籍には以下のTipsが書かれていました。

  • 極力 let を避けてconst を使用すべき
  • 変数への再代入は基本的に不要な実装にする
  • letを使用すると読み手の負荷が増す(再代入の可能性を考慮してコードリーディングが必要になるため)

プリミティブ型

TypeScriptには基本的な型が存在します。

それらはプリミティブと呼ばれます。

現時点では文字列、数値、真偽値、BigInt、null、undefined、シンボルの7種類がある様です。

数値

数値はTypeScriptにおけるプリミティブの一つです。 実は10進数以外を扱っても実行結果を見ると適切に数値として認識されます。

2進数/8進数/16進数を扱った場合は下記の様なアウトプットになります。

const binary = 0b1010;
const octal = 0o755;
const hexadecimal = 0xff;

console.log(binary, octal, hexadecimal);

コンパイル結果

% node dist/index.js                                                                                                                                   
10 493 255

またTypeScriptの数値はIEEE754倍精度浮動小数点数です。 何やら難しく感じられますが、整数の精度が53ビットであることを覚えておくと良いと思います。 (正直覚えなくても良い気もします)

そのため、53ビットに収まらない大きさの整数や小数を扱う際には注意が必要です。 例えば以下の出力は直感と異なる計算誤差が生まれます。

console.log(9007199254740993);
console.log(0.1 + 0.2);
9007199254740992
0.30000000000000004

計算誤差を受け入れられない場合は、任意精度計算に対応したライブラリを導入するなど対応が必要になります。

Number型 - TypeScript Deep Dive 日本語版

一方で、最近(ES2020)になってBigInt型が登場しました。 古いブラウザでは利用できない制約がありつつも、誤差なく表すことが可能な型です。 通常の数値(number)よりは計算速度が遅いものの、今後利用シーンが増加する見込みがあるようです。

null と undefined

  • TypeScriptの型で挙げた null と undefined は、それ自体が値の名前
  • どちらも「データがない」状況を示している
  • その状況を示す概念が2種類あるのはJavaScriptやTypeScriptに特有の特徴

著者はサポートが厚いundefinedを推していました。

一致判定

  • ===== の2つを比較したとき、基本的に === のみ使う(同じく !=!== も後者)
  • 後者の方がより厳密な一致判定が行われるから

もう少し具体的に言うと、

== は暗黙的に型変換を行ってから比較を行うため型が異なってもtrueになることがあり、 === は型が異なる場合は常に結果をfalseとなります。

const str: any = "3";

// true 
console.log(str == 3);

// false
console.log(str === 3);

短絡評価

ES2020で追加された論理演算子 ??

例えば

x ?? y

のような場合は「xがnullまたはundefinedのときのみyを返し、それ以外のときはxを返す」というロジックに。

例えば、データがない場合は代替値を返したい場合に活用できますね。

まとめ

第2章も内容は基本的な文法の説明でした。

  • 部分的な差異はあれどプリミティブ型は他の言語との類似点が多い
  • 演算子や制御構文も基本的に一つ言語に慣れていればすんなり理解できた
  • for文の省略記法は初見殺しかも(気になる方は書籍を読んでみてください)

Typescript学習〜『プロを目指す人のためのTypeScript入門』を読んでみて第1章〜

はじめに

普段はバックエンドの開発がメインですが時たまフロントエンドの開発に着手することがあります。 今まではRails内でjQueryによる開発が多かったのですが去年あたりから Next.js × TypeScript の環境に移行し始めたので良い機会と思いTypeScriptを勉強し始めました。

会社の同僚が紹介してくれた入門書を読んでいきがてら備忘録を残しておこうと思います。

メモ

  • TypeScriptには静的型システムが備わっている
  • コンパイルエラーが出たら大喜び
  • 型安全性とドキュメント化のメリットがある
  • TypeScriptは "Javascript + 型" という様相の言語である
  • Node.js は偶数のメジャーバージョン(14, 16, ...)が安定版とされている(←確かに、と思いつつ知らなかった)

作業に移る前の準備

nvmのインストール

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash

インストールが終わると .zshrc に以下が追加されます。

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

バージョンが表示されれば成功です。

% nvm -v
0.37.2

nodeのインストール

nvmに続けてnodeをインストールします。

% nvm install --lts
Installing latest LTS version.
Downloading and installing node v16.15.1...
Downloading https://nodejs.org/dist/v16.15.1/node-v16.15.1-darwin-arm64.tar.xz...
########################################################################################################################################################### 100.0%
Computing checksum with shasum -a 256
Checksums matched!
Now using node v16.15.1 (npm v8.11.0)
Creating default alias: default -> lts/* (-> v16.15.1)

バージョンが表示されれば成功です。

% node -v
v16.15.1

package.jsonを作成

% npm init --yes

※ --yes は対話形式でのコマンド入力をスキップして、すべての質問をデフォルト値で答える。

TypeScriptをインストール

% npm install --save-dev typescript @types/node                                                                                                          

added 2 packages, and audited 3 packages in 2s

found 0 vulnerabilities

tsconfig.jsonの準備

コンパイラオプションとしてコマンドライン引数ではなく tsconfig.json を採用

% npx tsc --init                                                                                                                                         

Created a new tsconfig.json with:                                                                                       
                                                                                                                     TS 
  target: es2016
  module: commonjs
  strict: true
  esModuleInterop: true
  skipLibCheck: true
  forceConsistentCasingInFileNames: true


You can learn more at https://aka.ms/tsconfig

基本的な進め方

個人開発しているRailsプロジェクトにCircleCIを導入する

はじめに

職場でCircleCIによるRspec及びrubocopの自動実行をしているので個人開発しているサービスにも導入してみようと思いました。

CircleCIのファイル編集とかは職場でもやったことが無かったので調査から始めてみます。

CircleCIの本家を当たってみる

作っているサービスは Ruby on Rails で運用しているため、CircleCiのRubyのガイドを読み進めてみます。

言語ガイド:Ruby - CircleCI

version: 2 # CircleCI 2.0 を使用します
jobs: # ステップの集合
  build: # Workflows を使用しない実行では、エントリポイントとして `build` ジョブが必要
    parallelism: 3 # このジョブのインスタンスを 3つ並列実行します
    docker: # Docker でステップを実行します
      - image: circleci/ruby:2.4.2-jessie-node # このイメージをすべての `steps` が実行されるプライマリコンテナとして使用します
        environment: # プライマリコンテナの環境変数
          BUNDLE_JOBS: 3
          BUNDLE_RETRY: 3
          BUNDLE_PATH: vendor/bundle
          PGHOST: 127.0.0.1
          PGUSER: circleci-demo-ruby
          RAILS_ENV: test
      - image: circleci/postgres:9.5-alpine # データベースイメージ
        environment: # データベースの環境変数
          POSTGRES_USER: circleci-demo-ruby
          POSTGRES_DB: rails_blog
          POSTGRES_PASSWORD: ""
    steps: # 実行可能コマンドの集合
      - checkout # ソースコードを作業ディレクトリにチェックアウトする特別なステップ

      # Bundler のバージョンを指定します

      - run:
          name: Bundler を指定
          command: bundle -v

      # バンドルキャッシュを復元します
      # 依存関係キャッシュについては https://circleci.com/docs/ja/2.0/caching/ をお読みください

      - restore_cache:
          keys:
            - rails-demo-bundle-v2-{{ checksum "Gemfile.lock" }}
            - rails-demo-bundle-v2-

      - run: # Ruby の依存関係をインストールします
          name: バンドルインストール
          command: bundle check || bundle install

      # Ruby の依存関係のバンドルキャッシュを保存します

      - save_cache:
          key: rails-demo-bundle-v2-{{ checksum "Gemfile.lock" }}
          paths:
            - vendor/bundle

      # アプリケーションで Webpacker または Yarn を他の何らかの方法で使用する場合にのみ必要です

      - restore_cache:
          keys:
            - rails-demo-yarn-{{ checksum "yarn.lock" }}
            - rails-demo-yarn-

      - run:
          name: Yarn をインストール
          command: yarn install --cache-folder ~/.cache/yarn

      # Yarn または Webpacker のキャッシュを保存します

      - save_cache:
          key: rails-demo-yarn-{{ checksum "yarn.lock" }}
          paths:
            - ~/.cache/yarn

      - run:
          name: DB を待機
          command: dockerize -wait tcp://localhost:5432 -timeout 1m

      - run:
          name: データベースをセットアップ
          command: bin/rails db:schema:load --trace

      - run:
          name: RSpec を並列実行
          command: |
            bundle exec rspec --profile 10 \
                              --format RspecJunitFormatter \
                              --out test_results/rspec.xml \
                              --format progress \
                              $(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)

      # タイミング解析のテスト結果を保存します

      - store_test_results: # テストサマリー (https://circleci.com/docs/ja/2.0/collect-test-data/) に表示するテスト結果をアップロードします
          path: test_results
      # デプロイコンフィグの例については https://circleci.com/docs/ja/2.0/deployment-integrations/ を参照してください

現状、開発しているプロダクトの構成は下記のとおりです。 - Dockerでweb, webpacker, dbコンテナをビルドする仕組み - ruby 2.6.6 - rails 6.0.0 - mysql 5.7

それぞれ対応するように修正していきます。

実際にファイルを作成してみた

version: 2
jobs:
  build:
    working_directory: ~/Hookah
    docker:
      - image: circleci/ruby:2.6.6-node-browsers
        environment:
          RAILS_ENV: test
          DATABASE_HOST: 127.0.0.1
      - image: mysql:5.7
        environment:
          MYSQL_ALLOW_EMPTY_PASSWORD: yes

    steps:
      - checkout
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "Gemfile.lock" }}
            - v1-dependencies-

      - run:
          name: Install bundle dependencies
          command: bundle install --path=vendor/bundle --jobs 4 --retry 3

      - run:
          name: Install yarn
          command: |
            yarn install

      - save_cache:
          paths:
            - ./vendor/bundle
            - ./node_modules
          key: v1-dependencies-{{ checksum "Gemfile.lock" }}

      - run:
          name: Database Setup
          command: |
            bundle exec rake db:create db:schema:load

これでリモートリポジトリにプッシュしてみると、、 bundle exec rake db:create db:schema:load

の段階でエラーに。

bundle exec rake db:create db:schema:load
2020-05-23 16:22:30 WARN Selenium [DEPRECATION] Selenium::WebDriver::Chrome#driver_path= is deprecated. Use Selenium::WebDriver::Chrome::Service#driver_path= instead.
DEPRECATION WARNING: Single arity template handlers are deprecated. Template handlers must
now accept two parameters, the view object and the source for the view object.
Change:
  >> Coffee::Rails::TemplateHandler.call(template)
To:
  >> Coffee::Rails::TemplateHandler.call(template, source)
 (called from <top (required)> at /home/circleci/Hookah/Rakefile:6)
Unknown MySQL server host 'db' (-2)
Couldn't create 'hookah_test' database. Please check your configuration.
rake aborted!
Mysql2::Error::ConnectionError: Unknown MySQL server host 'db' (-2)

bundle update slim を実行

エラーメッセージでググってみると、どうやら gem 'slim' が原因になっていそうな。

qiita.com

ただ、bundle update をしても既に最新バージョンになっていた。

別のクエリでググってみると、 coffee-rails が怪しそうに。

github.com

coffee-rails のバージョンを 5.0.0 に上げるのが良さそうだったので変更。

すると、エラーが一つ消えたがさらにMySQL周りでエラーに...(面倒くさそうw)

2020-05-23 16:36:15 WARN Selenium [DEPRECATION] Selenium::WebDriver::Chrome#driver_path= is deprecated. Use Selenium::WebDriver::Chrome::Service#driver_path= instead.
Unknown MySQL server host 'db' (-2)
Couldn't create 'hookah_test' database. Please check your configuration.
rake aborted!
Mysql2::Error::ConnectionError: Unknown MySQL server host 'db' (-2)

省略

この記事を見て、

CircleCIのmysqlイメージを用いるように変更を加えました。

teratail.com

しかし、結果は変わらず。

データベース名を削除

Unknown MySQL server host 'db' (-2)
Couldn't create 'hookah_test' database. Please check your configuration.

ここにある Unknown MySQL server host 'db' (-2) というのが気になったので調べてみると、config/database.ymlhost: db と定義していることを確認しました。 (1年以上前に記述していたので忘れていた・・・)

default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  database: <%= ENV['DATABASE_NAME'] %>
  username: <%= ENV['DATABASE_USERNAME'] %>
  password: <%= ENV['DATABASE_PASSWORD'] %>

development:
  <<: *default
  database: hookah_development
  host: db

test:
  <<: *default
  database: hookah_test
  host: db

production:
  <<: *default
  database: hookah_production
  username: root
  socket: /var/lib/mysql/mysql.sock

そこで、こちらの記事を参考に、hostには localhost を割り当てるように変更しました。 こちらは環境変数DATABASE_HOST として 127.0.0.1 になるようにしました。

qiita.com

変更後

default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  database: <%= ENV['DATABASE_NAME'] %>
  username: <%= ENV['DATABASE_USERNAME'] %>
  password: <%= ENV['DATABASE_PASSWORD'] %>
  host: <%= ENV['DATABASE_HOST'] %>

development:
  <<: *default
  database: hookah_development

test:
  <<: *default
  database: hookah_test

production:
  <<: *default
  database: hookah_production
  username: root
  socket: /var/lib/mysql/mysql.sock

完成版

こちらが初期段階として導入に成功したCircleCIのファイルです。 Ruby on Rails による開発を行うので、rubocopやRspecのjobを今後追加していこうと思います。

version: 2
jobs:
  build:
    working_directory: ~/Hookah
    docker:
      - image: circleci/ruby:2.6.6-node-browsers
        environment:
          RAILS_ENV: test
          MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
          DATABASE_HOST: 127.0.0.1
          DATABASE_USERNAME: root
      - image: circleci/mysql:5.7

    steps:
      - checkout
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "Gemfile.lock" }}
            - v1-dependencies-

      - run:
          name: Install bundle dependencies
          command: bundle install --path=vendor/bundle --jobs 4 --retry 3

      - run:
          name: Install yarn
          command: |
            yarn install

      - save_cache:
          paths:
            - ./vendor/bundle
            - ./node_modules
          key: v1-dependencies-{{ checksum "Gemfile.lock" }}

      - run:
          name: Database Setup
          command: |
            bundle exec rake db:create db:schema:load

以上で導入を終了します。 当初予定していたrubocopやRspecは未対応ですが、基盤ができたので一旦これにて完了とします。

Reactを動かしてみる【準備編】

概要

社内でReactを用いた新規事業がスタートしたので、これを機に今までちゃんと勉強してなかったツケを回収する。

学習教材

Boothで購入したPDFをもとにサクッと進めていく。 すべて含めて200ページ弱なので週末で終わるかな。

booth.pm

作業手順

  • node, npm, yarnのインストール
  • React Appの作成

node, npm, yarnのインストール

npm と node をインストールしておきます。 筆者はすでに導入済みでした。

Nodeのバージョン管理に anyenv を用いるのでインストールを推奨します。

qiita.com

シェルは bash を使用しています。

$ brew install anyenv
$ echo 'eval "$(anyenv init -)"' >> ~/.bash_profile
$ exec $SHELL -l
$ anyenv install --init
...
Completed!
$ node -v
v13.12.0
$ npm -v
6.14.4

この後は、yarn をインストールします

$brew install yarn
$yarn -v
1.22.4

React Appの作成

ここからは実際にアプリケーションの作成に移ります。 適当なワーキングディレクトリで下記コマンドを打ち込みましょう。

$ npx create-react-app hello-world --typescript

npx は npm のパッケージをいちいちインストールしなくてもそのバイナリが実行できるコマンドです。

完了したら作成したプロジェクトに移動して yarn start と入力します。

$ cd hello-world
$ yarn start

Chromeのブラウザ上にアプリが表示されれば成功です。

f:id:yuki-eda0629:20200415224131p:plain
ブラウザに表示されたアプリケーション

今回は一旦ここまでにしておきます。

続きは別記事で書いていこうと思います。