20200116のNode.jsに関する記事は8件です。

Ubuntu18.04 開発環境作成メモ

how to use

cd ~
chmod +x setup.sh
./setup.sh

setup.sh

setup.sh
sudo apt update
sudo apt -y upgrade
sudo apt -y install vim
sudo apt -y install git
sudo apt -y install guake
sudo apt -y install curl
sudo apt-get -y install xsel

# pyenv 
sudo apt -y install build-essential libffi-dev libssl-dev zlib1g-dev liblzma-dev libbz2-dev libreadline-dev libsqlite3-dev
git clone https://github.com/pyenv/pyenv.git ~/.pyenv
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc
source ~/.bashrc
pyenv install 3.7.6
pyenv global 3.7.6

# nodebrew
curl -L git.io/nodebrew | perl - setup
echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
nodebrew install-binary stable
nodebrew use stable
npm -g install @angular/cli
sudo sysctl fs.inotify.max_user_watches=524288
sudo sysctl -p

# docker
sudo apt install docker.io
sudo groupadd docker
sudo gpasswd -a $USER docker
sudo systemctl restart docker

# docker-compose
sudo curl -L "https://github.com/docker/compose/releases/download/1.25.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

# ssh keygen
ssh-keygen -t rsa
cat .ssh/id_rsa.pub | xsel --clipboard --input

# english directory
LANG=C xdg-user-dirs-gtk-update

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

Node.jsを用いた定期ツイートbot作成メモ

すぐ忘れるのでメモ。

もっと無駄の少ないやり方なんて知りません、、、

まずTwitterAPIの取得

申請の際の作文はbotにしか使わないという趣旨を書けばすぐに通るはずです。

API keyとToken keyが得られれば勝ち。

ツイート内容のコードを作る

用意するのはnpm i Twitternpm i node-schedule

ツイート
https://yukimonkey.com/js-application/twitter-bot-2/

画像ツイート
https://qiita.com/n0bisuke/items/6b269f61152e9f336c35

時間指定はNode-scheduleを使う

Heroku

アカウント作成

タイムゾーンについて、途中で気づいてめんどくさかったのでソースコードの時間を-9hしました。

Herokuへデプロイ

コマンドはこの記事を参考にしました。
https://qiita.com/daiki7nohe/items/035c39c1e538551b1f6c#git%E3%82%B3%E3%83%9F%E3%83%83%E3%83%88
この二つの記事を参考にapp.jsと、起動するためのコマンドをpackage.jsonに記述するか、procfileを作る
https://qiita.com/yfujii01/items/d675f654f1fcce3b9098
https://www.webprofessional.jp/building-facebook-chat-bot-node-heroku/

サーバーが寝ないようにする

Heroku Scheduler
https://miyabi-lab.space/blog/23

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

【文系新卒が】出来立てご飯を食べたかった話【GoogleHome LINE Node-RED】

事の始まり

僕はご飯が大好きな文系新卒君です。
僕はありがたいことに、家に帰るとご飯が毎日用意されています。
しかし学生時代のように出来立てのホカホカご飯を食べれる機会は減ってしまいました。
そう...社会人は学生とは違い帰る時間がバラバラ。
帰る時間を連絡しても、1日中ケータイを触ってるわけじゃないのでご飯の完成にラグが起きてしまう。

.....だったら帰宅時間を教えることのできるシステムを作ればいいじゃないか!!

全体図

どうすれば帰宅時間を知らせることができるか考えた結果、
「物理的」に知らせるのが一番じゃないかと考えました。
100.png

こんな感じで実装すれば、ラインメッセージと自宅へ音声送信両方が実現ができるはず!

実装

それでは実装していきますよ!!
事前準備は4つ

  • Node-REDのインストール
  • LINE Developersのアカウント
  • Google App Script
  • Node-REDと同じLANに接続されたGoogleHome

今回LINEとGoogleHomeを繋げる目的で利用するNode-REDですが
何かと何かを繋ぐ際にGUI上で実行できるWebアプリケーションと思って下さい。

参考資料
Node-RED日本ユーザ会
Windowsで実行する : Node-RED日本ユーザ会
LINEのBot開発 超入門(前編) ゼロから応答ができるまで
Google Homeの初期設定をする手順

1.Node-REDとGoogleHomeを繋げる

まず初めにNode-REDのページを開き、パレットの管理からnode-red-contrib-castを追加します。
これがGoogleHomeへ送ったメッセージを読み上げさせるノードになります。
インストールが完了したら、下図のフローを作成してください。
無題1.png

次にCastノードの設定を行います。

項目 入力内容
IP GooglHomeのIPアドレス
language ja
Volume 0~100(好みの音量サイズ)

設定後にinjectノードを実行し、設定した言葉がGoogleHomeから聞こえたらOKです!

2.Node-REDをネットワークに公開

このままではNode-REDはローカル外からのアクセスができません。
なので簡単にローカル環境を外部から接続させることのできるngrokを使いたいと思います。
ngrokをインストールしてNode-REDで設定されているポートをパスワード付きで公開してください。

EXAMPLES:
    ngrok http 80                    # secure public URL for port 80 web server
ngrok by @inconshreveable                                                                                                                                           (Ctrl+C to quit)

Session Status                online
Version                       2.2.4
Region                        United States (us)
Web Interface                 http://127.0.0.1:1880
Forwarding                    http://xxxxxxxx.ngrok.io -> localhost:1880
Forwarding                    https://xxxxxxxx.ngrok.io -> localhost:1880

Connections                   ttl     opn     rt1     rt5     p50     p90
                              6       0       0.05    0.02    23.33   25.98

Forwadingに書かれているURL(https)にアクセスができたらOKです!

ngrokの使い方(windows, mac)
少しでも安全にngrokを使用する(Basic認証)

3.LINEとNode-REDを繋げる

最後にLINEとNode-REDを繋げたいと思います。
まずはGoogle App Script(GAS)で以下のコードを張り付けて下さい。
※アクセス先の情報は自身で入力してください。

function doPost(e) {
  // アクセス先の情報
  var url = "ngrokで作成したHTTPSのURL" + "/line";
  var userid = "任意のID";
  var password = "任意のパスワード";

    // POSTメソッドの投稿データ
  var event = JSON.parse(e.postData.contents).events[0];
  var replyToken = event.replyToken
  var msg = event.message.text;
  var msgType = event.message.type;

  var payload = {"replyToken":  replyToken, "message":msg, "type":msgType};

    // POSTメソッドのオプション
    var options = {
      "method" : "POST",
      "headers" : {"Authorization" : " Basic " + Utilities.base64Encode(userid + ":" + password)},
      "payload" : payload,
      "muteHttpExceptions" : true
    }

    try{
      // POSTメソッドのリクエスト
      var response = UrlFetchApp.fetch(url, options);
      var content = response.getContentText("UTF-8");
    }catch(e){
      Logger.log(e.message);
    }
}

その後Webアプリケーションとして導入を行うことでWebhook用のURLが表示されるので、
それを忘れないようコピーして置いてください。(Current web app URLのところです)
無題2.png

LINE DevelopersへアクセスしてWebhook先へ先ほどのURLを貼り付けます。

無題3.png

ついでにチャンネルアクセストークンを使うのでメモしておきましょう。
100.png

あとはNode-RED上でLINE+GASからのメッセージとGoogleHomeを繋げてあげれば完了です!

4.LINEのメッセージとGoogleHomeを繋げる

いよいよ最終工程。完成状態はこんな感じになります!
無題4.png
最後に下に記載したJSONデータを読み込ませて、以下の項目を行えば終了です!!

  • googlehomeノードを最初に設定したgooglehomeノードに変更。
  • Line Reply API用設定Bearer "your_channel_access_token"""中身を先程メモしたチャンネルアクセストークンに変更。

※Line Reply API用設定でLINE Developersからチャンネルアクセストークンは確認できます。

作成したLINE botにメッセージを送信すれば、Googleホームが読み上げてくれます!!!

[{"id":"314b7d3f.2adc62","type":"tab","label":"フロー 1","disabled":false,"info":""},{"id":"72e325a4.cdbacc","type":"comment","z":"314b7d3f.2adc62","name":"line reply msg","info":"","x":310,"y":160,"wires":[]},{"id":"65a3144c.b1371c","type":"http in","z":"314b7d3f.2adc62","name":"","url":"/line","method":"post","upload":false,"swaggerDoc":"","x":170,"y":220,"wires":[["246b9d27.a33942","4ff3caa3.50ed94"]]},{"id":"accdaf77.6e5c9","type":"http response","z":"314b7d3f.2adc62","name":"","statusCode":"","headers":{},"x":850,"y":220,"wires":[]},{"id":"1bc5bba6.3b0244","type":"http request","z":"314b7d3f.2adc62","name":"Line Reply API","method":"POST","ret":"txt","paytoqs":false,"url":"https://api.line.me/v2/bot/message/reply","tls":"","persist":false,"proxy":"","authType":"","x":660,"y":220,"wires":[["accdaf77.6e5c9"]]},{"id":"246b9d27.a33942","type":"change","z":"314b7d3f.2adc62","name":"Line Reply API 用設定","rules":[{"t":"set","p":"headers.Content-Type","pt":"msg","to":"application/json","tot":"str"},{"t":"set","p":"headers.Authorization","pt":"msg","to":"Bearer \"your_channel_access_token\"","tot":"str"},{"t":"set","p":"payload.replyToken","pt":"msg","to":"payload.replyToken","tot":"msg"},{"t":"set","p":"payload.messages[0].type","pt":"msg","to":"text","tot":"str"},{"t":"set","p":"payload.messages[0].text","pt":"msg","to":"送信完了","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":420,"y":220,"wires":[["1bc5bba6.3b0244"]]},{"id":"894d56ce.436268","type":"cast-to-client","z":"314b7d3f.2adc62","name":"google home","url":"","contentType":"","message":"","language":"ja","ip":"","port":"","volume":"50","x":770,"y":380,"wires":[[]]},{"id":"97eee3ab.2f10f","type":"comment","z":"314b7d3f.2adc62","name":"googlehome","info":"","x":350,"y":340,"wires":[]},{"id":"4ff3caa3.50ed94","type":"change","z":"314b7d3f.2adc62","name":"受信したJSONからメッセージのみ取得","rules":[{"t":"set","p":"message","pt":"msg","to":"payload.message","tot":"msg"},{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":500,"y":380,"wires":[["894d56ce.436268"]]}]

あとがき

これにて我が家のホカホカご飯問題は幕を閉じた。
今日も出来立てご飯と幸せを噛みしめる文系新卒君であった。

文系新卒君の挑戦は続く...

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

LambdaからRedisのデータを取得したい

使用するもの

  • Lambda
  • Redis

私の環境

Node 12系

DockerでLamdaを用意しています。方法については、以下の記事を参考にしてください。
https://qiita.com/gdtypk/items/78b6a76dc9f212296c89

Redisも同様にDockerで起動しています。
redis:4.0

困ったこと

Node.jsは非同期で動作するので、そのあたりが苦労した。

コード

const redis   = require("redis");
const Promise = require('bluebird');

// 接続情報
const config = {
    host: 'redis',
    port: 6379
};

let client = null;
let value  = "";
const key  = "key";

exports.handler = async (event, context) => {
    try {
        //Redisに接続
        client = await connectRedis();

        // データの取得
        value = await findValueOfKey(client, key);

        //Redisとの接続を切断
        disconnectRedis();

        //レスポンス返却
        console.error('レスポンス:' + value);
        context.succeed({statusCode: 200, body: JSON.stringify(value)});
    } catch (error) {
        console.error('エラー:', error);
        disconnectRedis();
    }
};

/** 
 * Redisに接続する処理。
 */
function connectRedis() {
    return new Promise(function (resolve, reject) {
        const client = redis.createClient(config);

        client.on('connect', () => {
            console.log('接続OK');
            resolve(client);
        });
        client.on('error', (error) => {
            console.log(`接続NG`);
            reject(error);
        });
    });
}

/**
 * Redisとの接続を切断する。
 */
function disconnectRedis() {
    if (client) {
        console.log("切断します");
        client.end(true);
    }
}

/**
 * Keyを使用し、Valueを取得する。
 * @param client
 * @param key
 */
function findValueOfKey(client, key) {
    return new Promise(function (resolve) {
        client.get(key, (err, reply) => {
            resolve(reply);
        });
    });
}

おわり

もっといい書き方があったり、コードがおかしいとかあれば、教えて下さい。

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

Could not find matching close tag for "<%="のエラーメッセージ

node.jsのエラーコード

Could not find matching close tag for "<%="

意味 “<%=“. に合うタグが見つかりませんでした。

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

node.jsを10->12に更新したときに起きたエラーと対処内容

表題通りの記事です。
これからnode.jsを10->12に更新する方の助けになれば幸いです。

確認環境

  • Ubuntu: 18.04.3 LTS
  • node.js: 10.16.0、12.14.1
  • ビルドツール: gulp (後述しますが4系へのアップデートが必須でした)

やったこと(全体像)

  • n をつかってローカル環境のnode.jsを10->12に更新 (参考: nodeとnpmのバージョン更新方法)
  • npm ciして、出てきたエラーを潰す
    • firebaseの更新
    • node-sassの更新
  • npm run buildして、出てきたエラーを潰す
    • gulpを3系->4系へ移行

エラー1 (firebaseの更新により解消)

最初はイージーケースから。

事象

npm ciしたところ、大量(体感3分)のログが出力され、最後に以下のエラーが吐かれました。

# これ以前にも大量のエラーログが出る
cc1plus: error: unrecognized command line option ‘-Wno-cast-function-type’ [-Werror]
cc1plus: all warnings being treated as errors
grpc_node.target.mk:188: recipe for target 'Release/obj.target/grpc_node/ext/channel.o' failed
make: *** [Release/obj.target/grpc_node/ext/channel.o] Error 1

# 最後の方に出るmakeのログを見ることで、どのパッケージのビルドに失敗したかが分かる
# (repository-nameでgrepすると早く見つかる)
make: ディレクトリ '/home/user1/repository-name/node_modules/grpc/build' から出ます

gyp ERR! build error 
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack     at ChildProcess.onExit (/usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:194:23)
gyp ERR! stack     at ChildProcess.emit (events.js:223:5)
gyp ERR! stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:272:12)
gyp ERR! System Linux 4.15.0-74-generic
gyp ERR! command "/usr/local/bin/node" "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "build" "--fallback-to-build" "--library=static_library" "--module=/home/user1/repository-name/node_modules/grpc/src/node/extension_binary/node-v72-linux-x64-glibc/grpc_node.node" "--module_name=grpc_node" "--module_path=/home/user1/repository-name/node_modules/grpc/src/node/extension_binary/node-v72-linux-x64-glibc" "--napi_version=5" "--node_abi_napi=napi" "--napi_build_version=0" "--node_napi_label=node-v72"
gyp ERR! cwd /home/user1/repository-name/node_modules/grpc
gyp ERR! node -v v12.14.1
gyp ERR! node-gyp -v v5.0.5
gyp ERR! not ok 
node-pre-gyp ERR! build error 
node-pre-gyp ERR! stack Error: Failed to execute '/usr/local/bin/node /usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js build --fallback-to-build --library=static_library --module=/home/user1/repository-name/node_modules/grpc/src/node/extension_binary/node-v72-linux-x64-glibc/grpc_node.node --module_name=grpc_node --module_path=/home/user1/repository-name/node_modules/grpc/src/node/extension_binary/node-v72-linux-x64-glibc --napi_version=5 --node_abi_napi=napi --napi_build_version=0 --node_napi_label=node-v72' (1)
node-pre-gyp ERR! stack     at ChildProcess.<anonymous> (/home/user1/repository-name/node_modules/grpc/node_modules/node-pre-gyp/lib/util/compile.js:83:29)
node-pre-gyp ERR! stack     at ChildProcess.emit (events.js:223:5)
node-pre-gyp ERR! stack     at maybeClose (internal/child_process.js:1021:16)
node-pre-gyp ERR! stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:283:5)
node-pre-gyp ERR! System Linux 4.15.0-74-generic
node-pre-gyp ERR! command "/usr/local/bin/node" "/home/user1/repository-name/node_modules/grpc/node_modules/.bin/node-pre-gyp" "install" "--fallback-to-build" "--library=static_library"
node-pre-gyp ERR! cwd /home/user1/repository-name/node_modules/grpc
node-pre-gyp ERR! node -v v12.14.1
node-pre-gyp ERR! node-pre-gyp -v v0.12.0
node-pre-gyp ERR! not ok 

調べたこと

ログにあるとおり、grpcのビルドに失敗しています。
(最初は大量のログにとまどいました。どのパッケージがインストールできていないか調べるのが第一歩です)

更新対象リポジトリのpackage.jsonにはgrpcの記述がなく、
npm lsで依存パッケージを調べたところ、firebaseがgrpcに依存していました。

$ npm ls
# 結果を抜粋
├─┬ firebase@5.5.7
│ ├─┬ @firebase/firestore@0.8.6
│ │ ├─┬ grpc@1.13.1 <- ここでエラー

解決策

執筆時点でfirebaseは7系が最新。単純に古いので、アップデートしたところ解決。
(メジャーバージョン更新による影響も今のところなし)

$ npm install -D firebase




エラー2 (node-sassの更新により解消)

エラー1をちょっとひねったパターン。

事象

npm ciしたところ、大量(体感3分)のログが出力され、最後に以下のエラーが吐かれました。

# これ以前にも大量のエラーログが出る
/home/user1/.node-gyp/12.14.1/include/node/v8.h:3039:5: note:   candidate expects 2 arguments, 1 provided
binding.target.mk:129: recipe for target 'Release/obj.target/binding/src/create_string.o' failed
make: *** [Release/obj.target/binding/src/create_string.o] Error 1

# 最後の方に出るmakeのログを見ることで、どのパッケージのビルドに失敗したかが分かる
make: ディレクトリ '/home/user1/repository-name/node_modules/node-sass/build' から出ます

gyp ERR! build error 
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack     at ChildProcess.onExit (/home/user1/repository-name/node_modules/node-gyp/lib/build.js:262:23)
gyp ERR! stack     at ChildProcess.emit (events.js:223:5)
gyp ERR! stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:272:12)
gyp ERR! System Linux 4.15.0-74-generic
gyp ERR! command "/usr/local/bin/node" "/home/user1/repository-name/node_modules/node-gyp/bin/node-gyp.js" "rebuild" "--verbose" "--libsass_ext=" "--libsass_cflags=" "--libsass_ldflags=" "--libsass_library="
gyp ERR! cwd /home/user1/repository-name/node_modules/node-sass
gyp ERR! node -v v12.14.1
gyp ERR! node-gyp -v v3.8.0
gyp ERR! not ok 
Build failed with error code: 1

調べたこと

ログにあるとおり、node-sassのビルドに失敗しています。
とりあえずググったところ、node-sassは4.12.0でnode.jsに12対応したそうです。

更新対象リポジトリのpackage.jsonにはnode-sassの記述がなく、
npm lsで依存パッケージを調べたところ、gulp-sassがnode-sassの4.11に依存していました。

$ npm ls
# 結果を抜粋
├─┬ gulp-sass@4.0.2
│ ├─┬ node-sass@4.11.0  ←ここでエラー(4.12以降にする必要がある)

私は最初、この段階で「詰んだ」と勘違いしました。
gulp-sassの依存パッケージを変えるには、gulp-sass公式にissueなりPRなりを投げてpackage.jsonを書き換えなければならないと思ったからです。

解決策

明示的にnode-sassをインストールしたところ、nodeがよしなにやってくれました。

$ npm install -D node-sass@4.13.0  # 実行時点での最新バージョン
$ npm ls
# 結果を抜粋
├─┬ gulp-sass@4.0.2
│ ├── node-sass@4.13.0 deduped     <- 明示的に4.13を入れたところ、nodeが重複パッケージをまとめてくれた 

上記にdeduped(=重複排除)と表示されていますが、
これはnodeが「バージョン違いの同一パッケージを1つに統合した」ことを表しています。
(今回で言うとnode-sassの4.11, 4.13のうち、より新しい4.13に統合された)

この仕様は、今回のようなケースのほかに、
セキュリティ上の脆弱性を持つ孫パッケージ(こういう呼び方があるかは不明)のバージョンを更新したいときにも役立ちます。
(参考: https://cloudpack.media/41572)

$ npm ls
├─┬ lib-nobody-update@1.1.0 # 更新が止まっているライブラリ
│ ├── lib-something@2.2.0   # 2.3.0で脆弱性が修正されたライブラリ

$ npm install -D lib-something@2.3.0
$ npm ls
├─┬ lib-nobody-update@1.1.0
│ ├── lib-something@2.3.0 deduped
Llib-something@2.3.0

今回初めて知りましたが、なかなかに素敵。




エラー3 (gulpを3系->4系へ移行することで解消)

最後はgulpの話です。

事象

npm ci実行後、npm run buildしたところ以下のエラーが発生。

[18:21:08] Requiring external module @babel/register
fs.js:27
const { Math, Object } = primordials;
                         ^

ReferenceError: primordials is not defined
    at fs.js:27:26
    at req_ (/home/user1/repository-name/node_modules/natives/index.js:143:24)
    at Object.req [as require] (/home/user1/repository-name/node_modules/natives/index.js:55:10)
    at Object.<anonymous> (/home/user1/repository-name/node_modules/vinyl-fs/node_modules/graceful-fs/fs.js:1:37)
    at Module._compile (internal/modules/cjs/loader.js:955:30)
    at Module._compile (/home/user1/repository-name/node_modules/pirates/lib/index.js:99:24)
    at Module._extensions..js (internal/modules/cjs/loader.js:991:10)
    at Object.newLoader [as .js] (/home/user1/repository-name/node_modules/pirates/lib/index.js:104:7)
    at Module.load (internal/modules/cjs/loader.js:811:32)
    at Function.Module._load (internal/modules/cjs/loader.js:723:14)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! my-package-name@0.0.0 build-gulp: `gulp build`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the my-package-name@0.0.0 build-gulp script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/user1/.npm/_logs/2020-01-15T09_21_13_322Z-debug.log
ERROR: "build-gulp" exited with 1.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! my-package-name@0.0.0 build: `run-p build-gulp build-client-ts`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the my-package-name@0.0.0 build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/user1/.npm/_logs/2020-01-15T09_21_13_421Z-debug.log

調べたこと

一見して何のエラーか分かりませんでしたが、とりあえずエラーメッセージでググったところ
gulp3系がnode12に未対応なのが原因だと判明。gulp4系は対応済み。

いっそビルド関連をwebpackに置き換えることも考えましたが、
今回は対応速度を重視してgulpを更新する方針にしました。

解決策

以下を参考にgulpを更新しました。
(破壊的変更が多く、そこそこ面倒でした)


要点をかいつまむと、以下のようになります。

  • gulp.task()は非推奨になった(この点に触れない記事が多い)
    • 後方互換性のため、一応まだ使える
    • 代わりに関数をexportするスタイルになった
  • タスクの直列実行、並列実行は新関数gulp.series(), gulp.parallel()で制御
// 3系: gulp.task(”タスク名”, タスク用の関数)
gulp.task("buildFrontend", () => { /* フロントエンドのビルド処理 */ });
gulp.task("buildBackend", () => { /* バックエンドのビルド処理 */ });
gulp.task("build", ["buildFrontend", "buildBackend"]);  // []は並列実行

// 4系: export const タスク名 = タスク用の関数;
export const buildFrontend = () => { /* フロントエンドのビルド処理 */ };
export const buildBackend = () => { /* バックエンドのビルド処理 */ }; 
export const build = gulp.parallel(buildFrontend, buildBackend);

3系に比べて可読性があがりましたね。
なお、exportの順番が大切で、自行より下で定義された関数を参照するとエラーになります。(これは微妙)

// ダメな例
export const build2 = gulp.parallel(buildFrontend2, buildBackend2);
export const buildFrontend2 = () => { /* フロントエンドのビルド処理 */ };
export const buildBackend2 = () => { /* バックエンドのビルド処理 */ }; 


// 実行すると以下のエラーが出る
$ npx gulp build
> my-package-name@0.0.0 build /home/duser1/repository-name
> gulp build

/home/duser1/repository-name/gulpfile.js:10
const build = gulp.parallel(buildFrontend2, buildBackend2);
                            ^
ReferenceError: Cannot access 'buildFrontend2' before initialization
    at Object.<anonymous> (/home/duser1/repository-name/gulpfile.js:10:29)
    at Module._compile (internal/modules/cjs/loader.js:955:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:991:10)
    at Module.load (internal/modules/cjs/loader.js:811:32)
    at Function.Module._load (internal/modules/cjs/loader.js:723:14)
    at Module.require (internal/modules/cjs/loader.js:848:19)
    at require (internal/modules/cjs/helpers.js:74:18)
    at execute (/home/duser1/repository-name/node_modules/gulp/node_modules/gulp-cli/lib/versioned/^4.0.0/index.js:36:18)
    at Liftoff.handleArguments (/home/duser1/repository-name/node_modules/gulp/node_modules/gulp-cli/index.js:201:24)
    at Liftoff.execute (/home/duser1/repository-name/node_modules/liftoff/index.js:201:12)
    at module.exports (/home/duser1/repository-name/node_modules/flagged-respawn/index.js:51:3)
    at Liftoff.<anonymous> (/home/duser1/repository-name/node_modules/liftoff/index.js:191:5)
    at /home/duser1/repository-name/node_modules/liftoff/index.js:149:9
    at /home/duser1/repository-name/node_modules/v8flags/index.js:138:14
    at /home/duser1/repository-name/node_modules/v8flags/index.js:41:14
    at /home/duser1/repository-name/node_modules/v8flags/index.js:53:7
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! my-package-name@0.0.0 build: `gulp build`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the my-package-name@0.0.0 build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/duser1/.npm/_logs/2020-01-15T10_04_26_061Z-debug.log




まとめ

  • バージョン更新は思った以上に大変
  • こまめな更新が、バージョン更新のコストを下げる
  • npm lsでパッケージの依存関係をチェックできる
  • nodeにはdedupeという素敵機能がある
  • node12でgulp3系は使えない。4系に移行するか、webpackなど他ツールへ移行する


webpackちゃんと使えるようになりたいです。

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

npm を使用して、誰かが書いたコードをリユースする方法

npmで誰かが書いたコードを使用する

NPM(Node Package Manager)は、誰かが書いたコードを使用できる便利な管理システム。

自分で1から作るんじゃなくて、誰かが書いたコードを使用できるなら、それをリユースして無駄な時間を削減しようっていう考え方を元に作成された管理システム。

https://www.npmjs.com/

npm を使用するまでの手順

今回は intro-to-node のフォルダ内のindex.jsというファイルでnpmを使用できるようにします。

スクリーンショット 2020-01-14 15.14.42.png

npm を初期化する

コマンドラインでちゃんと intro-to-node フォルダに移動しているか確認してください。

スクリーンショット 2020-01-14 15.17.05.png

確認できたら

npm init

で初期化します。

色々入力を求められるので、こんな感じで入力していきます。

スクリーンショット 2020-01-14 15.20.32.png

まぁほとんどコマンドラインの提案通りにEnter押していくだけで、実際入力したのは、description(説明)とauthor(著者)のみ。

すると、package.jsonファイルが intro-to-nodeフォルダに作成されているのがわかります。

スクリーンショット 2020-01-14 15.22.19.png

ちなみに、package.jsonの中身はこんな感じ。

package.json

{
  "name": "intro-to-node",
  "version": "1.0.0",
  "description": "This is a introduction to node project.",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "kibinag0",
  "license": "ISC"
}

npm で使用したいパッケージを選ぶ

npm の公式サイト
(https://www.npmjs.com/)
にいって、使用したいパッケージを選ぶ。

今回使うのは、下記のスーパーヒーローの名前を取得してくれるパッケージです。
https://www.npmjs.com/package/superheroes

『superheroes name』 と検索したら、出てきました。

使用するパッケージをインストールする

各パッケージには、インストールの部分があるので、コマンドラインを使用してインストールします。

スクリーンショット 2020-01-16 08.34.24.png

ちゃんと自分が使用するフォルダ(intro-to-node)にいるか確認してから、インストールを実行しましょう。

スクリーンショット 2020-01-16 08.37.29.png

『npm install パッケージ名』

これでインストールは完了。

パッケージを使用する

使用するときは、パッケージのUsageを見るとわかりやすいです。

スクリーンショット 2020-01-16 08.40.59.png

index.js
// superheroes をファイル内で使用できるようにする
const superheroes = require("superheroes");


// Usage に記載されている random() を使用する
var hero = superheroes.random();

// ランダムで Super Hero の名前を取得できる

これにてnpmの使用方法まとめ終了です。

このコンテンツはUdemyの The Complete 2020 Web Development Bootcamp を参考にしています。

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

ネットサークル「TeamKitten」のメンバー管理APIをNodeで書き直した

TeamKittenというインターネット上のサークルのリーダーをやっているTinyKittenです。

最近goa(v1だったかな)で書いていたメンバー管理用APIをNode.js(NestJS)で書き直したことと、エコシステムについて書いていきます。

晩酌中に書いてるので普段以上に文が意味不明になってるかと思いますがご容赦ください。

そもそもなぜ移行したか?

いままでgoaというGolangで書いたDSLをよしなにSwaggerと実装テンプレートに落とし込んでくれるすぐれものを使っていました。が、
突然のアップデートでgo getすらできなくなる
という事態が発生ししばらく安定して動くコードで騙し騙しで動かしていました。
しかし、APIにバグが見つかりどうにも現行コードベースでは修正できないと判断し移行した次第です。

goaをアップグレードすればよかったのでは?

それもそうなのですが、goa自体にそれほど固執がなかったのと、チーム内にGolangを書けるメンバーがいなかったのでNode.jsを使ったNestJSフレームワークに白羽の矢が立ったわけです。
それにデザインから書くのが割と面倒だったので。デザインから書くことで助かったことも割と多かったですが、うちのAPIはそこまでクリティカルなものではないので。

NestJSとは?

NestJSとは、AngularにインスパイアされたサーバーサイドNode.jsフレームワークです。
Angularにインスパイアされたということで、書き方もほぼAngularです。
仕事でAngularを長年(というほどでもない)使っているので、割とすんなり書ける感じでそこも選ぶ要因の一つでした。

スタックはどのように変わった?

teamkitten-gcp.png
goaを使っていたときはGCPを使っていました。なんとなくGoogleに揃えたかったのと、AWSのコンソールが複雑怪奇だと当時思ってたからです。
上記の図の通り、シンプルにすべてのTeamKitten内部サービスからGAEのAPIにアクセスし、バックではデータベースにCloudSQL(MySQL)、オブジェクトストレージにCloudStorageを用いていました。
今はどう変わったかというと、単純にAWSになりました。(ALBとかRoute53も増えてますが...)
teamkitten-aws.png
このような図はあまり書いたことがなく見づらくて恐縮です。
ポータル、公式サイト、すごいBOT等のエコシステムにAPIをつないでいます。(後述)
費用に関しては、個人的な機械学習に使ったEC2も混じっているのではっきりとは言えませんが、今の時点で\$100程度請求されています。(多分\$30くらいが機械学習)
GCPのときは\$50しませんでした。費用削減の余地はありそう。

良かった点は?

仕事ではTypeScript・Angularを扱っているのでスムーズに書ける点でした。
NestJSのドキュメントは割と充実しているので英語さえ多少読めればすぐに扱えます。
テストコードもだいたいAngularっぽいです。(JasmineがJestになってますが)

苦労した点は?

仕事柄、GoよりもJavaScript(ここではTypeScript)を扱うことの方が慣れているので、割とサクサク書くことができました。
が、強いて言うならTSLintを怒らせたくないがためにレスポンスのスネークケースをキャメルケースに置き換えたり、最初からデザインから書くわけではないのでSwaggerがまだ整備できていない点でしょうか。(多分クライアントを作るのは自分だけなのでそれほど必要はないですが)

エコシステムのポータルとは?

FireShot Capture 006 - TeamKitten Portal - portal.teamkitten.tk.png
メンバーの方々がログインして、自己紹介・アイコン・スクリーンネーム(ログイン用に使える名前)・カバーイメージなどを自主的に変更できるチーム内サービスです。
EXCメンバー(一般メンバーより偉いメンバー)は他の人のパスワード、担当を変更できたりします。
リーダー権限のメンバー(自分だけ)は、メンバー削除、権限降格・昇格などが可能にしてます。
また、監査という機能を新APIには実装して、誰が誰の情報をいじったかを可視化できるようにしました。これで権限を使って勝手なことをするメンバーがいたとしても、すぐに検出できます。(この機能は上位メンバーのみ見れます)
このサービスは今まではNuxt.jsで書かれていましたが、自分の個人的な趣向とまともなUIフレームワークを欲していたのでIonic 4にしました。
FireShot Capture 007 - TeamKitten Portal - portal.teamkitten.tk.png
新APIに対応させるために改装中です。

エコシステムのすごいBOTとは?

これに関してはチーム内の機密情報なのですが、DiscordのBOTです。まあおもちゃみたいな存在とだけ言います。あとはメンバーの照会ができます。

まとめ

適当に取り留めもなく書いてしまいましたが、Node.js化して正解でした。
メンバーもNode.jsならできるという方もいますし、個人的にもTypeScriptが一番しっくり来るので良かったです。

GitHub

サークルの公式GitHubチーム
API
Portal

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