20191021のNode.jsに関する記事は7件です。

初心者こそ、Docker を使おう!

初心者こそ、Docker を使うべきです。

初心者こそ、Docker で node.js の 練習環境を作って快適に練習しよう!

対象者: dotinstall 等で javascript(node.js) を練習されているかた
練習環境を想定していますので、ここでは本格的な環境は想定していません。
nodeのversion管理面倒なんだけどと思っているなら、とても参考になるでしょう。
version違うけど、動くからと思っている人には、効果が薄いかもしれません.(笑)

まぁ、node環境しかり、python環境しかり、練習する前に環境を作る手間が誰でも手間ですが、初心者にとっては苦痛の何者でもありません。
簡単なお試しであれば、ウエブ上でもできますが、ある程度好みをいれるとなるとローカル環境を作ることになります。
様々なヴァージョンのnode, python を入れるのに nodenv, pyenv, anyenv 等はなかなかクールで愛用していますが、Dcoker に練習環境をいれるのは、さらにクールです。
 練習用コンテナを作って用が済めば、コンテナを消すのも簡単
会社のwindowsでdocker で作業をして、 macbook で 喫茶店で気になるところをチェックする、 家に帰って iMac で Docker を立ち上げ作業を続ける等もやろうと思えば出来るでしょう。(笑)
初心者でも、こんな環境が手に入るのです。 使わない理由がありません。

今回の作業内容は、githubにおいてありますので、うまく行かない場合は clone してつかってください.

  • 動かないと、やる気が半減するので置いておきます
  • https://github.com/atoris1192/docker-node-env
  • 最初複雑に見えるかもしれませんが、同じパターン作業なので慣れます.

  • この作業は、うまくいかない場合ためしてください、 最初は、導入からどうぞ

git clone https://github.com/atoris1192/docker-node-env.git

git reset --hard c026b7e19331000aa0a

cd docker-node-env
docker-composer up
docker-compose run --service-ports node bash

cd src
yarn
npx parcel index.pug

導入

Docker for Mac 或いは Docker for Windows を入れる  
入れ方は、検索してみてくださいね (DockerをMacにインストールする) などQiitaの記事丁寧でいいんじゃないでしょうか
Docker のアカウントも作って、DcokerHubにも入れるようにしておいてください。

Dockerfiledocker-compose.yml ファイルを作ります。
この2つで、Docker を操作します。
イメージは、最初からnodeが入っている公式のを使います。
vim 等を入れていますが、要らなければ削除してください
yarn も要らないものは、削除すればいいでしょう、必要になれは後からいれればいいのですから。

Dockerfile

FROM node:10.15.3
WORKDIR /tmp/src
RUN ["apt-get", "update"]
RUN ["apt-get", "install", "-y", "vim"]
RUN ["apt-get", "install", "-y", "tree"]
RUN yarn init -y && yarn add parcel-bundler pug typescript sass stylus firebase
CMD ["/bin/bash"]

イメージを作り直すのにビルドします
最後のドットは忘れないでください。 カレントのDockerfile を指定しています

docker build -t atoris1192/node:0.1.5 .
docker images でローカルにイメージができているのが確認できます。

docker-compose.yml
* 先にビルドしたものを使う

version: "3"
services:
  node:
    container_name: node
    image: atoris1192/node:0.1.5
    # build: .
    # volumes は上書きに注意
    volumes:
      - .:/app
    ports:
      - "1234:1234"
      - "1235:1235"
    working_dir: /app
    command: cp -rp /tmp/src /app
    # command: npx parcel --hmr-port 1235 --hmr-hostname localhost index.pug
    tty: true

docker-compose.yml ファイルがあるディレクトリであることを確認します。
dockder-compose up で環境を作ります。

最初のdocker-compose up は非常に時間がかかります。
早い機種ならすぐにおわるのでしょうが、Macbookで、5分位かかります
Attaching to node # この状態で止まる
node exited with code 0 # これがでればコピーが終わり
src配下にnode_modules, package.json, yarn.lock ができているはずです

docker-compose.ymlがあるディレクトリで

# ホスト(Mac)作業
  docker-compose up  # コピーに時間がかかります Attaching to node で止まっているように見える
  docker-compose ps  # node state が exit0 になっているのを確認します。 copy が終わってstopした状態です
  docker-compose run --service-port node bash # コンテナが立ち上がります. ここからlinux側です。
# コンテナ作業
  uname -a` # linuxが動作しています。
  node --version # node が動作しています。

npm がつかえるので、 npm install で vue.js, nuxt, react等 をいれればコンテナ環境で練習ができる
yarn もつかえますので、yarn global add @vue/cli をすればいいですね。
これで Vue Cli version3 が使えます。
https://qiita.com/atoris/items/6e603e59228f0ccadfd8
使い方は,上記を参考にしてもらえれば幸いです。

  • さて、現在の構成です。
    • node_modulesは、src配下にはいっていますので、npm, yarn を使うのはコンテナに入り、src 配下でしてください。
    • コンテナに入らずに、ホスト(Mac)のターミナルで npm, yarn はしないでください、たぶん nodeのヴァージョンがちがうはずです。node --version すればわかります。 同じであればうごくかもしれませんがファイルが壊れるのでしないほうがいいでしょう
├── Dockerfile
├── docker-compose.yml
└── src
    ├── package.json
    └── yarn.lock

今回は webpack ではなく、 Parcel bundler を使います

今回は、webpackでバンドルされていないものを使います
練習にもってこいのParcel-bundler です
webpack, parcel-bundler も ファイルをコンパイルして纏めるのが仕事ですが、練習に余計なファイルができるのは避けたいのと簡単に、pug, sass, stylus, typescript, 等を練習に混ぜたいためです。

pug で html を仮に作ります。 pug が嫌いな人は、src/index.html を作りましょう

ホスト側(Mac)、コンテナどちらからでもOKです
ターミナルは2つ立ち上げておいたほうが便利でしょう( host用,コンテナ用)
touch src/index.pug

後は、お好きなエディターでホスト側(atom, vscode等)作っていきます。
持ちろん、コンテナ側で vim で作ってもらってもOKです。

src/index.pug

<!DOCTYPE html>
html(lang="en")
  head
    meta(charset="UTF-8")
    meta(name="viewport", content="width=device-width, initial-scale=1.0")
    meta(http-equiv="X-UA-Compatible", content="ie=edge")
    title Document
  body
    div Hello !
  • コンテナ内作業 ( linux 側 uname すればわかります mac なら Darwin と表示されます)
cd src
npx parcel index.pug

ブラウザーで確認します。
http://localhost:1234

Hello がでていれば、Parcel が正常に動いています

エラーになる場合ポートマッピングがされているか確認しましょう

  • ホスト側 docker-compose.ymlがあるディレクトリから実行 docker-compose ps
  • ports が指定されているか確認
  atoris@atorisnoMacBook 08 % doccom ps
            Name                   Command          State                    Ports                
  ------------------------------------------------------------------------------------------------
  08_node_run_ca4fd0d55598   bash                   Up       0.0.0.0:1234->1234/tcp,              
                                                             0.0.0.0:1235->1235/tcp               
  node                       cp -rp /tmp/src /app   Exit 0                      

よくあるのが、何回も試していると二重起動やコンテナがすでにある場合失敗します。


docker container ls -a で確認して、一旦 コンテナを削除してしまいましょう
docker container stop コンテナid
docker container rm コンテナid
docker-compose down など コマンドを駆使して消してください(笑)


docker-compose.yml があるディレクトリで再度
* ホスト(Mac)作業 の項目から試して見てください

無事にブラウザーに表示されたら、そこまでの作業fileを git commit しておきましょう。(host側にgitが入っていれば)

vue.js で簡単なTodo アプリを開発してみます。

  • まず vueコンポーネントが正常に動くか確認します。
  • コンテナでparcel が動いていれば一旦 ctrl + c で止めておきます
  • コンテナ作業 でvue.js のライブラリを入れておきます。
  • package.json がなければ、yarn init -yで作っておきます あるはずですが

  • コンテナ作業

  cd src
  yarn add vue
  • vue も無事入っていますね

pacage.json

{
  "name": "src",
  "version": "1.0.0",
  "main": "index.js",
  "license": "mit",
  "dependencies": {
    "firebase": "^7.2.1",
    "parcel-bundler": "^1.12.4",
    "pug": "^2.0.4",
    "sass": "^1.23.0",
    "stylus": "^0.54.7",
    "typescript": "^3.6.4",
    "vue": "^2.6.10"
  }
}
  • vue でコードを書いていきます。

src/index.pug

<!DOCTYPE html>
html(lang="en")
  head
    meta(charset="UTF-8")
    meta(name="viewport", content="width=device-width, initial-scale=1.0")
    meta(http-equiv="X-UA-Compatible", content="ie=edge")
    title Document
  body
    p index.pug
    #app
    script(src="./index.js")

src/index.js

import Vue from 'vue/dist/vue.esm';
import MyApp from './MyApp.vue';

new Vue({
  el: '#app',
  components: {
    MyApp,
  },
  template: '<my-app></my-app>'
})

src/MyApp.vue

<template lang="pug">
  div
    p MyApp
    Hello
</template>
<script lang="ts">
import Vue from 'vue';
import  Hello  from './Hello.vue';
export default Vue.extend({
  components: {
    Hello,
  }
})
</script>

src/Hello.vue

<template lang="pug">
  div
    p Hello.vue
    p {{ name }}
</template>
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
  data() {
    return({
      name: 'Hello !!!'
    })
  }
})
</script>
  • 現在のファイル構成です。
.
├── Dockerfile
├── docker-compose.yml
└── src
    ├── Hello.vue
    ├── MyApp.vue
    ├── dist
    ├── index.js
    ├── index.pug
    ├── package.json
    └── yarn.lock
  • コンテナが止まっている場合は再度立ち上げます、立ち上がっていれば parcel コマンドを実行
  • ホスト側
docker-compose ps
docker-compose run --service-port node bash
  • Parcel オプションを追加して立ち上げます
    • もし時間がかかってうまく起動しない場合オプション抜きで試してみてください
    • node-hmr が使えないだけです
  • コンテナ作業
cd src
npx parcel --hmr-port 1235 --hmr-hostname localhost index.pug
# npx parcel index.pug

ブラウザーにすべて表示されていれば、OKです。
すべてのコンポーネントが動いています

index.pug

MyApp

Hello.vue

Hello !!!

今回 Todo アプリを作るところまでいけなかったので、次回があります。(笑)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JSON内の特定の値をマスクする

 目的

APIリクエスト・レスポンスをログに吐きだす際など用のメモ書き

javascript

const MASK_KEYS = ['email', 'password']

const maskJson = obj =>
  MASK_KEYS.reduce(
    (memo, key) =>
      memo.replace(new RegExp(`"${key}":"[^,}]*"`), `"${key}":"XXXXXX"`),
    JSON.stringify(obj)
  )

console

maskJson({ email: 'sample@email.com', password: 'password' })
=> "{"email":"XXXXXX","password":"XXXXXX"}"

ruby

MASK_KEYS = %w[email password].freeze

def mask_json(hash)
  MASK_KEYS.inject(JSON.generate(hash)) { |memo, key| memo.gsub(/("#{key}":"[^,}]*")/, "\"#{key}\":\"XXXXXX\"") }
end

console

mask_json({ email: 'sample@email.com', password: 'password' })
=> "{\"email\":\"XXXXXX\",\"password\":\"XXXXXX\"}"
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

discord.js で Bot を作成して Heroku で永続稼働させる

環境

  • macOS Mojave 10.14.3

事前準備

Homebrew のインストール

https://qiita.com/naente_dev/items/1195ff834c65be4be5a6

nodebrew および Node.js のインストール

https://qiita.com/kyosuke5_20/items/c5f68fc9d89b84c0df09
こちらの記事を参考に導入しました。

Discord Bot の登録

Discord Developer Portal ページにアクセスします。
FireShot Capture 028 - Discord Developer Portal — My Applications - discordapp.com.png
New Application ボタンをクリックします。
FireShot Capture 029 - Discord Developer Portal — My Applications - discordapp.com.png
NAME 欄に任意のアプリケーション名を入力して Create ボタンをクリックします。
FireShot Capture 030 - Discord Developer Portal — My Applications - discordapp.com.png
アプリケーションの作成に成功すると General Information ページにリダイレクトされます。
左側の SETTINGS メニューから Bot を選択します。
FireShot Capture 031 - Discord Developer Portal — My Applications - discordapp.com.png
Add Bot をクリックします。
FireShot Capture 032 - Discord Developer Portal — My Applications - discordapp.com.png
Yes, do it! をクリックします。
FireShot Capture 033 - Discord Developer Portal — My Applications - discordapp.com.png
Bot が追加されました。

TOKEN 欄の Copy ボタンをクリックして、Bot のトークンをコピーします。
開発時に使用するので、どこかに控えておきます。

続いて、左側の SETTINGS メニューから OAuth2 を選択します。
FireShot Capture 034 - Discord Developer Portal — My Applications - discordapp.com.png
OAuth2 URL Generator - SCOPE 欄にある bot のチェックボックスを選択すると
オーソライズ URL が表示されるのでコピーして、アクセスします。
FireShot Capture 035 - アカウントへのアクセスを許可します - discordapp.com.png
Bot を追加したいサーバーを選択して 認証 ボタンをクリックします。

Bot を追加できるのは自身が管理者権限を所持しているサーバーに限定されます。
権限の無いサーバーは一覧に表示されません。
スクリーンショット 2019-10-20 11.28.34.png
スクリーンショット 2019-10-20 11.29.15.png
サーバーに Bot が追加されましたが、この時点ではまだオフラインです。

開発

例として MyDiscordBot というディレクトリを作成して、その中で開発を進めていきます。

$ mkdir MyDiscordBot
$ cd MyDiscordBot/

discord.js のインストール

https://discord.js.org/

$ npm install discord.js
略
+ discord.js@11.5.1
added 7 packages from 6 contributors and audited 7 packages in 2.183s
found 0 vulnerabilities

成功するとカレントディレクトリ内に
discord.js および依存ライブラリを含む node-modules ディレクトリと
package-lock.json ファイルが作成されます。

コーディング

MyDiscordBot ディレクトリの直下へ index.js を作成します。

以下、公式リファレンスに記載されている ping と発言すると Pong! とリプライしてくれる Bot の
コードとなります。
(トークン部分のみ定数化しました)

MyDiscordBot/index.js
const Discord = require('discord.js');
const client = new Discord.Client();
const BOT_TOKEN = '***********************************************************';

client.on('ready', () => {
    console.log(`Logged in as ${client.user.tag}!`);
});

client.on('message', msg => {
    if (msg.content === 'ping') {
        msg.reply('Pong!');
    }
});

client.login(BOT_TOKEN);

BOT_TOKEN には Discord Developer Portal ページで取得した Bot のトークンを
設定してください。

Node.js ローカルサーバーで Bot を起動

$ node index.js
Logged in as Application Name#0000!

スクリーンショット 2019-10-20 12.54.29.png
Bot がオンラインになりました。

スクリーンショット 2019-10-20 12.57.51.png
ping と発言すると Pong! とリプライしてくれます。

デプロイ

このままでは自身の端末で Bot を起動している時のみしか利用できない為、
今回は Heroku にデプロイしてみます。

Heroku を利用した永続起動

https://qiita.com/InkoHX/items/590b5f15426a6e813e92

こちらの記事を参考に Heroku への登録〜デプロイまでを実施しました。

補足

$ git push heroku origin --force

デプロイしようの箇所に記載されている上記のコマンドではプッシュできなかった為、
下記コマンドで対応しました。

$ git push heroku master --force

Heroku タイムゾーンの設定

Heroku のデフォルトタイムゾーンは UTC(協定世界時)ですので
日本時間と 9時間の遅れがあります。

タイマー処理など時刻に関する処理を実装する予定があれば JST(日本標準時)に変更しておきましょう。

https://qiita.com/ikemura23/items/52ab8a5d260c7ee4d42b

こちらの記事を参考に設定させていただきました。

Heroku コマンド抜粋

$ heroku ps

dyno 無料分の残時間や使用時間、Web/Worker の稼働状態を確認できます。

$ ps:scale worker=0

Worker dyno のスケール数を 0 にできます。

$ ps:scale worker=1

Worker dyno のスケール数を 1 にできます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

「Node.js 8.10を使用するAWSのLambda関数が非推奨になるよ」というお知らせを読んで考えたこと

はじめに

社内向けにお知らせを書いていたけど、残念な弊社では議論できそうな人がいなかったので、保守とか更新についての考えとかを指摘があればQiitaでコメントもらいたいなと思って投稿した記事です。

なので、コメントがあればいただけますと幸いです。

AWS Lambdaのサービス利用に関するお知らせ

2019年10月19日 午前 4:10:00 UTC+9にPersonal Helth Dashboardにて通知がありました。

通知内容

We are contacting you as we have identified that your AWS Account currently has one or more Lambda functions using Node.js 8.10, which will reach its EOL at the end of 2019.

このAWSアカウントには現在、Node.js 8.10を使用するLambda関数があり、2019年末にEOLに達することを確認したため、お知らせします。

What’s happening?

The Node community has decided to end support for Node.js 8.x on December 31, 2019 [1]. From this date forward, Node.js 8.x will stop receiving bug fixes, security updates, and/or performance improvements. To ensure that your new and existing functions run on a supported and secure runtime, language runtimes that have reached their EOL are deprecated in AWS [2].

どうゆうことですか?

Nodeコミュニティは、Node.js 8.xのサポートを2019年12月31日に終了することを決定しました。[1]
この日以降、Node.js 8.xはバグ修正、セキュリティアップデート、および/またはパフォーマンス改善の受信を停止します。サポートされている安全なランタイムで新しい関数と既存の関数を実行することは、EOLに達した言語ランタイムはAWSで非推奨になりました。[2]

For Node.js 8.x, there will be 2 stages to the runtime deprecation process:
1. Disable Function Create – Beginning January 6, 2020, customers will no longer be able to create functions using Node.js 8.10
2. Disable Function Update – Beginning February 3, 2020, customers will no longer be able to update functions using Node.js 8.10

Node.js 8.x の場合、ランタイムは2段階のプロセスで非推奨になります。

1. 関数を無効にする
 2020年1月6日以降、お客様はNode.js 8.10を使用して関数を作成できなくなります。

2. 関数の更新を無効にする
 2020年2月3日以降、お客様はNode.js 8.10を使用している関数を更新できなくなります。

After this period, both function creation and updates will be disabled permanently. However, existing Node 8.x functions will still be available to process invocation events.

この期限が過ぎると、関数の作成と更新の両方が永久に無効になります。
ただし、既存のNode 8.x関数は、呼び出しイベントによる利用は引き続き可能です。

What do I need to do?

We encourage you to update all of your Node.js 8.10 functions to the newer available runtime version, Node.js 10.x[3]. You should test your functions for compatibility with the Node.js 10.x language version before applying changes to your production functions.

何をする必要がありますか?

Node.js 8.10のすべての関数を利用可能な新しいランタイムバージョン(Node.js 10.x)に更新することをお勧めします。
実動関数に変更を適用するために、Node.js 10.x言語バージョンとの互換性について関数をテストする必要があります。

What if I have issues/What if I need help?

Please contact us through AWS Support [4] or the AWS Developer Forums [5] should you have any questions or concerns.

問題がある場合/助けが必要な場合はどうなりますか?

 質問や懸念がある場合は、AWSサポート[4]またはAWS開発者フォーラム[5]からご連絡ください。

[1] https://github.com/nodejs/Release
[2] https://docs.aws.amazon.com/lambda/latest/dg/runtime-support-policy.html
[3] https://aws.amazon.com/about-aws/whats-new/2019/05/aws_lambda_adds_support_for_node_js_v10/
[4] https://aws.amazon.com/support
[5] https://forums.aws.amazon.com/forum.jspa?forumID=186

考えたこと

今回はNode.jsのため弊社では影響はないので問題はないでしょう。(利用していないので)

ただし、これがPythonになった場合は話が変わります。

 既存のLambda関数の更新およびテスト

現在、保守/運用している顧客のAWS環境においては、Python 3.6で動くLambda関数をいくつか利用しています。

先日、2019年10月14日に Python 3.8の正式リリースが発表されました。

詳細な機能についてはまとめてくれているものがあるので参考にするとよいでしょう。
Python3.8の新機能 (まとめ)

現在AWS Lambdaでデフォルトで利用できるPythonのランタイムバージョンは3.6と3.7です。

AWSでの他の言語ランタイムのサポートの雰囲気を鑑みると、1 or 2 バージョンにのみをサポートとし3つ前のバージョンはサポート非推奨とする流れでしょう。

つまり、現在利用中のLambda関数はすべて、更新準備に向けてテストを実施しなければなりません。

ランタイムポリシー

[2] https://docs.aws.amazon.com/lambda/latest/dg/runtime-support-policy.html

を覗いてみました。

AWS Lambda ランタイムは、メンテナンスとセキュリティの更新の対象となるオペレーティングシステム、プログラミング言語、およびソフトウェアライブラリの組み合わせを中心に構築されています。ランタイムのコンポーネントがセキュリティアップデートでサポート対象外となった場合、Lambda はこのランタイムを廃止します。

廃止は、2 つのフェーズで行われます。最初のフェーズでは、廃止予定のランタイムを使用する関数を作成することはできません。少なくとも 30 日間は、廃止予定のランタイムを使用する既存の関数を引き続き更新することができます。この期間が過ぎると、関数の作成と更新のいずれも、完全に無効になります。ただし、この関数は呼び出しイベントの処理に引き続き使用することができます。

お知らせ内容のことですね。

ほとんどの場合、言語バージョンまたはオペレーティングシステムのサポート終了日は事前に通知されます。今後 60 日以内に廃止予定の関数がランタイムで実行されている場合は、関数をサポートされているランタイムに移行して準備する必要があることが Lambda より E メールで通知されます。下位互換性のない更新を必要とするセキュリティ上の問題、または長期サポート (LTS) スケジュールをサポートしないソフトウェアなど、場合によっては事前通知が不可能な場合があります。

『下位互換性のない更新を必要とするセキュリティ上の問題、または長期サポート (LTS) スケジュールをサポートしないソフトウェアなど、場合によっては事前通知が不可能な場合があります。』

ですよねー。
ということは、概ね新しいランタイムバージョンが正式リリースされた場合は、身構えておく必要があるということですかね。

ランタイムが廃止されると、Lambda は呼び出しを無効にすることで終了する可能性があります。廃止予定のランタイムは、セキュリティアップデートやテクニカルサポートの対象にはなりません。ランタイムを終了する前に、Lambda によって、影響を受けるお客様に追加の通知が送信されます。現時点では、ランタイムの廃止予定はありません。

ちょっと日本語理解が難しいような気がする文章。

呼び出し すなわち、 CloudWatchとかのイベントトリガーのことを指しているのかな。
あ、違うのかな。AWS様が呼び出し機能を無効にした場合、その時点からランタイムが終了するから気を付けてねって方かな。

しかも廃止予定のランタイムについては、更新とかはサポートしませんよっと。

お知らせ通知から廃止になるまでの期間

最低でも30日間の利用は可能。
今回の通知が、2019年10月19日 で、2020年2月3日以降更新不可ということは、
テストできる期間は約3か月ほどって感じでしょうか。

カスタムランタイム利用して、自分たちで面倒みるのは運用面であったりバージョンの管理性とか
もろもろ良いやり方って感じではないですもんねえ。

まとめ

とりあえず、AWS Lambdaのランタイムの廃止予定については、
事前には通知はするけど、すべて顧客で対応してねということ。

今後やっておくべきこと(やっておきたいこと)

  1. 利用している言語の新規バージョンリリースをウォッチする。
  2. AWSのランタイムに合わせて関数を更新する
  3. Lambda関数の一覧をランタイムバージョン付きでリストアップしておくこと。

こんなところでしょうか。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CircleCI でテストを並列に分割する

はじめに

テストを追加していくとテストの実行時間がボトルネックになりがちです。
そこで CircleCI ではテストを分割し、parallelism というキーを指定して並列実行ができるようになっています。
ここでは Node.js のプロジェクトで Jest を使用したものを例に話を進めます。

環境

CircleCI 2.1

CircleCI の設定

ジョブの並列レベルの設定

通常 CircleCI のジョブは config.yml に設定した処理を 1 つの Executor 上でジョブが動作します。
複数のジョブを並列に動作させたい場合は、parallelism というキーに並列数を 1 以上で設定します。
ここでは 2 を指定しているので並列数 2 で動作します。

.circleci/config.yml
version: 2.1
jobs:
  test:
    docker:
      - image: circleci/node:12
    parallelism: 2

ジョブの並列レベルの設定

並列数を増やしただけでは並列にジョブが動作するだけで、テスト時に同じテストファイルが実行されてしまいます。
次の設定を追加してテストファイルを分割することで分割されたテストファイルが並列に実行されます。
まず circleci tests glob コマンドにテストファイルのパスを渡します。
glob に使えるパターンはドキュメントを参照してください。
ここでは JavaScript と TypeScript が同居するプロジェクトを想定し、jsts を指定しています。
取得したファイルを分割するにはパイプで circleci tests split コマンドに渡します。
--split-by オプションには filesizetimings を指定できます。
今回は timings を指定します。
timings は、別途 store_test_results キーを使用することで適切なタイミングデータが生成されます。
store_test_results キーを使用した記事についてはこちらを参照してください。
split コマンドで実行した結果を環境変数に保存してからテストコマンドに渡すことで、テストが並列に分割された状態で実行されます。
DB などに依存するテストの場合でも並列に実行されるためデータが競合することはありません。

.circleci/config.yml
version: 2.1
jobs:
  test:
    docker:
      - image: circleci/node:12
    parallelism: 2
    steps:
      - run:
          command: |
            TESTFILES=$(circleci tests glob "__test__/**/*.spec.{js,ts}" | circleci tests split --split-by=timings)
            npm test $TESTFILES

さいごに

簡単ですが、CircleCI の並列分割テストについて取り上げました。
parallelism と CircleCI が用意した分割コマンドを実行することで簡単に並列実行できるのは便利だと感じます。

参考

Running Tests in Parallel - CircleCI

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CircleCI で Jest のテスト結果を保存する

はじめに

テストを実行するに当たって、テストカバレッジやテストの実行時間を計測してテスト戦略を立てていくことは重要です。
ここでは CircleCI で Jest を使ったテストにおける設定項目をまとめます。

環境

CircleCI 2.1

Jest の設定

カバレッジを取得する設定

jest.config.js に以下の設定を追加します。
collectCoverage を有効にし、coverageDirectory でカバレッジレポートの出力先を指定しています。
プロダクションコードが src ディレクトリ配下にあり、JavaScript、TypeScript が存在するプロジェクトを想定しています。

jest.config.js
  collectCoverage: true,
  collectCoverageFrom: ['src/**/*.{js,ts}'],
  coverageDirectory: 'coverage',

これでテストを実行するとカバレッジレポートが出力されます。

テスト結果を取得する設定

プロジェクトに jest-junit を追加します。

$ npm install --save-dev jest-junit

jest-junit は Jest で実行したテスト結果を JUnit 形式にレポートを出力するライブラリです。
jest.config.js に以下の設定を追加します。

jest.config.js
  reporters: [
    'default',
    [
      'jest-junit',
      {
        suiteName: 'jest tests',
        outputDirectory: 'reports/jest',
        outputName: 'js-test-results.xml',
        classNameTemplate: '{classname}-{title}',
        titleTemplate: '{classname}-{title}',
        ancestorSeparator: '',
      },
    ],
  ],

いくつか設定に使った項目について触れていきます。
他の設定項目に関しては、README を参照してください。

  • suiteName
    testsuites タグの name 属性に表示する名前を指定します。

  • outputDirectory
    テスト結果の出力ディレクトリを指定します。

  • outputName
    テスト結果のファイル名を指定します。

  • classNameTemplate
    testcase タグの classname 属性に表示する名前を指定します。

  • titleTemplate
    testcase タグの name 属性に表示する名前を指定します。

  • ancestorSeparator
    Jest の describe ブロックを結合するために使用する文字を指定します。

通常のテストコマンドとは別に CircleCI 用に npm scripts を追加します。
--ci オプションで CI に最適化され、--runInBand オプションで実際の仮想化されたビルド環境のみを使用するようになります。

package.json
    "test:ci": "jest -i --ci --runInBand"

CircleCI の設定

カバレッジを保存する設定

追加した npm run test:ci コマンドでテストを実行します。
store_artifacts キーに生成された coverage ディレクトリを指定すると CircleCI 上へと保存されます。

.circleci/config.yml
version: 2.1
jobs:
  test:
    docker:
      - image: circleci/node:12
    steps:
      - checkout
      - run: npm install
      - run: npm run test:ci
      - store_artifacts:
          path: coverage

テスト結果を保存する設定

store_test_results キーに reports ディレクトリを指定することで Builds ページの Test Summary タブに表示されます。
store_artifacts キーに指定することで coverage 同様 CircleCI 上へと保存されます。

.circleci/config.yml
 version: 2.1
 jobs:
   test:
     docker:
       - image: circleci/node:12
     steps:
       - checkout
       - run: npm install
       - run: npm run test:ci
+      - store_test_results:
+          path: reports
+      - store_artifacts:
+          path: reports
       - store_artifacts:
           path: coverage

実際に CircleCI 上で実行したテスト結果を確認すると Test Summary タブでは失敗したテストを見やすく表示してくれます。
成功した場合はスローテストを表示してくれます。

Test Summary

Artifacts タブでは CircleCI 上に保存したテスト結果ファイルが確認できます。
カバレッジレポートでは HTML ファイルが生成されるため、開くとそのままブラウザから表示できます。

Artifacts

Timing タブでは、テストのタイミングデータを保存します。
これは、テストを並列実行した際のタイミング解析に用いることができます。
詳しくはドキュメントを参照してください。

Timing

さいごに

CircleCI で Jest のテスト結果を取り扱う方法について取り上げました。
デフォルトでは CircleCI 上で長いスクロールをしながら原因を特定する必要がありましたが、これらの設定をすることでテスト結果をページ上部から確認できるようになりとても分かりやすくなりました。
是非これらの設定をしてテストの改善に役立ててみてください。

参考

Generating Code Coverage Metrics - CircleCI
Configuring CircleCI - CircleCI
jest-community/jest-junit: A Jest reporter that creates compatible junit xml files - GitHub

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

超初心者がLineBot×Obnizでスピーカから音を出してみた。

はじめに

先週、人生で初めてLineBotを作った超初心者です。
勢いにのって、Obnizに初挑戦。
パソコンとObnizが繋がって画面に表示されただけでも、かなりワクワクです。
出来ることは限定的ですが、これからObnizでトライする方々の超初心者と指導者の方々の情報のために初歩的なことを記載しておきます。

作った目的

Obnizはパソコンから操作するだけでもIOTぽさがあり楽しいですが
LineBotと連動すれば更に世界が広がるかも・・・。
ということで練習がてら実践してみました。
裏でLEDやらマイクロサーボなどちょっと触りましたが
今回はLineBotとのやり取りが一番簡単にできたスピーカーで出来たことを書いてます。

仕様

・「音を教えて」と入力すると「ヘルツで入れてください」と答えてくれる。
・数字を入れるとhzで音を出力する。
・ずっと鳴っているとうるさいので

使った環境

・Node.js v10.16.3
・Windows 10 pro
・Visual Studio Code v1.39.1
Obniz ボード
圧電スピーカー(圧電サウンダ)(13mm)PKM13EPYH4000-A0
・USB2.0ケーブル(A-microBタイプ)50cm

作成方法

こちらは老眼と加齢性難聴のチェックができるLINEbotとIotの作成を参考に作りました。
そちらの記事のコードBの部分だけ、非常にシンプルなものにしたので記載します。

''use strict';

const express = require('express');
const line = require('@line/bot-sdk');
const PORT = process.env.PORT || 3000;

const config = {
    channelSecret: 'Lineのチャンネルシークレット',
    channelAccessToken: 'Lineのアクセストークン'
};

 // Obnizの準備
var Obniz = require("obniz");
var obniz = new Obniz("Obniz ID");  // Obniz ID を入力
var speaker; // 全体で使えるようにするスコープ
obniz.onconnect = async function () {
    speaker = obniz.wired("Speaker", {signal:0, gnd:1});
}

const app = express();

app.get('/', (req, res) => res.send('Hello LINE BOT!(GET)')); //ブラウザ確認用(無くても問題ない)
app.post('/webhook', line.middleware(config), (req, res) => {
    console.log(req.body.events);
 //ここのif分はdeveloper consoleの"接続確認"用なので削除して問題ないです。
    if(req.body.events[0].replyToken === '00000000000000000000000000000000' && req.body.events[1].replyToken === 'ffffffffffffffffffffffffffffffff'){
        res.send('Hello LINE BOT!(POST)');
        console.log('疎通確認用');
        return; 
    }

    Promise
      .all(req.body.events.map(handleEvent))
      .then((result) => res.json(result));
});

const client = new line.Client(config);

function handleEvent(event) {
    if (event.type !== 'message' || event.message.type !== 'text') {
      return Promise.resolve(null);
    }
  //ここからがコードB
    var hz = Number(event.message.text);
    speaker.play(hz);
    obniz.wait(1000);
    speaker.stop();
    let replyText = '';
    if(event.message.text === '音を教えて'){
      replyText = 'ヘルツを言ってください';
    }else{
      replyText = hz;
    }
    return client.replyMessage(event.replyToken, {
      type: 'text',
      text: replyText
    });
  }
  app.listen(PORT);
  console.log(`Server running at ${PORT}`);

動作確認

いちおう単純な返答と音は確認。音が出る瞬間、個人的な達成感はあるも家族から見たら地味・・。
Screenshot_20191021-023825.png

疑問

もっと色々な応答を試したかったが、let replyText以下を少し変えるだけでうまく作動しなくなってしまった。前回実施したじゃんけんBOTとの組み合わせもトライしたが「じゃんけん」か「音の出力」どちらかになってしまいました。どうして組み合わせができないかもう少しお勉強してみたいと思います。

感想

素直にLineBotもIOTも楽しい!!
ですが二つを組み合わせると初心者には不明なドツボにはまる危険性も高まる気がしました(笑)
ObnizはスピーカーのほかにLED(個人的には豊富な色もだせてはまる予感)やモーターなどツールにバラエティがあるので少しづつお勉強しつつ、幅を広げていきたいです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む