Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all 8902 articles
Browse latest View live

Alibaba Cloud ECSへのNode.jsのインストールと設定

$
0
0

このチュートリアルでは、Alibaba Cloud ECSインスタンスにNode.jsをインストールして設定します。

本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。

前提条件

  • Alibaba Cloud Elastic Compute Service (ECS)を有効にし、有効な支払い方法を確認する必要があります。新規ユーザーの場合は、新規アカウントで300ドル~1200ドル相当のAlibaba Cloudクレジットを獲得できます。ECSインスタンスのセットアップ方法がわからない場合は、このチュートリアルまたはクイックスタートガイドを参照してください。ECSインスタンスには、少なくとも1GBのRAMと1つのCoreプロセッサが必要です。
  • Alibaba Cloudから登録されたドメイン名。すでにAlibaba Cloudまたは他のホストからドメインを登録している場合は、そのドメインネームサーバーレコードを更新することができます。
  • ドメイン名は、あなたのAlibaba Cloud ECSのIPアドレスを指している必要があります。
  • Alibaba CloudのVNCコンソールまたはPCにインストールされているSSHクライアントにアクセスします。
  • サーバーのホスト名を設定し、root権限のユーザーを作成します。

環境の設定

サーバーの設定

パッケージのインストールを進める前に、以下のコマンドを実行してUbuntuシステムをアップデートしてください。このコマンドを実行するには、root ではないユーザーから sudo 権限でログインすることを忘れないでください。

# sudo apt update && sudo apt upgrade

ソフトウェアプロパティ共通のインストール

Docker CEのインストールに対応したファイルを取得するためには、software-properties-commonパッケージが必要です。software-properties-commonパッケージをインストールするには、以下の手順に従います。

software-properties-commonをインストールするには、以下のコマンドを実行します。

# sudo apt-get install software-properties-common -y 

apt-transport-httpsのインストール

Docker CEのインストールにはapt-transport-httpsが必要です。apt-transport-httpsをインストールするには、以下の手順を実行します。

apt-transport-httpsをインストールするには、以下のコマンドを実行します。

# sudo apt-get install apt-transport-https -y 

ca-certificatesのインストール

Docker CEのインストールにはca-certificatesが必要です。ca-certificatesをインストールするには、以下の手順で行います。

ca-certificatesをインストールするには、コマンドを実行します。

# sudo apt-get install ca-certificates -y 

curlのインストール

Docker CEのインストールにはcurlが必要です。curlをインストールするには、以下の手順で行います。

curlをインストールするには、コマンドを実行します。

# sudo apt-get install curl -y 

Docker CEのインストール

Docker community editionをインストールするには、以下の手順で完了します。

以下のコマンドを実行して、Docker用のGPGキーを追加します。

# curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

以下のコマンドを実行して、GPGキーのフィンガープリントを確認します。

# sudo apt-key fingerprint 0EBFCD88

ここで、以下のコマンドを実行してDockerリポジトリを追加します。

# sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable”

以下のコマンドを実行してシステムをアップデートし、追加されたリポジトリをロードします。

# sudo apt update

以下のコマンドを実行してDockerをインストールします。

# sudo apt install docker-ce

以下のコマンドを実行して、ユーザ名をdockerグループに追加します。

# sudo adduser aareez docker 

現在のシェルセッションを閉じて新しいセッションを開始すると、dockerが実行できなくなり、パーミッションエラーが発生する可能性があります。

次に、以下のコマンドを実行して、dockerが正しく実行されているかどうかを確認します。

# docker run hello-world

Docker Composeのインストール

Docker composeをダウンロードしてインストールするには、以下の手順で行います。

以下のコマンドを実行して、最新版のdocker composeをダウンロードしてインストールします。

# sudo curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose

以下のコマンドを実行して、ファイルのパーミッションを設定します。

# sudo chmod +x /usr/local/bin/docker-compose

以下のコマンドを実行して起動したコンテナの一覧を取得します。

# docker container ls —all

image.png

ポート808080を使用しているコンテナを停止します。そのためには、コンテナのIDを取得し、以下の8baab990c424に置き換えて、以下のコマンドを実行します。

# docker stop 8baab990c424

Node.jsのインストールと設定

このチュートリアルでは、具体的にNode.jsの公式イメージを使ってDocker上にインストールしていきます。Node.jsをダウンロードしてインストールするには、以下のコマンドを実行して、公式のdockerリポジトリから最新のNodejsを引っ張ってくる必要があります。

# docker pull linode/server-node-js

ここで以下のコマンドを実行してdockerイメージを実行します。

# docker run -d -p 80:3000 linode/server-node-js

これで、アリババクラウドECSのIPアドレスまたはそのIPアドレスを指すドメイン名にアクセスして確認することができるようになりました。http://your_domain.tld/test.htm

以下のページが表示されます。

image.png

ファイアウォールとポートの設定

ファイアウォールを有効にしている場合は、クラウドサーバーの Alibaba Cloud セキュリティグループで、ポート 80/tcp と 443/tcp の例外を追加するルールを定義する必要があります。ECSインスタンスの作成時にこれらのポートを有効にすることができますが、これらのポートのブロックを解除し忘れた場合は、このガイドの手順に従ってください:セキュリティグループルールの追加

アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ


【Node.js 超入門】Node.jsとExpessを使ってCRUD処理できるサーバサイドの実装をする!

$
0
0

【Node.js 超入門】Node.jsとExpessを使ってCRUD処理できるサーバサイドの実装をする!

【Node.js 超入門】という参考書を読んで、Node.jsで実装した内容を備忘として書きます。

今回は、データベースを使って画面からユーザ情報を登録、更新などCRUD処理できるアプリケーションを作成します。
メインとしてNode.jsとExpressを使い、サーバサイドの処理を作ります。
データベースはMySQLを使います。

大まかな流れとしては、
・環境構築
・コード実装
・動作確認

続きはこちらの記事にまとめています!
https://masa-enjoy.com/nodejs-learning1

【共有用】Windows10PCにNode.jsをインストールする手順

$
0
0

本記事では、Windows10PCにNode.jsをインストールする手順を紹介いたします。

Node.jsとは

サーバーサイドで動かすことができるJavaScriptです。

JavaScriptは近年多くのWebサイトで活用されており
例えばカーソルを当てるとメニューが飛び出したり
image.png

クリックすると画像が拡大するような
動きのあるWebサイトを作成するのに不可欠な言語です。

Node.jsはこのJavaScriptをサーバサイド(裏側の仕組み)で活用することができる仕組みになります。

公式では以下のように書かれています
Node.js はスケーラブルなネットワークアプリケーションを構築するために設計された非同期型のイベント駆動の JavaScript 環境です。 以下の「Hello World」の例では、たくさんの接続を同時に処理することができます。 各接続ごとにコールバックは発火され、何もすることがない場合、Node.js はスリープします。
これは OS のスレッドが採用されている一般的な同時実行モデルとは対照的です。 スレッドベースのネットワーキングは比較的非効率であり、使うのはとても困難です。 さらに Node.js にはロックがないので Node.js ユーザーはプロセスのデッドロックの悩みから開放されます。 ほとんどの Node.js の関数は I/O を直接実行しないため、プロセスをブロックしません。 ブロックしないのでスケーラブルなシステムを開発するのに Node.js はとても最適です。
出典:https://nodejs.org/ja/about/

自分の中では最近の開発で選択することが多い仕組みの1つです

理由としては以下になります。 
※ほかにもメリットは多くありますが大きく以下の3つをピックアップしています。
・開発環境として軽くてサクサク動くVS Codeを使って快適に開発ができる
・Node.jsを動かすことができるサーバを簡単に構築することができる
・Node.jsで使うことができるライブラリが豊富なので開発品質向上や工期の短縮が可能

インストール手順

公式サイトのダウンロードページにアクセスします
https://nodejs.org/ja/download/

LTSまたは最新版のWindowsの64bit(32bit版のWindows10PCはほとんど出回っていませんが32bit版を使用している方は32bitを指定)を選択し、ダウンロードします。

image.png

ダウンロードしたインストーラを起動し、インストールをすすめます。

インストール時の注意点は特にありませんが

インストール先を変えたい場合は、以下の設定の際にインストール先を変更してください。
特に変更しない場合はnextを選択してください
image.png

インストールのカスタマイズも強いこだわりがなければ何もせずnextを選択してください
※弊社ハンズオン等で動かす分にはデフォルトにしたままでnextを選択してください
image.png

chocolateyのインストールも基本は不要となりますのでチェックはいれずにnextを選択してください
※弊社ハンズオン等で動かす分には不要です
image.png

Installを選択するとInstallが開始されます
image.png

インストールの確認

ここに入力して検索から『cmd』を入力して、コマンドプロンプトを呼び出します
image.png

コマンドプロンプトにて『node -v』と入力して、バージョン情報が表示されればインストール完了です
※表示されるバージョン番号は下記キャプチャと異なる場合がありますがバージョン番号が確認できればインストールは完了していますので問題ありません
image.png

TypeScript + Node.jsプロジェクトにESLint + Prettierを導入する手順2020

$
0
0

TL;DR

https://github.com/notakaos/typescript-node-base-with-eslint-prettier

完成形のソースコードはこちら↑

この記事の趣旨

TypeScript + Node.js プロジェクトのはじめかた2020で作成したTypeScript + Node.jsのプロジェクトに ESLint / Pretiter / husky & lint-stagedを導入する手順を紹介します。

今回導入するツールとバージョンは以下になります。

項目バージョン
ESLint7.6.0
Prettier2.0.5
husky4.2.5
lint-staged10.2.11

動作環境

node と npm はインストール済みとします。

$ node -v
v12.18.3
$ npm -v
6.14.6

また、今回の記事はmacOSにて検証しております。

$ uname-v
Darwin Kernel Version 19.6.0: Sun Jul  5 00:43:10 PDT 2020; root:xnu-6153.141.1~9/RELEASE_X86_64

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.15.6
BuildVersion:   19G73

Linux環境だと手順はほぼ同じだと思いますが、Windows環境の場合は読み替えが必要になるかもしれません。

ESLint

https://eslint.org/

ESLintについて

ESLintイーエスリントはJavaScriptコードのエラーチェックを行うLinterと呼ばれるツールの一つです。

JavaScriptは動的な言語なので、実行するまでエラーがあるのかどうかわからない部分があります。
ESLintを使うことで、JavaScriptのコードを実行することなくコード上の問題を発見するのに役立ちます。

また、ESLintは本来JavaScript用ですが、TypeScript用のプラグインを追加することにより、TypeScriptでもESLintが使えるようになります。

以下ではTypeScript (+ Node.js)なプロジェクトへのESLintの導入手順を紹介します。

ESLint (+ TypeScriptプラグイン)の導入

https://github.com/notakaos/typescript-node-baseにESLintを導入します。

# typescript-node-base リポジトリをローカルで作成済みとします cd typescript-node-base

Node.jsプロジェクトにESLintとESLintのTypeScript用プラグインを追加します。

typescript-node-base
npm install-D eslint typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin

# ESLintのバージョン確認
./node_modules/.bin/eslint --version#=> v7.6.0

次に、ESLint用のTypeScript設定ファイル tsconfig.eslint.jsonを作成します。

typescript-node-base
# tsconfig.eslint.json ファイルの作成touch tsconfig.eslint.json

# エディターで編集(お好みのエディターをお使いください)
vim tsconfig.eslint.json
tsconfig.eslint.json
{"extends":"./tsconfig.json","include":["src/**/*.ts",".eslintrc.js"],"exclude":["node_modules","dist"]}

そして、ESLint用の設定ファイル .eslintrc.jsをプロジェクトディレクトリ直下に作成します。

typescript-node-base
# .eslintrc.js ファイルの作成touch .eslintrc.js

# エディターで編集(お好みのエディターをお使いください)
vim .eslintrc.js
~/typescript-node-base/.eslintrc.js
module.exports={root:true,env:{es6:true,node:true,},parser:'@typescript-eslint/parser',parserOptions:{sourceType:'module',ecmaVersion:2019,// Node.js 12の場合は2019、他のバージョンのNode.jsを利用している場合は場合は適宜変更するtsconfigRootDir:__dirname,project:['./tsconfig.eslint.json']},plugins:['@typescript-eslint',],extends:['eslint:recommended','plugin:@typescript-eslint/recommended','plugin:@typescript-eslint/recommended-requiring-type-checking',],rules:{},};

なお、extendsでいくつかの項目がありますが、extendsはあらかじめ用意されたESLintルールのセットになります。これを入れることによって、以下のルールを適用しています。

これで、ESLint導入完了です。

ESLintの実行

早速、ESLintを実行してみましょう。

typescript-node-base
npx eslint src/index.ts
実行結果

何も表示されなければ成功です!

設定やソースコードに問題がない場合、何も表示されないのが正常です。
もしここでエラーが表示される場合は記述ミスが考えられますので、各種設定ファイルやソースコードを見直してください。

次に、ESLintでエラーを検知できるか確認してみましょう。
src/index.tsを以下のように編集します。

src/index.ts
function hello(name: string): string {
  return `Hello, ${name}!`;
}- console.log(hello('TypeScript'));
+ console.log(hello('TypeScript')

最後の行の閉じカッコを一つ削除して、文法エラーを意図的に発生させます。
ソースコードを書き換えたら保存し、ESLintを実行します。

typescript-node-base
npx eslint src/index.ts

すると以下のようなエラーが発生します。

実行結果
/Users/notakaos/typescript-node-base/src/index.ts
  6:0  error  Parsing error: ')' expected

✖ 1 problem (1 error, 0 warnings)

「パースエラー: )が期待されている(が存在しない)」というエラーがでましたね。
ESLintで文法チェックが正しく動いていることがわかります。

ちなみに、文法のチェックに関してはtscでも同様のチェックができます。
(--noEmitオプションをつけてjsファイルを生成しないようにします)

typescript-node-base
npx tsc --noEmit
実行結果
src/index.ts:6:1 - error TS1005: ')' expected.

6 



Found 1 error.

そのため、文法チェックだけだとtscのみでよいのでは? と思われるかもしれませんが、ESLintにはtscに含まれていないエラーチェック機能が入っているため、tscとESLintを併用することによりエラーの検知率をあげることができます。

ここで、tscではエラーにならず、ESLintでエラーになる例を見てみましょう。
src/index.tsに以下の記述を追加します。

src/index.ts
function hello(name: string): string {
  return `Hello, ${name}!`;
}- console.log(hello("TypeScript")
+ console.log(hello("TypeScript")); // 元に戻す
+ function example() {} // どこからも呼ばれない中身が空の関数を用意

まずはtscを実行してみます。

npx tsc --noEmit
実行結果

特にエラーもなく正常にコマンドが終了しました。
次にESLintを実行します。

npx eslint src/index.ts
eslint実行結果
/Users/notakaos/typescript-node-base/src/index.ts
  7:10  warning  'example' is defined but never used  @typescript-eslint/no-unused-vars
  7:20  error    Unexpected empty function'example'  @typescript-eslint/no-empty-function

✖ 2 problems (1 error, 1 warning)

ESLintでは1つの警告と1つのエラーが発生しましたね。

警告・エラーの内容について、

  • 「警告: example関数は定義されているものの使われていない」
  • 「エラー: 空の関数は期待されていない」

といった内容になっています。

このように、tscでは通るもののESLintではエラーになるようなものもあり、
両者を適切に設定することでよりバグが少ないコードを書くことができるようになります。

最後に毎回 eslint / tscのコマンドを手打ちすると面倒なので、簡単にエラーチェックができるようにpackage.jsonのscriptsに設定を追加します。

package.json
{
  ...
  "scripts": {
    "dev": "ts-node src/index.ts",
    "dev:watch": "ts-node-dev --respawn src/index.ts",
    "clean": "rimraf dist/*",
    "tsc": "tsc",
    "build": "npm-run-all clean tsc",
-   "start": "node ."
+   "start": "node .",
+   "check-types": "tsc --noEmit",
+   "eslint": "eslint src/**/*.ts",
+   "eslint:fix": "eslint src/**/*.ts --fix",
+   "lint": "npm-run-all eslint check-types"
  },
  ...
}

エラーチェックを実行する時は以下のコマンドを実行します。

typescript-node-base
npm run lint

こうすることで、一度のコマンド実行で eslinttscの両方を実行することができます。

また、以下のように個別に実行することもできます。

typescript-node-base
# tsc --noEmit だけ実行
npm run check-types 

# eslint だけ実行
npm run eslint

# eslint のエラーを(できるものだけ)自動修復
npm run eslint:fix

普段は npm run lintを使い、必要に応じて個別のコマンドを使い分けることになります。

Prettier

https://prettier.io/

Prettierについて

Prettierプリティアはソースコードの整形ツール(コードフォーマッター)の一つです。
JavaScript/TypeScript/JSON等の形式に対応しています。

Prettierを使うことで、スペースやインデント、文字列のクオートの統一、1行が長くなりすぎた場合の改行位置調整などを自動で行ってくれます。

Prettier等のコードフォーマッターを使わない場合、実装者によってコードの書き方がばらばらになり、コードレビュー時にインデント位置やスペース等の指摘が入ってしまうことがあります。それだと本質的なディスカッションができません。そのため、フォーマッターを設定しておくことで、コードの書き方が統一され、ロジックのレビューに集中できるようになる効果があります。

ちなみに、ESLintにもコードフォーマット機能があるため、ESLintと併せてPrettierを利用する場合はESLint側のフォーマットルールをOFFにする必要があります。幸い、PrettierとESLintのフォーマットルールがぶつからないようにするためのルールセット(config)が用意されていますので、そちらも併せて導入します。

Prettier (+ eslint-config-prettier) の導入

PrettierとESLintのPrettier configをインストールします。

typescript-node-base
# --save-exact でバージョンを固定してdevインストール
npm install-D--save-exact prettier eslint-config-prettier

# Prettierのバージョン確認
./node_modules/.bin/prettier --version#=> 2.0.5

次に、Prettier用の設定ファイルをプロジェクトディレクトリ直下に作成します。

typescript-node-base
echo"{}"> .prettierrc.json
.prettierrc.json
{}

.prettierrc.jsonは必要に応じて書き換えてください

また、prettierの対象外となるファイルを指定する .prettierignoreをプロジェクトディレクトリ直下に作成します。

typescript-node-base
touch .prettierignore

# エディターで編集
vim .prettierignore
.prettierignore
# Ignore artifacts:
/dist
node_modules
package.json
package-lock.json
tsconfig.json
tsconfig.eslint.json

このままだと、ESLintのコードフォーマット機能とPrettierのコードフォーマット機能がコンフリクトしてしまうので、.eslintrc.jsのextendsに prettierprettier/@typescript-eslintの記述を追加します(追加する位置はextendsの最後の方になります)。

.eslintrc.js
module.exports = {
  // ...
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:@typescript-eslint/recommended-requiring-type-checking',
+   'prettier',
+   'prettier/@typescript-eslint',
  ],
  // ...
}

これでPrettierの設定は完了です。

コラム: eslint-plugin-prettier について

インターネット上でESlintとPrettierの導入方法を調べると、 eslint-plugin-prettierも一緒に入れる方法が紹介されていることがあります。

いつからかはわかりませんが、 公式ドキュメントによると、eslint-plugin-prettier が 一般的には推奨されなくなっているようです。

なぜ非推奨なのかというと、以下のような理由が挙げられています。

  • エディターに赤い波線がたくさん表示され、煩わしくなる
  • Prettierを直接実行するよりも遅くなる
  • 物事が壊れる可能性がある間接層の1つになる

そのため、この記事では eslint-plugin-prettier を導入せず、eslintとは別にpretiterを実行する形を採用しております。

Prettierの実行

では、Prettierを実行してみましょう。

まず src/index.tsを以下のようにインデントなどがバラバラな状態に書き換えます。

src/index.ts
functionhello(name:string):string{return`Hello, ${name}!`}console.log(hello("TypeScript"))

そして、以下のコマンドでPrettierを実行します。

typescript-node-base
npx prettier --write src/index.ts

すると、以下のようにコードが修正されます。

src/index.ts
function hello(name: string): string {return`Hello, ${name}!`;}

console.log(hello("TypeScript"));

きれいに整形されましたね。

Prettierのnpm-scripts設定

あとは、prettierを簡単に実行できるようにpackage.jsonのscriptsに追記します。

Prettier単体で実行する formatと、 eslint / tsc / prettierを1度に実行する lint:fixを追加しています。

package.json
{
  ...
  "scripts": {
    "dev": "ts-node src/index.ts",
    "dev:watch": "ts-node-dev --respawn src/index.ts",
    "clean": "rimraf dist/*",
    "tsc": "tsc",
    "build": "npm-run-all clean tsc",
    "start": "node .",
    "check-types": "tsc --noEmit",
    "eslint": "eslint src/**/*.ts",
    "eslint:fix": "eslint src/**/*.ts --fix",
+   "format": "prettier --write 'src/**/*.{js,ts,json}'",
-   "lint": "npm-run-all eslint check-types"
+   "lint": "npm-run-all eslint check-types",
+   "lint:fix": "npm-run-all eslint:fix check-types format"
  },
  ...
}

Prettierのみを実行する場合は以下のコマンドを実行します。

typescript-node-base
npm run format

eslinttscも併せて実行する場合は、以下のコマンドを実行します。

typescript-node-base
npm run lint:fix

これでPrettierの導入完了です。

Git commit時に自動でlintを実行する(huskyとlint-staged)

これまでの手順でESLintとPrettierを導入しましたが、コードを修正するたびに lint:fixコマンドを手動で実行する必要がありました。
そのため、lintをかけていないコードを間違ってコミットしてしまうことがあります。

これを防ぐため、git commit時に esLint/ tsc / prettierを自動的に実行するように huskylint-stagedを導入します。

huskyとは

https://github.com/typicode/husky

gitのcommit前やpush前などに特定のコマンドを実行するためのGit hooksを簡単に作成するためのツールです。後述のlint-stagedと組み合わせて使います。

lint-stagedとは

https://github.com/okonet/lint-staged

git addでステージングに追加されたファイルに対して、指定したコマンドを実行します。

huskyとlint-stagedの導入

huskyとlint-stagedは以下のコマンドを実行するとpackage.jsonに自動で設定が追加されます。

typescript-node-base
npx mrm lint-staged
package.json
{
  ...
  "devDependencies": {
    "@types/node": "^12.12.54",
    "@typescript-eslint/eslint-plugin": "^3.9.0",
    "@typescript-eslint/parser": "^3.9.0",
    "eslint": "^7.6.0",
    "eslint-config-prettier": "6.11.0",
+   "husky": "^4.2.5",
+   "lint-staged": "^10.2.11",
    "npm-run-all": "^4.1.5",
    "prettier": "2.0.5",
    "rimraf": "^3.0.2",
    "ts-node": "^8.10.2",
    "ts-node-dev": "^1.0.0-pre.56",
    "typescript": "^3.9.7"
- }
+ },
+ "husky": {
+   "hooks": {
+     "pre-commit": "lint-staged"
+   }
+ },
+ "lint-staged": {
+   "*.js": "eslint --cache --fix",
+   "*.{js,ts,json}": "prettier --write"
+ }
}

そのままではTypeScriptファイルにおいて、ESLintとtscが実行されないので、lint-stageの部分を少し修正します。

package.json
{
  ...
  "lint-staged": {
-   "*.js": "eslint --cache --fix",
+   "*.{js,ts}": "eslint --cache --fix",
+   "*.ts": "tsc --noEmit",
    "*.{js,ts,json}": "prettier --write"
  }
}

これで設定完了です。

husky & lint-staged を試す

それではhuskyとlint-stagedを試してみましょう。

まず src/index.tsを以下のように書き換えます。

src/index.ts
functionhello(name:string):string{return`Hello, ${name}!`;}console.log(hello("TypeScript!!!!!"));

そしてgit addを行い、その後git commitを実行します。

typescript-node-base
git add src/index.ts
git commit -m"Update src/index.ts"
実行結果
husky > pre-commit (node v12.18.3)✔ Preparing...
✔ Running tasks...
✔ Applying modifications...
✔ Cleaning up... 
[feature/husky-lint-staged f69684a] Update src/index.ts
 1 file changed, 1 insertion(+), 1 deletion(-)

eslint / tsc / prettierの各コマンドが実行されたのがわかります。

そして src/index.tsを確認してみると、prettierによって自動整形されているのがわかります。

typescript-node-base
functionhello(name:string):string{return`Hello, ${name}!`;}console.log(hello("TypeScript!!!!!"));

git log -pで差分を確認してみましょう。

typescript-node-base
git log -p
実行結果
...
--- a/src/index.ts
+++ b/src/index.ts
@@ -2,4 +2,4 @@ function hello(name: string): string {
   return `Hello, ${name}!`;
 }

-console.log(hello("TypeScript"));
+console.log(hello("TypeScript!!!!!"));

prettierでコードフォーマットされた後にcommitされていますね。

これでlintをかけずにcommitされることを防ぐことができます。

設定は以上です。

あとはお好みでカスタマイズしましょう!

成果物

以上の手順を実行した完成形のソースコードは以下のリポジトリをご参照ください。

https://github.com/notakaos/typescript-node-base-with-eslint-prettier

参考

変更履歴

  • 2020/8/12 記事公開

【Node.js】Expoプッシュ通知を一斉送信するWebAPI|配列を任意の数に分割をする

$
0
0

はじめに

現在Expo ReactNativeを使ってネイティブアプリ開発をしています。
Expoを使ってプッシュ通知を送るためにプッシュ通知のTokenを1つ、1つPOSTリクエストを飛ばしてもいいのですが、Expoの仕様では最大100個のTokenをまとめてPOSTできる。そこでN個ずつに配列を分割して二次元配列にして処理する方法を紹介します。

以下のような長さ75の配列があるとする、それを10分割して余った分は10個未満になっても分割をする。
今回は長さ75の配列を10個づつ分割して二次元配列にする。

処理前

スクリーンショット 2020-08-12 午後6.59.47.png

処理後

スクリーンショット 2020-08-12 午後7.02.02.png

コード

constmain=()=>{//TOKENにみたて複数の数字を配列にセットletarr=[]for(leti=0;i<75;i++){arr.push(i)}console.log(arr)letresult_arr=[]//分割数constdivision_count=10//配列の数を分割数で割った値を切り上げた値constadd_arr_count=Math.ceil(arr.length/division_count)//add_arr_countの分だけ空配列を追加するfor(leti=0;i<add_arr_count;i++){result_arr.push([])}//いい感じに分割して配列にいれるarr.forEach((item,index)=>{result_arr[Math.floor(index/division_count)].push(item)})console.log(result_arr)}(async()=>{main()})()

Expoを使って実際に通知を送る

私の環境ではNode.jsを使ってWebAPIを作り、まとめて送信できるようにしています。
また、Token一覧を管理しているのはMySQLを使っています。

Request body
プッシュ通知のタイトルを設定するpush_titleとプッシュ通知の本文部分にあたるpush_body載せてください

※本物のコードは外部から実行できないようにセキュリティ対策をしています

コード

constexpress=require('express')// expressモジュールを読み込むconstcors=require('cors')//クロスドメインでアクセスを許可する系のやつconstbodyParser=require('body-parser')//いい感じにGET POSTを解釈するやつconstutil=require('util')// SQL Async/Awaitconstaxios=require('axios')//npm install axiosconstmysql=require('mysql')constmulter=require('multer')// multerモジュールを読み込む これがないとBODYの中身をうまく読み取らない//↑ 各種、「npm install」してください//↑ 各種、「npm install」してください//↑ 各種、「npm install」してください// 例1 npm i express// 例2 npm i corsconstapp=express()// expressアプリを生成するapp.use(bodyParser())app.use(express.static('web'))// webフォルダの中身を公開するapp.use(cors())//CROS許可app.use(multer().none())// multerでブラウザから送信されたデータを解釈する//サーバの受付ポート番号、SQL接続情報、設定ファイル読み込みconstconfig=require('./server_config.json')// config.server.portのポートでサーバを立てるapp.listen(config.server.port,()=>console.log('Listening on port '+config.server.port))//MySQL接続情報Async/Await★★★★★★★★★★★★★★★★★★★★★★★★★★★★//★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★constpool_config={host:config.sql.host,user:config.sql.user,password:config.sql.password,port:config.sql.port,database:config.sql.database,timezone:config.sql.timezone//timezoneの指定省略の場合はシステムローカルになる}//★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★//★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★//汎用的にMySQLを発行するconstrunQuery=async(sql,data)=>{console.log('runQuery...')console.log('sql: '+sql)console.log('data: '+data)constpool=mysql.createPool(pool_config)pool.query=util.promisify(pool.query)//これないと動かないconstrun_sql=mysql.format(sql,data)console.log('発行されたquery:\n'+run_sql+'\n')constresult=awaitpool.query(run_sql)// console.log(JSON.stringify(result))pool.end()// mysqlのコネクションのプロセスを終了させる。returnresult}constuuid=require('node-uuid')app.post('/api/v1/expoPushNotice',(req,res,next)=>{(async()=>{console.log('/api/v1/expoPushNotice...')//私の環境ではMySQLでpush_tokenというTableを作ってそこでTokenを保存していますletpush_token_list=awaitrunQuery('select `push_token` from `push_token`',[])//通知を送るtokenletto_tokens=[]//分割数constdivision_count=100//配列の追加数 切り上げた値の数だけ配列を追加constadd_arr_count=Math.ceil(push_token_list.length/division_count)console.log('add_arr_countの文だけから配列を追加する')//add_arr_countの文だけから配列を追加するfor(leti=0;i<add_arr_count;i++){to_tokens.push([])}push_token_list.forEach((item,index)=>{to_tokens[Math.floor(index/division_count)].push(item.push_token)})console.log('to_tokens: ')console.log(to_tokens)//APIコールconsole.log('pushSend...')constreq_url='https://exp.host/--/api/v2/push/send'constheaders={headers:{Accept:'application/json','Accept-encoding':'gzip, deflate','Content-Type':'application/json',},}//分割した分で別々にPOSTリクエストを飛ばすfor(leti=0;i<to_tokens.length;i++){//bodyに好きなデータを載せると、アプリ側でいろいろできます。constresult=awaitaxios.post(req_url,{'to':to_tokens[i],'sound':'default','title':req.body.push_title,'body':req.body.push_body,'data':{},},headers)console.log('result: ')console.log(result)}res.json({status:200,//message:'リクエストは正常に受信されました',})})(res,next).catch((e)=>{console.log('サーバエラー : '+e)console.log('res : '+res)console.log('e : '+e)res.json({status:500,message:'サーバエラー\n'+next,})})})

Tokenを保存しているDB情報

CREATETABLE`push_token`(`id`int(11)unsignedNOTNULLAUTO_INCREMENT,`push_token`varchar(255)DEFAULTNULL,PRIMARYKEY(`id`),UNIQUEKEY`push_token`(`push_token`))ENGINE=InnoDBAUTO_INCREMENT=1DEFAULTCHARSET=utf8;

サーバの設定ファイルを記述しているJSONファイル

{"sql":{"host":"localhost","user":"hoge","password":"hoge","port":8889,"database":"fuga","timezone":"jst"},"server":{"port":3003}}

スクワットしないとジェイソン・ステイサムに撃たれるLINE bot ~SQUAT or DIE~

$
0
0

Qiitaで「ジェイソン・ステイサム」というタグを密かに育んでいるたわちゃんです。
もちろん、今回も愛しのステイサムたんがテーマ!
ぜひ、最後までご覧ください♪

今回のステイサム作品

自粛により13キロも太ってしまった私。
空いた時間にスクワットしたいけどヤル気が出ないので、スクワットしないとステイサムに殺●れるLINE botを作りました。
その名も「SQUAT or DIE」です。

出来たもの

※キャプチャ撮る時LINE botの名前変えるの忘れてた・・・「SQUAT or DIE」です。
Image from Gyazo

基本、私からの問いかけには一切無視というドS設定ですが、スクワット表明をすると反応してくれます。

ステイサムたんの命令は絶対・・・!すぐにスクワット開始です。
ちなみにTシャツに反応した方は、そっとコメントください。

スクワット20回をやり切ると、ステイサムたんからご褒美をいただけます。

Image from Gyazo

逆に諦めると、撃たれます

Image from Gyazo

作り方

動画でもチラ見えしていますが、Obnizでスクワットの回数をカウントし、LINE Messaging APIを使ってLINE botと連携しています。ソースコードは記事の下部に貼ってるので、ここでは割愛しますね!

Obnizを跨いでスクワットし、超音波距離センサ(HC-SR04)でお股との距離を測り、50㎝以下になるとカウントするようにしました。
※ちなみに、超音波だからかお股だとなかなか反応してくれず、お股に手のひらをかざすとカウントしてくれました。笑

ちゃんとディスプレイの文字が見えるように、何度もスクワットしながら撮影したので筋肉痛になりました。

ソースコードと改善点

コチラ▶https://gist.github.com/twtjudy1128/05972d30e240979338476d3bc2eef82f

プロトアウトスタジオの先輩の記事
「onizで腹筋カウンター&line bot」https://qiita.com/karu/items/87e79eeb3c3a0892d00aを参考にさせていただきました!

ただ、自分でコード解読できないままお借りしたので、思い通りにカスタムできず、、、
while文の無限ループから抜け出せませんでした(´;ω;`)

<< 改善したい点 >>
▶ 回数もLINE BOTに表示させたい
▶ 20回スクワットしたら、自動的にステイサムから褒められたい
▶ 5分以内に20回スクワットしなかったら、自動的にステイサムに撃たれたい
▶ あと9キロ痩せたい

こう書き換えたらいいよ!とかアドバイスいただけると嬉しいです・・・

おまけ

実は!先日初めてハッカソンに参加しました!
そのテーマが「チーム制でObnizを楽しもう」だったのですが、チームで役割分担したら、一切Obnizを触ることなくハッカソンが終わっていました(笑)
(ハッカソンの様子はnoteにまとめてます▶https://note.com/tawata_judy/n/n7b5ac3b60e69 )

というわけで、自分でObniz使って何か作ってみよう!と思いチャレンジした次第です。
初めてObniz使った時も不完全燃焼だったのに、今回も中途半端になって悔しい~~~精進します!

参照▶【はじめてのIoT】サイリウムを自動的に光らせてみた【ラブライブ】
https://qiita.com/twtjudy1128/items/6df974ea12646665c73b

nodenvを使ってnode環境を作る

$
0
0

はじめに

ちょっと仕事で AWS Lamdbaを使うことになりそうなので、いまさらながらお勉強。
WSL2のUbuntuに開発環境を作って、試してみようと思います。

環境

Windows 10
WSL2
Ubuntu 20.04 LTS

nodenvをインストールする

git clone で必要なファイルを取得します。

git clone git://github.com/nodenv/nodenv.git ~/.nodenv
git clone git://github.com/nodenv/node-build.git ~/.nodenv/plugins/node-build

nodenvにパスを通します。

echo'export PATH="$HOME/.nodenv/bin:$PATH"'>> ~/.profile
echo'eval "$(nodenv init -)"'>> ~/.profile
source ~/.profile

Node.jsをインストールする

インストール可能なバージョン一覧を取得し、表示されたバージョンを指定してインストール。
ここでは最新のLTSを選択

nodenv install--list
nodenv install 12.18.3

利用するNode.js のバージョンを指定する
localを指定することで、コマンド実行した配下のディレクトリで、該当バージョンを利用することができます。

nodenv local 12.18.3

最後にバージョン確認。指定したバージョンが表示されればOK

node -v

さいごに

これで、準備はできたので、次はServerlessFrameworkだ。

息子の可愛さを普及するために、AWS + LINEでBotを作った話

$
0
0

2020年7月、我が家に長男が誕生。
もう天使。かわいい。CMのオファー来るんじゃないのか?(親バカ)

親族・友人に息子を会わせて、可愛さを自慢やりたかったが、このご時世それも叶わず。。。
我が息子の可愛さを普及したい。どうしよう。

そうだ。我が息子の可愛さを普及するLINE Botを作ろう。

1. デモ

最初にご紹介。(かわいい)
demo.gif

2. 全体構成

Design.png

2-1. LINEBotからWebHookでAPIGateway→Lambda実行
2-2. メッセージを解析して、返信用のメッセージと画像を取得
2-3. LINEに返信

とシンプルなもの。
GASとかで構築した方が安い。というのは秘密。

3. LINE①

まずはLINEBot MessagingAPIの設定。
下記サイトを参考に設定。
1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 #nodefest

Webhook URLはAPI構築後に設定。

4. AWS

Lambda + DynamoDBはCloudFormationで、APIGateway + S3は手動で構築。

4-1. CloudFormation

template.yml
AWSTemplateFormatVersion:2010-09-09Resources:HaruBotFunction:Type:AWS::Lambda::FunctionProperties:Code:./release/app.zipFunctionName:HaruBotFunctionHandler:index.handlerRuntime:nodejs12.xRole:Fn::GetAtt:- "HaruBotRole"- "Arn"MemorySize:128Timeout:30Environment:Variables:TZ:Asia/TokyoACCESSTOKEN:<LINE ACCESSTOKEN>CHANNELSECRET:<LINE CHANNELSECRET>ReplyMapping:Type:AWS::DynamoDB::TableProperties:TableName:ReplyMappingAttributeDefinitions:-AttributeName:typeAttributeType:SKeySchema:-AttributeName:typeKeyType:HASHProvisionedThroughput:ReadCapacityUnits:3WriteCapacityUnits:3HaruBotRole:Type:"AWS::IAM::Role"Properties:AssumeRolePolicyDocument:Version:"2012-10-17"Statement:-Effect:AllowPrincipal:Service:-"edgelambda.amazonaws.com"-"lambda.amazonaws.com"-"dynamodb.amazonaws.com"-"cloudwatch.amazonaws.com"Action:-sts:AssumeRole
  • ACCESSTOKEN, CHANNELSECRETはLINE Bot設定時に発行した値を設定。
  • ReadCapacityUnits, WriteCapacityUnitsは適当に。一応複数人に公開することを考慮して3。
  • Roleは最低限の権限のみ付与。

4-2. DynamoDB

4-2-1. テーブルデザイン

Key説明
typeStringPK
imgList画像URLのリスト、今回はS3上に静的WebホスティングしたURLを設定
msgList返信メッセージのリスト

4-2-2. サンプル

{"img":["https://hogehoge.com/oyasumi01.jpewg","https://hogehoge.com/oyasumi02.jpewg"],"msg":["おやすみなちゃい","Zzzz..."],"type":"おやすみ"}

4-3. Lambda

4-3-1. ソース全文

index.js
'use strict'constline=require('@line/bot-sdk')constclient=newline.Client({channelAccessToken:process.env.ACCESSTOKEN})constcrypto=require('crypto')constAWS=require('aws-sdk')constdynamodb=newAWS.DynamoDB.DocumentClient({region:'ap-northeast-1'})exports.handler=async(event)=>{returnnewPromise(async(resolve,reject)=>{constsignature=crypto.createHmac('sha256',process.env.CHANNELSECRET).update(event.body).digest('base64')constcheckHeader=(event.headers||{})['X-Line-Signature']if(signature!==checkHeader){reject('Authentication error')}constbody=JSON.parse(event.body)constevents=body.events[0]constmessage=events.message.textconstparam={TableName:'ReplyMapping',Key:{type:message}}constresult=awaitdynamodb.get(param).promise()letmsg,imgconsole.log(result.Item)if(result.Item){constgetRandomList=(list)=>list[Math.floor(Math.random()*list.length)]msg=getRandomList(result.Item.msg)img=getRandomList(result.Item.img)}else{msg=`${message}ってなんでちゅか?`img=''}constreplyText={type:'text',text:msg}constreplyImage={type:'image',originalContentUrl:img,previewImageUrl:img}client.replyMessage(events.replyToken,replyText).then((r)=>{returnclient.pushMessage(events.source.userId,replyImage)}).then((r)=>{resolve({statusCode:200,headers:{'X-Line-Status':'OK'},body:'{"result":"completed"}'})}).catch(reject)})}

4-3-2. 認証処理

constsignature=crypto.createHmac('sha256',process.env.CHANNELSECRET).update(event.body).digest('base64')constcheckHeader=(event.headers||{})['X-Line-Signature']if(signature!==checkHeader){reject('Authentication error')}

LINEからハッシュ化されている値と突合して、正しいリクエストかどうかハンドリング。

4-3-3. 返信用のメッセージ、画像を取得

constbody=JSON.parse(event.body)constevents=body.events[0]constmessage=events.message.textconstparam={TableName:'ReplyMapping',Key:{type:message}}constresult=awaitdynamodb.get(param).promise()letmsg,imgif(result.Item){constgetRandomList=(list)=>list[Math.floor(Math.random()*list.length)]msg=getRandomList(result.Item.msg)img=getRandomList(result.Item.img)}else{msg=`${message}ってなんでちゅか?`img=''}

送信されたメッセージを元に、DynamoDBからレコード取得。
※ ユーザーからの送信テキストををKeyに完全一致でレコードを取得しているため、良さげなワードから良さげに引っ張ってくることはできない。
例えば、「かわいい」のみレコードを登録していた場合、「かわいいね」とメッセージが送られてきても、良さげな返信はされない。
形態素解析して、良さげな言葉を引っ張ってきたかったが、時間が足りず。。(お宮参りに間に合わせたかったんだもん。)

レコードが存在する場合は、レコード内のimg, msgからランダムに値を取得。
存在しない場合はデフォルトを返却。

4-3-4. 返信

constreplyText={type:'text',text:msg}constreplyImage={type:'image',originalContentUrl:img,previewImageUrl:img}client.replyMessage(events.replyToken,replyText).then((r)=>{returnclient.pushMessage(events.source.userId,replyImage)}).then((r)=>{resolve({statusCode:200,headers:{'X-Line-Status':'OK'},body:'{"result":"completed"}'})}).catch(reject)

詳しいことはドキュメントを参考に。

4-4. APIGateway

RestAPIで作成。
公開するAPIではないので、特にカスタムドメイン名の設定はしない。

4-4-1. APIGateway > API作成押下

01.png

4-4-2. REST API > 構築

02.png

4-4-3. API名入力 > APIの作成

任意の文字列を入力する。
03.png

4-4-4. メソッドの作成 > post選択

04.png
05.png

4-4-5. Lambda関数選択 > 保存

Lambda関数はCloudFormationmで構築したLambda関数を定義。
今回は HaruBotFunction
06.png

権限付与ダイアログは脳死でOK
07.png

4-4-6. メソッドリクエスト > HTTPリクエストヘッダー追加

08.png

設定する値。

名前必須キャッシュ
X-Line-SignatureTF

09.png

4-4-7. APIのデプロイ > URLコピー

10.png
ステージ名は任意の文字列を入力。
11.png
枠内のURLを控える。
12.png

5. LINE②

4-4-7. でコピーしたURLを、LINE Developers > Messaging API設定 > Webhook設定 のWebhook URLに登録。
スクリーンショット 2020-08-12 22.02.54.png

6. 完成

これで完成。
DynamoDBに会話用のレコードを登録し、CDNに画像をアップロードすればデモのように動かせることができる。

7. まとめ

7-1. 残念なロジック

今回は、息子に直接会えない親族や、友人に少しでも息子に触れ合ってもらえるようにBotを構築。
お宮参り後に公開したくてちょっと無理やりな構成になってしまったのは残念。
特に、形態素解析して、ワードをピックアップするロジックを組みたかったけど、うまくいかなかったため、残念なロジックに・・・
ここは改善したい。

ゆくゆくは、メンテナンス不要で、いい感じに更新されていくような構築ができたら完璧。

7-2. CDNをS3にする必要は..

家族アルバムアプリのみてねっていい感じのAPIないかなぁ?
日時指定すると、いい感じの画像を返却してくれるAPIが欲しい。笑
もしあれば課金しますわ。

というか、Instagramでもいいかなぁ。(怒られる恐れあり?)


npmでローカルにインストールしたコマンドを実行する

$
0
0

コマンドは./node_modules/.binに集められています。下記のようにパスを指定して実行してください。

% ./node_modules/.bin/jest

チュートリアルのサンプルコードを実行しようとして、コマンドが存在しないエラーになりました。

% jest my-test --notify --config=config.json
zsh: command not found: jest

npm token createの結果をjsonで取得する

$
0
0

TL; DR

npm token create --json

経緯

記事のタイトルとは関係ないけど、Node.jsのプログラム中からnpmアカウントのAuth Tokenを生成する方法で困ってた。

https://docs.npmjs.com/creating-and-viewing-authentication-tokens

ここにあるnpm token create以外にAPIが見つからないけど、npm token createはCLI上でインタラクティブにパスワードの入力を求めてくる。

これについては下記の方法で可能だということがわかった。
意外とお手軽で良かった。

main.js
constchild=require('child_process')child.spawn("npm",["token","create"],{stdio:'inherit'})

ということで実行してみたところ、パスワードも問題なく親プロセスから対話的に入力でき、トークンが生成できた。(トークン部分は隠してあります)

node main.js

npm password: 
┌────────────────┬──────────────────────────────────────┐
│ token          │ xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx │
├────────────────┼──────────────────────────────────────┤
│ cidr_whitelist │                                      │
├────────────────┼──────────────────────────────────────┤
│ readonly       │ false                                │
├────────────────┼──────────────────────────────────────┤
│ created        │ 2020-08-13T07:53:39.394Z             │
└────────────────┴──────────────────────────────────────┘

しかし実際にはこのトークンをは次の処理への入力にする必要があり、(これパースするのか・・・面倒だな・・・)と思って、ダメ元で--jsonオプションを渡してみたらJSONで取得できた。
感謝感謝。

main.js
constchild=require('child_process')child.spawn("npm",["token","create","--json"],{stdio:'inherit'})
node main.js 

npm password: 
{"token":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","cidr_whitelist":[],"readonly":false,"created":"2020-08-13T08:04:16.531Z"}

これならあとはstdoutへの出力を親プロセスで受け取るだけなのでいけそう。

【node.js】ルーティング設定ホーム画面表示させる。

$
0
0

【ゴール】

node.jsを使用して、対象のviewを表示させる。

【メリット】

■node.jsの理解度向上
■JavaScriptの理解度向上

【開発環境】

■ Mac OS catalina
■ Homebrew 2.4.9
■ mysql Ver 8.0.21

【実装】

作業環境作成

*nodebrewをPC内にインストールしてください
*npm をPC内にインストールしてください。

mac.terminal
$ mkdir js
$ cd js
$ npm init -y
$ npm install express
$ npm install ejs
$ touch server.js
$ touch app.ejs

ルーティング作成

server.js
// for using expressconstexpress=require('express');constapp=express();// for path of viewfunctionviews(){app.set('views','views'),app.set('view engine','ejs')}// for routingapp.get('/',(req,res)=>{views();res.render('app');})// for using 3000 port app.listen(3000,(req,res)=>{console.log('success');})

view作成

テンプレートエンジンは「ejs」なので、HTMLの宣言は不要です。

app.ejs
<h2>成功</h2>

確認

*サーバー立ち上げ。

mac.terminal
$ node server.js
success

以上

【合わせて読みたい】

■ 【node.js】 node.jsインストール 芋っていたけど、簡単だった件...
https://qiita.com/tanaka-yu3/items/739db5ffed24a8d9ae4b

■【HOMEBREW】 Mac OSのパッケージマネージャーについて node.jsやってたら学んだ事
https://qiita.com/tanaka-yu3/items/65dac47443cc08914a86

■ 【comandLine】 一言で コマンドライン 各種コマンド ターミナル
https://qiita.com/tanaka-yu3/items/b32e353bd6d7c9ebd4fb

JavaScriptのイベントループを理解する

$
0
0

イベントループとは?

JavaScriptはシングルスレッドです。一度に実行できるタスクは1つだけです。つまり、

  • 2つ以上の処理を並行して実行できない
  • 2つ以上の関数を同時実行できない

ということになります。

例えば、10秒掛かるタスクを実行すると、他のタスクは10秒間待機しなければなりません。
JavaScriptはデフォルトでブラウザのメインスレッドで実行されるため、UI全体が動かなくなります。

では、イベントループについて解説していきます。
まず、V8などのJavaScriptエンジンやブラウザには、下記の画像の様にコールスタック(Call Stack)ヒープ(Heap)タスクキュー(Task Queue)Web APIと呼ばれる4つのメカニズムを備えています。

JavaScriptエンジン

まずは、このメカニズムを簡単に説明していきます。

Web API

Web APIにはDOM Event, setTimeout, Ajaxなどが含まれます。これらの機能は非同期(ノンブロッキング)に実行されます。
ブラウザが提供する機能です。

ヒープ(Heap)

動的に確保と解放を繰り返せるメモリ領域です。
オブジェクトはヒープに割り当てられています。
JavaScriptエンジンの内部に実装されています。

コールスタック(Call Stack)

関数は呼び出されるとコールスタックに追加されます。
コールスタックはLIFO(後入れ先出し)で機能します。
JavaScriptエンジンの内部に実装されています。

タスクキュー(Task Queue)

コールバック関数はタスクキューで待機します。
タスクキューはFIFO(先入れ先出し)の配列で、イベントループは、コールスタックが空になる度に、タスクキューからコールバック関数を取り出して実行します。
JavaScriptエンジンの外部に実装されています。

MDNでは、なぜ「ループ」という名前が付いたか、下記の様な仮想コードで説明しています。

while(queue.waitForMessage()){queue.processNextMessage();}

上記のwaitForMessage()は、現在実行中のタスクが存在しない場合、次のタスクがタスクキューに追加されるまで待機します。このようにイベントループは、「現在実行中のタスクがないこと」と「タスクキューにタスクがあるか」を繰り返し確認します。簡単にまとめると次のようになります。

  • すべての非同期APIは作業完了後、コールバック関数をタスクキューに追加する。
  • イベントループは、現在実行中のタスクがない(コールスタックが空になった)場合、FIFOでタスクキューから取り出して実行する。
  • 現在実行中のコールタスクがある(コールスタックに関数がある)場合、LIFOでコールスタックから取り出して実行する。

これらがイベントループの簡単な説明になります。
では、このメカニズムを実際のコードを踏まえて理解していきましょう。

イベントループをコードで理解する

プログラム1

まずは簡単に下記のコードの実行結果を考えてみましょう。

constfoo=()=>console.log("First");constbar=()=>setTimeout(()=>console.log("Second"),1000);constbaz=()=>console.log("Third");foo();bar();baz();

実際に実行してみましょう。実行結果は下記の様になったと思います。

"First""Third""Second"

このプログラムの流れとしては

  1. fooがコールスタックに追加されます。そして、"First"を返し、コールスタックからポップされます。
  2. barがコールスタックに追加されます。
  3. コールバック関数の() => console.log("Second")がWeb APIに追加され、1000ms待機します。
  4. その瞬間setTimeoutはコールスタックからポップされ、値を返します。
  5. 1000ms待機している間に、bazがコールスタックに追加さます。そして、"Third"を返し、コールスタックからポップされます。
  6. 1000ms後、() => console.log("Second")は直ぐにコールスタックに追加されるのではなく、タスクキューに渡されます。
  7. そして、イベントループで、コールスタックが空なことを確認し、タスクキューにある() => console.log("Second")がコールスタックに渡されます。
  8. () => console.log("Second")"Second"を返し、コールスタックからポップされ、プログラムは終了します。

となります。視覚的に理解したい方は、こちらで上記のプログラムを実行してみると面白いと思います。
では、次のプログラムにいきましょう。少し難易度が上がります。

プログラム2

下記のプログラムを実行し、ボタンをクリックしてみましょう。

<!DOCTYPE html><head><title>event loop</title></head><body><buttonid="heavyCount">click</button><divid="counter">0</div><script>constbutton=document.getElementById('heavyCount');constcounter=document.getElementById('counter');button.addEventListener('click',function(){letcount=0;lettimes=1000;functionloop(){if(count++<times){counter.innerHTML=count;loop();}else{alert("Done");}}loop();});</script></body></html>

恐らく、アラートが表示された後、下記の様にページ内の0が1000に変化したと思います。

a6cb49d5b20cc69f661d337d8b57cf47.gif

では、このプログラムを下記の様に動かしたいときはどうでしょう。ソースコードを少し修正してあげるだけで、この動きは実現できます。

26ad84952b606021e1665555cb5dcfff.gif

その前に、イベントループにおける、最初の動きの流れを追っていきたいと思います。

  1. まず、addEventListenerをコールスタックに追加。
  2. addEventListenerのコールバック関数をWebAPIに追加。
  3. ボタンをクリックすると、loopがコールスタックに追加されます。
  4. countが++されます。
  5. counter.innerHTMLがタスクキューに追加されます。
  6. 次に、loopの中で更にloopを再帰的に呼び出しています。
  7. loopがコールスタックに追加されます。
  8. countが++されます。
  9. counter.innerHTMLがタスクキューに追加されます。
  10. 次に、loopの中で更にloopを呼び出します。
    …という風に、今回のプログラムでは、コールスタックにcountが1000になるまで、つまり、1000個のloopがコールスタックに追加されます。
  11. そして、countが1000になったところで、else内のalert("Done")が実行されます。
  12. コールスタックが空になったところでタスクキューで待機しているcounter.innerHTML達を実行していきます。
  13. 最後に1000が表示されてプログラムは終了します。

プログラム2-2の解答

では、プログラム2-2の解答です。

// ...省略functionloop(){if(count++<times){counter.innerHTML=count;setTimeout(loop,0);// setTimeoutを追加}else{alert("Done");}}

setTimeoutのコールバックとしてloopを渡していますね。
では、何故これだけで上記の動きが実現できるのでしょうか。

今までは、コールスタックにloopがどんどん追加されていき、その間にinnerHTMLがタスクキューにどんどん追加されていきました。
これは、タスクにあるloopを全て処理仕切ったとき、つまり、countが1000になった後、タスクキューで待機していたinnerHTMLでレンダリング処理をするという流れになります。ここはさっき説明したので、問題ないと思います。

しかし、再帰呼び出しでsetTimeoutを挟むことによってloopはコールスタックではなく、WEB APIを経由した後、タスクキューに追加されていきます。
つまり、タスクキューには、innetHTMLloopinnetHTMLloop→ ... という風に、追加されていきます。では、この部分の処理の流れを追っていきましょう。

  1. まず、innerHTMLが実行されます。countは1なので、1が画面にレンダリングされます。
  2. loopをコールスタックに追加します。countを++します。
  3. コールスタックが空になりましたのでタスクキューで待機しているinnerHTMLを実行します。countは2なので、2が画面にレンダリングされます。
  4. これをcountが1000になるまで実行します。

という風に、setTimeoutを使用することで、loopの間にinnerHTMLによるレンダリング処理を追加することができます。これで、2枚目の動きが実現できる訳ですね。

スタックオーバーフロー

このコールスタックは、無限に関数を積み重ねることはできません。何事にも限界はあります。コールスタックの許容量を超えてしまうと、スタックオーバーフロー(StackOverflow)というエラーが発生します。これは関数の再帰的な実行を行うときによく出てきます。

今回話せなかったこと

  • マイクロタスク(micro task)
  • ウェブワーカー(Web Worker)
  • setTimeoutの誤差

この3つもイベントループに関係してきますので、気になる方は勉強してみると面白いですよ。
僕も機会があればまた記事を書こうと思います。

参考文献

Node.jsのインストールからReactNative+Expo+Typescript環境を構築しようね(2020/08/13 LTS対応)

$
0
0

初学者との開発プロジェクト始動!

初学者との開発プロジェクトを始めるにあたって
手順書をざっくり作成したのでここに書き留めます。

概要

  • Node.jsインスト―ル
  • Expoインスト―ル
  • ReactNative+Typescriptでプロジェクト作成

バージョン(記事作成時LTS)

-Version
Node.js12.18.3
npm6.14.6
expo3.24.0

Node.js

①最新Nodeのインストーラをダウンロード
https://nodejs.org/ja/download/releases/

②実行
node.jsがインストールされているのでアプリ実行
→真っ黒の画面が出たらOK(以下でnodeと呼びます)

③確認
nodeにて「node --version」と入力してEnter
→v12.18.3と出力されたらOK

次にExpo!!

▼PC

①インストール
nodeにて「npm install -g expo-cli」と入力してEnter
→Errorが出なければOK

②確認
nodeにて「expo --version」と入力してEnter
→3.24.0と出力されたらOK

▼スマホ

①アプリ
「Expo Client」をインストールしておく
image.png

最後にプロジェクト作成!

①開発用フォルダ作成
適当な空フォルダを事前に作成

②開発用フォルダに移動
nodeにて「cd ○○○」と入力してEnter
 ※○○○には①で作成したフォルダへのパスを指定

③プロジェクト作成
nodeにて「expo init ○○○」と入力してEnter
 ※○○○には作成したいプロジェクト名を指定
 ※以下templateにてblank(TypeScript)を指定
 image.png

④確認
nodeにて「expo start」を入力してEnter
→QRコードが表示されるのでスマホで読み取る
→「Open up App.tsx to start working on your app!」と表示された白い画面が出れば完了!お疲れ様でした!

参考URL

https://nodejs.org/ja/download/
https://tech.fusic.co.jp/posts/2019-10-30-react-native-expo-typescript-native-base/
https://qiita.com/jeq/items/f16594ec99d675bed300
https://stackoverflow.com/questions/52476154/uninstalling-expo-cli

`npm token create --json`をchild_processで実行しつつ、結果のトークンはコンソールに表示しない方法

$
0
0

npm token createをNodeJSのプログラム中から呼びたくて、

execだとプロセスが終わるまで帰ってこないので、対話的なプログラムには向かない

帰ってこない
constexec=child.exec("npm token create --json",(err,stdout,stderr)=>{console.info({err,stdout,stderr})})

非同期処理を書きたくないのでspawnSyncを使おうとした。

やりたいことは

  1. パスワードの入力を求めるメッセージはコンソールに表示したい
  2. ユーザーが入力するパスワードはコンソールに表示したくない
  3. 最終結果は(秘密のトークンを含むので)コンソールに表示したくない

である。
とりあえず

constchild=require('child_process')constoptions={encoding:"utf-8",stdio:"inherit"}constresult=child.spawnSync("npm",["token","create","--json"],options);console.info("result",result)

こうすると、1と2はクリアできるけど3がだめ。結果が普通に表示される。(そりゃそうだ)

じゃあこういうことでしょ?

constchild=require('child_process')const{Writable}=require('stream')classHookextendsWritable{_write(chunk,encoding,callback){console.log("chunk",chunk.toString())callback()}}consthook=newHook();hook.fd=1// これがないとspawnに渡せないconstoptions={encoding:"utf-8",stdio:["inherit",hook,"inherit"]}constresult=child.spawnSync("npm",["token","create","--json"],options)console.info("result",result)

と思ってやってみたが、挙動は変わらない。hook._writeが呼ばれていない。
ちなみにhook.fdの値をいくつか変えて試してみたが、コンソールに表示されなくなったりnpm ERR! code EPIPEが出たりする。

調べていると、spawnはカスタムストリームを受け取れない(バグ)という情報があった。
https://stackoverflow.com/questions/34967278/nodejs-child-process-spawn-custom-stdio
https://github.com/nodejs/node-v0.x-archive/issues/4030

これにならってこうすると、

constchild=require('child_process')constresult={};const{Writable}=require('stream')classHookextendsWritable{_write(chunk,encoding,callback){conststr=chunk.toString()try{result=JSON.parse(str)}catch{console.log(str)}callback()}}consthook=newHook();constoptions={stdio:["inherit","pipe","inherit"]}constprocess=child.spawn("npm",["token","create","--json"],options)process.stdout.pipe(hook)process.on("close",()=>{console.info("result",result)})

1と3はクリアできたが2がダメ。
1と3についても、渡ってきたデータがJSON.parseを通るかどうかで分岐させているのでどうもすっきりしない。

ここにあるような、process.stdout.writeを一時的に上書きするアプローチもだめだった。
上書きしたwriteが呼ばれてなさそうな挙動。

https://stackoverflow.com/questions/26675055/nodejs-parse-process-stdout-to-a-variable
https://gist.github.com/pguillory/729616

結局、stdinもstdoutもpipeしてしまって、状況をひとつひとつハンドリングするこのようなコードになってしまった。
1も2も3もクリアできはしたけど、ぜんぜん納得いってない。

constchild=require('child_process');// stdinとstdoutはユーザーコードで処理する。stderrは親プロセスに流すconstoptions={stdio:['pipe','pipe','inherit']}constproc=child.spawn("npm",["token","create","--json"],options);// デフォルトは`Buffer`(バイト列)なのでutf-8を指定proc.stdout.setEncoding('utf-8')// パスワード入力を受け付けるためにprompt-syncを使うconstprompt=require('prompt-sync')({sigint:true})letresult={};proc.stdout.on('data',(data)=>{try{// JSONでパースしてみるresult=JSON.parse(data)// できたら結果が出たということなので子プロセスを終了してよいproc.kill()}// パースできなかったらこちらへcatch(e){// パスワード入力を求められてたらif(data==="npm password: "){// prompt.hideで入力受け付けconstanswer=prompt.hide(data)// 入力された文字列をproc.stdinに渡す// 改行コードを送らないと向こうで処理を始めてくれないproc.stdin.write(answer+"\n")}}});proc.stdout.on('end',()=>{console.info("result",result)});
node main.js

npm password: 
result {
  token: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
  cidr_whitelist: [],
  readonly: false,
  created: '2020-08-14T06:03:21.551Z'
}

そういえば、stdoutをpipeしているのに、npm password:がコンソールに表示されるのはなんでだ・・・?

https://github.com/npm/cli/blob/latest/lib/token.js#L210
https://github.com/npm/cli/blob/latest/lib/utils/read-user-info.js#L41
https://github.com/npm/read/blob/master/lib/read.js#L19

こう読み進めていくと、結局process.stdoutを使っていそうなのだが、child_process内でのprocess.stdoutへの出力がpipeされるのではないのか・・・?

ちょっとよくわからないので放置しとく・・・。

【Alexa】新機能 hostedスキルで作成する

$
0
0

はじめに

2020年7月頃よりβ版だったAlexa-hostedスキルが正式公開となりました。※なったはず。
ここでは新しく実装されたAlexa-hostedスキルを使ってスキルを作っていきます。

Amazon開発者ポータルを使用するためにAmazonデベロッパーアカウントが必要です。
あらかじめ環境を整えてから読んでください。

Alexa-hostedスキル以前の方法

Alexa-hostedスキルが正式に公開されるまではAlexaとのインターフェイスはAlexaスキル、そのプログラムの実装はAWSにて行われていました。

手段コンソールアカウント
Alexaにスキルを用意するAmazon開発者ポータルAmazonデベロッパー
Alexaにプログラムを用意するAWSコンソールAWSアカウント

そのためAmazon開発者ポータルAWSコンソールを行き来して開発する必要があります。
そしてAmazonデベロッパーアカウントのほかにAWSアカウントも必要になります。

さらにこの2つのサーバー?でデータをやりとりするためのインターフェイスを作る必要があります。

データの方向必要な情報
Alexaスキル→AWSAmazon開発者ポータルにて取得するスキルID
AWS→AlexaスキルAWSのLambdaにて取得するARN

現状ではこの方法でないと出来ない事もあるのですが、ちょっとAlexaのスキルを作ってみたいという人には壁が高すぎます。

Alexa-hostedスキルを使う

Alexa-hostedスキルを使ってスキルを作ると簡単にスキルを作ることができますが、そのための準備が必要なのでは結局ハードルが高くなっていまいます。

Alexa-hostedスキルはAmzaon開発者ポータルでスキルを作成すると自動的に使えるようになっています!!

早速使ってみましょう。

Amazon開発者ポータル

Amazon開発者ポータルからAlexa SkillsKit を選択して Alexa Developer consle を開きます。
今後このページを頻繁に開くのでブックマークにしておきましょう。

Alexa Developer consle

ページを開くと下記のような画面が表示されます。
console.png

書籍やネットの情報と見比べるとわかりますが上部のメニューに「コードエディタ」と表示されていますが、これがAlexa-hostedスキルを使ったやり方となるページです。

後の操作説明にも出てくると思いますが、このやり方にAWSが全く関係しないのではなく、Alexa Developer consleにてコードを記述した後デプロイという機能を利用してコードがAWSに送られています。
AWSでのソースコード記述をAlexa Developer consleから送信することでリモートで行っているようなイメージになります。

AWSのアカウントがなくてもAlexa Developer consleと紐付けされたプライベートアカウントとして動作するのでAWSアカウントがなくても動作するようです。本来のAWSアカウントではないのでいくつか出来ないことも存在します。

スキルを作成する

スキル一覧からスキル作成を選択します。
skillmake.png

スキル名を入力します。スキル名=スキル呼び出し名ではありませんが、呼び出し名の初期値はスキル名になります。スキル呼び出し名とは「Alexa xxx」の xxx部分になります。

下の方にスクロールすると
skillmake3.png

作るスキルは「カスタム」そして「Alexa-Hosted(Node.jp)」が選択されています。Alexa-hostedスキルとしてNode.jpを使うという意味になります。

これまでのようにAlexa-hostedスキルを使わない場合は「ユーザー定義のプロビジョニング」を使います。

skillmake4.png

HelloWorldをテンプレートとして使用します。

skillmake5.png

スキル作成には1分かかります。サーバー側の処理のためユーザー環境で速度は変わらないものと思われます。

スキルメニューから呼び出し名を確認します。

skillmake6.png

次にインテントを確認します。

インテントとは

「Alexa xxx で yyy して」
というときに xxx がスキル呼び出し名で yyy がインテントになります。

skillmake7.png

テンプレートを使ったのでインテント名が自動的に作られています。

対話するプログラムを作るときに様々な言い回しがプログラムを複雑にします。
たとえば「おはよう」「こんにちは」「こんばんは」と挨拶がありますが
これをプログラムで直接比較しようとすると

sample.v
if(say=='おはよう'||say=='こんにちは'||say=='こんばんは'){処理}

のように書く必要がありますが曖昧な言い回しが増えるたびにプログラムを変更していくと効率が悪くなります。
そのためインテントを使用して言い回しをここで吸収するようになっています。
言い回しをまとめるグループ名がインテント、その中の1つ1つの要素が発話となります。

インテント名発話
helloおはよう こんにちは こんばんは
eatみかん リンゴ ステーキ 寿司

では実際にインテントと発話の関係を見てみましょう
HelloWorldIntentが用意されていますのでこれをクリックして設定を見てみましょう。

skillmake8.png

さすがにテンプレートは日本語になっていません。手動で日本語にしましょう。

skillmake9.png

この設定方法、毎回行うのは手間ですね。左側のメニューでJSONエディターがあるので見てみましょう。

sample.json
{"interactionModel":{"languageModel":{"invocationName":"ノードテスト","intents":[{"name":"AMAZON.CancelIntent","samples":[]},{"name":"AMAZON.HelpIntent","samples":[]},{"name":"AMAZON.StopIntent","samples":[]},{"name":"HelloWorldIntent","slots":[],"samples":["おはよう","こんにちは","こんばんは"]},{"name":"AMAZON.NavigateHomeIntent","samples":[]}],"types":[]}}}

今まで設定した内容がそのまま反映されていることがわかります。つまりこのJSONを保存しておけば、ほかのスキルを作ったときにインテントを使い回すことができます。

AMAZON.CancelIntentやAMAZON.StopIntent、AMAZON.HelpIntent、AMAZON.NavigateHomeIntentは必須のインテントですが発音はテンプレートに無いようです。

この後コードエディタから保存、デプロイと操作して上部のメニューから「テスト」を選んでいくとAlexaエミュレータからテストを行うことが出来ます。
テストをする前に「非公開」から「開発中」に変更する必要があります。
その後テキスト入力欄に

「ノードテストを開く」

など入力すると まだ設定していないので英語ですが返事が返ってきます。
エミュレータからテストする場合は最初にAlexaを呼ぶ名称がなくても大丈夫です。

実機テスト

Alexaを持っている人ならテストしたいと思うのが当たり前ですが・・・なぜか説明がありません。
それもそのはずです、テストが問題なく行えたのであれば、そのままAlexaを呼んでスキルを実行すれば良いわけです。

うーん、まるでVisualBasicを実行したら実はexeファイルも出来てました!ぐらいの感動ですね。


node.jsを使ってみる

$
0
0

node.jsをインストールしてみる。
参考:https://www.sejuku.net/blog/82322

1. ダウンロード

実行してみる。

% node --version
v12.18.3

2. Hello, world!

hello.js
console.log('Hello, world!')
% node hello.js
Hello, world!

と、無事実行できた。
参考:https://qiita.com/loremipsumjp/items/3d32a44fe80c9a2febbe

3. npmを使い、expressをインストールしてみる

参考:https://qiita.com/tarotaro1129/items/e02fbb911dc4af412ad0
npmとは、パッケージ管理システム。gemみたいなもの。
expressは、node.js版の簡易なWebサーバ。WEBrickみたいなもの。

% mkdir myapp
% cd myapp
% npm init
  • ここで、10回ほどリターンを押す。package.jsonが作られる。
package name: (myapp) 
version: (1.0.0) 
description: 
entry point: (index.js) 
test command: 
git repository: 
keywords: 
author: 
license: (ISC) 
About to write to /Users/eto/dev/Day17_node/myapp/package.json:
package.json
{"name":"myapp","version":"1.0.0","description":"","main":"index.js","scripts":{"test":"echo \"Error: no test specified\"&& exit 1"},"author":"","license":"ISC"}
% npm install express --save
- package-lock.jsonが生成される。
  • app.jsというファイルを作る。
app.js
constexpress=require('express')constapp=express()app.get('/',(req,res)=>{res.send('Hello World!')})app.listen(8000,()=>console.log('Example app listening on port 8000!'))

起動してみる。

% node app.js
Example app listening on port 8000!
Hello World!

と表示されていたら、成功。

done!

プロ野球選手のリアルタイム成績を返すLINE botを作った(LINE bot+heroku)

$
0
0

概要

現役プロ野球931名(2020/8/14現在)のプロフィール&今年度成績を教えてくれるLINE botを作ったという話。

経緯

自分はプロ野球が好きです。

野球を見てると、自分や相手チームの選手の成績や出身高校が知りたくなる時がありました。
ただ、気になった選手の情報を欲しいときにすぐに入手するのは意外に難しいです。

  • 選手名鑑の本だと、前年度成績しか載ってない…
  • 速報アプリだと、調べたい選手の情報にたどり着くのに時間がかかったり、欲しい情報に対して情報過多だったりする…
  • チームと背番号しかわからない選手だと、調べること自体が難しい…

そんな中、1年ほど前にBリーグの選手情報を返すLINE Botを作った の記事を拝見しました。

  • 普段から使っているLINEが選手名鑑になる! 本を取り出さなくてもいい!
  • 出てくる情報がシンプルで、欲しい情報が一目瞭然!
  • 選手名が分からなくても、チーム名と背番号だけで調べられる!(これが一番うれしいかも)

こんなツールがプロ野球にもあったらいいな と思ったのが開発経緯です!

プロ野球選手名鑑bot

色々試行錯誤して、こんなのできました!

image

使ってみたい方はこちらからご自由にどうぞ!
友だち追加
※ちなみに、botが誰と友達かとかは自分からは一切分からないので安心してご利用ください。

機能

以下がシステム構成図です。

npbmeikan

ざっくりいうと、以下の動作です。

  1. NPBウェブサイトから1日1回、現役プロ野球全選手データを取得してDBに格納
  2. LINE-botからWebhookリクエストがあったら、DBから選手データを引っ張ってLINEに表示

コードや機能詳細は、Github (suibari/NPBmeikan_bot) を参照ください!

ふりかえり

Keep

  • Promiseクラスを使った同期処理にTryできた
  • SQLを基本情報で勉強して以来使えた。手を動かすことでSQLインジェクションの攻撃原理と対策方法が理解できた
  • heroku postgresで人生初のDB構築できた
  • heroku schedulerを初めて使ってcronっぽいことができた
  • LINE flex-messageを使って、LINE上の見た目を工夫できた
  • 既存の異体字検索アルゴリズムを組み込めた

Problem

  • 機能分割的に綺麗じゃない
  • コードが汚い。Don't repeat yourself の原則を守りたい。例えば、request→cheerio→Xする の処理は何度も出てきてるので、Xを引数でコールバック関数にするとか
  • 野球に詳しくないと、数字を見ただけではどういう選手かは分からない。誰にでもわかりやすい情報を提供することはできていない

Try

  • 機能分割
  • リファクタリング。同じ処理を関数化・クラス化してまとめる
  • どういうタイプの選手なのか、成績から評価コメントを生成する? ランダムに生成できたらすごい楽しそう

まとめ

LINE bot楽しい!
特にflex messageで見せ方を変えられるのは楽しいです。今後も色々なbotに応用できるかも。

もしご意見ご質問、ここが詳しく知りたいなどありましたらぜひコメントください。

Node.jsのインストール

$
0
0

Node.jsのインストール

環境

OS: Windows10 Pro
Node.js: v12.18.3

手順

  1. Node.js公式サイトへアクセスして推奨版をDL
  2. DLしたmsiを実行
  3. コマンドプロンプトでバージョン確認

1.公式サイトへアクセス

https://nodejs.org/ja/へ移動して推奨版を選択します。
nodejs.org_ja_.png

2.DLしたmsiを実行

msi_bn.png

2-1.Node.jsのセットアップを開始

「Next」をクリックします。
node_1.png

2-2.ライセンスに同意

チェックを入れてから「Next」をクリックします。
node_2.png

2-3.インストール先フォルダの選択

インストール先を変更する場合はここで選択します。
node_3.png

2-4.セットアップのカスタム

機能をインストールする方法を選択します。
ツリーのアイコンをクリックして、機能をインストールする方法を変更します。
選択肢は主に下記があります。

  1. Will be installed on local hard drive
    ローカルハードドライブにインストールされます

  2. Entire feature will be installed on local hard drive
    機能全体がローカルハードドライブにインストールされます

  3. Will be installed to run from network
    ネットワークから実行するようにインストールされます

  4. Entire feature will be installed to run from network
    機能全体がネットワークから実行するようにインストールされます

  5. Feature will be installed when required
    機能は必要なときにインストールされます

  6. Entire feature will be unavailable
    機能全体が使用できなくなります

デフォルトでnpmも一緒にインストールされます。
そのまま次へ。
node_4.png

2-5.ネイティブモジュール用のNode.jsセットアップツール

一部のnpmモジュールは、インストール時にC / C ++からコンパイルする必要があります。
これらのモジュールをインストールできるようにするにはいくつかのツール
(PythonおよびVisual Studioビルドツール)をインストールする必要があります。

チェックをすると必要なツールを自動的にインストールします。
これによりChocolateyもインストールされることに注意してください。
インストールが完了すると、スクリプトが新しいウィンドウでポップアップします。

または、https://github.com/nodes/node-cyp#on-windowsの指示に従って、依存関係を自分でインストールします。

今回は何もせずそのまま「Next」をクリックします。
node_5.png

2-6.Node.jsのインストールの準備

特に修正する点が無ければそのままInstallボタンを押下します。
node_6.png

2-7.インストール中

node_7.png

2-8.インストール完了

「Finish」をクリックします。
node_8.png

3.バージョン確認

コマンドを叩いてバージョンの確認が出来たらインストールが出来ている状態です。

バージョン確認
node --version
結果
v12.18.3
バージョン確認
npm --version
結果
6.14.6

【Node.js mysql】mysql接続 データを取り出す

$
0
0

【ゴール】

mysql接続 データを取り出す

【開発環境】

■ Mac OS catalina
■ Homebrew 2.4.9
■ mysql Ver 8.0.21

【実装】

appを作成

homebrewのインストールが事前に必要です
mysqlのインストールが事前に必要です
*mysqlのコマンドも合わせて覚えれます

mac.terminal
// ディレクトリ作成

$ mkdir js
$ cd js
$ npm init -y
$ npm install express
$ npm install ejs
$ npm isntall mysql
$ touch server.js
$ touch app.ejs

// mysql でDATABASEを作成

$ mysql -u root -p
$ mysql> CREATE DATABASE JS;
$ use JS;
$ CREATE TABLE User (id int auto_incremet, name char(10));
$ INSERT INTO User value (1, tarou);

コーディング


■ npmのmysqlを読み込み。
■「createCOnnection」で({})内の任意のDBに接続


■ cosnt sql = データベースへの命令を定数へ
■「query」メソッドで、DBへ命令
■「if(err) throw err;」はエラーがあっても挙動させる
■「err, result」にDBからのデータが格納されています

server.js
constexpress=require('express');constapp=express();// ① 〜constmysql=require('mysql');constconnection=mysql.createConnection({host:'localhost',user:'root',password:'あなたのsqlのパスワード',database:'JS'});// ここまでfunctionviews(){app.set('views','views'),app.set('view enigine','ejs');}app.get('/',(req,res)=>{ // ② 〜constsql='select * from User id = 1';connection.query(sql,(err,result)=>{if(err)throwerr;console.log(result);views();res.render('app',{user:result});}) // ここまで②})app.listen(3000,(req,res)=>{console.log('success');})
app.ejs
<%=user.id%><%=user.name%>

確認

*localhost 3000接続

mac.terminal
$ node app.js
success

以上

【合わせて読みたい】

■ 【HOMEBREW】 Mac OSのパッケージマネージャーについて node.jsやってたら学んだ事
https://qiita.com/tanaka-yu3/items/65dac47443cc08914a86

■【node.js】 node.jsインストール 芋っていたけど、簡単だった件...
JavaScript
https://qiita.com/tanaka-yu3/items/739db5ffed24a8d9ae4b

■DBonline
https://www.dbonline.jp/

Cloud Functions を Node.js 10 移行する

$
0
0

久しぶりに Cloud Functions のコンソール画面を開いたら下記のような警告が来ていました。どうやら Node.js 8 が非推奨になり2021年の3月中旬には全面的にサポートされなくなるとのことなので、Node.js 10 へ移行します。

image.png

https://cloud.google.com/functions/docs/migrating/nodejs-runtimes?hl=ja

移行していく

まずは Node.js 10 にバージョンアップするので、Deploy・エミュレーションができるように最新の Firebase CLI をインストールします。

$ npm install -g firebase-tools@latest

次に functions> package.jsonenginesブロックの nodeターゲットを 10 に変更します。

"engines":{"node":"10"}

ほとんどの場合 Node.js 8 と Node.js 10 ではコードが変更されることはありませんが、自動的にセットされる環境変数が変更されたみたいなので、詳しくは下記リンクを参照してください。

https://cloud.google.com/functions/docs/env-var#environment_variables_set_automatically

テストしてみる

firebase emulators:startでエミュレートをスタートさせ、View in Emulator UIで表示されたローカルポートで Emulator Suite を開きます。

image.png

emulator がインストールされていない場合は下記コマンドでインストールします。

$ npm install -g @google-cloud/functions-emulator

http://localhost:5001/{project_name}/us-central1/{関数名}のように HTTP関数でリクエストを実行すれば、ローカル環境でテストを行うことができるようになります。

https://firebase.google.com/docs/functions/get-started?hl=ja#emulate-execution-of-your-functions

テストが完了したので最後にデプロイします。

$ firebase deploy --only functions
Viewing all 8902 articles
Browse latest View live