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

CodeCommitにcommit/pushしたらLambda経由でSlackにcommentつき通知を飛ばす

$
0
0

AWS CodeCommit上で管理しているリポジトリに、誰かがcommit/pushしたらSlackで通知を受け取りたいと思って試行錯誤したときのメモになります。Lamda関数はNode.jsで記述しています。

前置き

  • CodeCommitやLamda、Slackの細かい話は書きません。
  • Lamda関数のNode.jsのサンプルコードや注意点だけを書きます。
  • 以下はすべてAWS Console上からの操作です。

処理の流れ

CodeCommit → トリガー → Lambda → Slack Incomming WebhookのURLにPOST → Slackからスマホアプリ等に通知が飛ぶ

Lamda関数

適当な名前でLamda関数を作成します。以下のサンプルコードをindex.jsに上書きします。optionsのIncomming WebhookのURLと、中程にあるSlack上に表示するメッセージのBlock Kitテンプレートはお好みに合わせて修正します。

codeCommitToSlackWebhook
constAWS=require('aws-sdk');constcodecommit=newAWS.CodeCommit({region:'ap-northeast-1'});consthttps=require('https');//const util = require("util");constoptions={hostname:'hooks.slack.com',path:'/services/*******/*******/*******',method:'POST',headers:{"Accept":"application/json","Content-Type":"application/json; charset=UTF-8"}};exports.handler=function(event,context){letrepository=event.Records[0].eventSourceARN.split(":")[5];letreferences=event.Records[0].codecommit.references;letfuncArr=references.map((x)=>{returnnewPromise((resolve,reject)=>{letparams={commitId:x.commit,repositoryName:repository};codecommit.getCommit(params,function(err,data){if(err)reject(err);elseresolve({params:params,data:data});});});});Promise.all(funcArr).then((values)=>{//console.log(util.inspect({//  values:values//},{colors:true, depth: null}));returnnewPromise((resolve,reject)=>{letblocks=[];blocks.push({type:'section',text:{type:'mrkdwn',text:`new commit pushed to \`${references[0].ref}\`\n\n*Repository:* "${repository}"`,}});letv=values.map((x)=>{lettmp=newDate(x.data.commit.committer.date.split('')[0]*1000);tmp=`${tmp.getFullYear()}/${('0'+(tmp.getMonth()+1)).slice(-2)}/${('0'+tmp.getDate()).slice(-2)}${('0'+tmp.getHours()).slice(-2)}:${('0'+tmp.getMinutes()).slice(-2)}:${('0'+tmp.getSeconds()).slice(-2)}`;return{type:'section',fields:[{type:'mrkdwn',text:'*CommitId:*\n'+x.params.commitId},{type:'mrkdwn',text:'*Comment:*\n'+x.data.commit.message},{type:'mrkdwn',text:'*Committer:*\n'+x.data.commit.committer.name},{type:'mrkdwn',text:'*When:*\n'+tmp}]};});values={blocks:blocks.concat(v)};resolve(values);});}).then((value)=>{//console.log(util.inspect({//  value:value//},{colors:true, depth: null}));letreq=https.request(options,(res)=>{letbody='';//console.log('statusCode: '+res.statusCode);res.setEncoding('utf8');res.on('data',(chunk)=>{body+=chunk;});res.on('end',()=>{//console.log({body:body});context.done(null,body);});});req.on('error',(e)=>{//console.log({e:e});context.fail(e);});req.write(JSON.stringify(value));req.end();}).catch((err)=>{//console.log({err:err});context.fail(err);});};

Lambdaのアクセス権限

  1. Lambda アクセス権 → 実行ロール → IAMロールの設定が別ウィンドウで開く
  2. 「ポリシーをアタッチします」でAWSCodeCommitReadOnlyをアタッチ

Lambdaのトリガー

  1. Lambda 設定 → デザイナー → トリガーの追加
  2. トリガーの設定 → CodeCommitを選択
  3. リポジトリ名選択、トリガー名にslackWebhookTriggerなど入力、ブランチ名をすべてのブランチを選択
  4. 追加

通知のテスト

  1. CodeCommit リポジトリ選択
  2. 設定 → トリガー → slackWebhookTriggerなどトリガー名のリンク
  3. ページ下部 → トリガーのテスト

Lambdaの注意点

環境変数を設定しないと通知内容に含まれる時刻がUTCになってしまいます。以下を設定します。

  • Lambda 設定 → 環境変数 → キー: TZ、値: Asia/Tokyoを追加

デバッグ

Lambda関数内のconsole.logのコメントアウトを外し、CloudWatch Logsでどこでエラーが発生しているか確認します。

参考URL

例: AWS Lambda 関数の AWS CodeCommit トリガーを作成する
https://docs.aws.amazon.com/ja_jp/codecommit/latest/userguide/how-to-notify-lambda.html

以上です。


【JavaScript 】Node.jsとは

$
0
0

はじめに

Node.jsとはサーバーサイドのjavascriptのプラットフォーム(実行環境)である。
javascriptは本来クライアントサイドで動作するプログラミング言語だが、Node.jsを使用することでサーバーサイドでもjavascriptが利用できるようになる。

公式サイト、またはOSのパッケージ管理ツールを使用してインストールすることでNode.jsが使用できる。
公式サイト
色々なパッケージ管理ツールでのインストール

クライアントサイドとサーバーサイド

🌟 WEBページをブラウザで閲覧する場合の仕組み

1. ブラウザ(クライアント)でURLを指定、サーバーにリクエスト
2. リクエストを受けたサーバーはページを表示するために
   必要なhtmlやそれに関連するCSSやjavascriptをブラウザ(クライアント)に返す
3. クライアント側でそれらを受け取ることでWEBページが閲覧できるようになる

クライアントサイド
クライアントサイドの言語とは、クライアント(WEB上であればブラウザのこと)からサーバーにリクエストして得られた結果をブラウザで処理(表示)する際に使われる言語のこと。
javascriptがクライアントサイドの言語として挙げられる。

サーバーサイド
サーバーサイドの言語とは、クライアントに結果を渡すためにサーバー内で処理を行う言語のこと。
PHP、Ruby、Pythonなどの言語がサーバーサイドで使用される。

npm

npmとはNode.jsのパッケージを管理するツールで、Node.jsをインストールすることで自動的に使えるようになる。
ここでいうパッケージとは、あらかじめ用意されているNode.jsの便利な機能をまとめたもののこと。
npmで様々なパッケージのインストールやアップデートをコマンドラインから行うことができる。
npmでインストールされたパッケージはnode_modulesディレクトリにインストールされ、package.jsonファイルで管理ができる。

npmのインストールの種類

npmでパッケージをインストールするにはグローバルインストールローカルインストールの2種類の方法がある。

グローバルインストール
npmをインストールした場所にパッケージがインストールされる。全てのプロジェクト(フォルダ)でインストールしたパッケージが使用できるようになる。

↓下記コマンドを打ち込むことでグローバルにインストール

npm install -g パッケージ名

ローカルインストール
任意のプロジェクト(フォルダ)内にだけパーケージをインストールする。インストールしたプロジェクト内でしかパッケージが使用できない。

↓下記コマンドを打ち込むことでローカルにインストール

npm install パッケージ名

npm コマンド色々

npm install は npm i と省略して記述することもできる

* 作成したものを動かすために必要なパッケージをインストール
(package.json の dependenciesに追加される)
npm i -S

* 開発に必要なパッケージをインストール
(package.json の devDependenciesに追加される)
npm i -D

* パッケージのインストールリスト
npm list

* パッケージをアンインストール
npm rm

* node_modulesフォルダを削除
rm -rf node_modules

npm runでCannot find module '@babel/compat-data/corejs3-shipped-proposals'のエラー

Cloud Firestore で特定の collection のドキュメント全件数を count する方法

$
0
0

概要

Cloud Firestore で特定の collection のドキュメント全件数を count するサンプルコードをご紹介します。

前提知識: count() クエリは無い

まず、前提として Firestore には db.collection("users").count()みたいな count()クエリはありません。

結論: FieldValue.increment(1) を活用する

count()クエリが無いため、以下のように db.collection("users")のドキュメントが増減するタイミングで、ドキュメント全件数を管理する db.collection("counters")の値を FieldValue.increment()で増減させて、これでドキュメント全件数を管理します。

db.collection("counters").doc("user").update({count:FieldValue.increment(1)})

サンプルコード: 特定 collection のドキュメント全件数 count

constadmin=require("firebase-admin");admin.initializeApp();constdb=admin.firestore();constFieldValue=admin.firestore.FieldValue;db.collection("users").add({name:'test'}).then(()=>{returndb.collection("counters").doc("user").update({count:FieldValue.increment(1)}).finally(()=>{returnres.status(200).send("OK");});}).catch((err)=>{console.error(err);returnres.status(500).send("NG");});

以上、Cloud Firestore で特定の collection のドキュメント全件数を count したい、現場からお送りしました。

参考情報

Node.jsのバージョンを切り替えてnode -vしてもバージョンが切り替わっていない!

$
0
0

Node.jsのバージョン切り替えで詰まった話。

バージョンを設定して、確認すると

terminal
$nodebrew use v12.18.2
$nodebrew lsv10.16.3
v12.4.0
v12.18.2
v14.5.0

current: v12.18.2 // nodebrewでは選択されている

順調っ!

terminal
$node -vv10.16.3

あれっ?設定されていない?
環境変数PATHに設定されているディレクトリを確認してみる。

terminal
$which node
/usr/local/bin/node ← Systemのnode
  • システムのnodeを参照していることが原因だった

解決法

環境変数を追加

/.bash_profile
...
export PATH=$HOME/.nodebrew/current/bin:$PATH
terminal
ルートディレクトリにて
$source .bash_profile
$which node
/Users/macuser/.nodebrew/current/bin/node ←nodebrewが適用されている

$node -vv12.18.2

できた!!

Node.js 依存モジュールのファイルはケースセンシティブの件

$
0
0

皆さん開発の時ほとんど macOS を使ってるんでしょうか、だが macOS のファイル名はケースインセンシティブ(大小文字は区別しない)。つまり同じフォルダ下に package.jsonpackagE.jsonは一緒にいられない。

ほとんどの人は知ってるかにもかかわらず、あまりこれに注意を払ってないのではないかなと思って、だってみんなの母語は英語ではないし、インポートの際は intelliSense も結構賢く補足してもらってるので、あんまりここに転んだことはないと思います。転んでもすぐ忘れるんだろう。

よく会った問題はこれです👇

Linux でデプロイ時にモジュールは見つからない

多分誰がメモ帳で書いたコード

constlist=require('./List');

でも List のファイル名はlist.js

そしたらすべての List を list に変えなきゃいけない。

細かい点で解決には難しくないが、時間ちょっと無駄しましたね。

でも今日話したいのは僕の午後をまるごと無駄しましてこの技術的な内容あまりない記事を書くことになったこれです👇

require('./a.js') !== require('./A.js')

TypeORM を使ってる時新しいスキーマ(テーブル)を入れたが、デバッグの時ずーとそのスキーマが見つからないエラーに怒られて

TypeORM EntityMetadataNotFound: No metadata for "***" was found

option に何度も確認しまして確かにスキーマは入ってるが。

どうしようと思って、 node_modules に入って直接ソースコードを改ざんしてデバッグすることになった。

console.logでスキーマはたしかに入ってますが、

https://github.com/typeorm/typeorm/blob/master/src/connection/Connection.ts

/**
     * Gets entity metadata for the given entity class or schema name.
     */getMetadata(target:Function|EntitySchema<any>|string):EntityMetadata{constmetadata=this.findMetadata(target);if(!metadata)thrownewEntityMetadataNotFoundError(target);returnmetadata;}
/**
     * Finds exist entity metadata by the given entity class, target name or table name.
     */protectedfindMetadata(target:Function|EntitySchema<any>|string):EntityMetadata|undefined{returnthis.entityMetadatas.find(metadata=>{console.log(metadata.target,target,metadata.target===target)// ←ここif(metadata.target===target)returntrue;if(targetinstanceofEntitySchema){returnmetadata.name===target.options.name;}if(typeoftarget==="string"){if(target.indexOf(".")!==-1){returnmetadata.tablePath===target;}else{returnmetadata.name===target||metadata.tableName===target;}}returnfalse;});}

左と右は同じく Function xxxがリファレンスは同じではない。

これは事件ですね。んでファイル両方の import を一行一行で確認して、最終的に import のパスに問題を見つかった。
自分がインポートした際に、一つは Class 名をそのままコピペしたが、もう一つはファイル名でしたが、Class 名は PascalCase が、ファイル名は camelCase でした。

そしたらなぜ同じファイルで使う時ファイル名が違ったらリファレンスは違うになりますか?

Node.js のソースコードに見てきました。
https://github.com/nodejs/node/blob/master/lib/internal/modules/cjs/loader.js#L936

Node.js の require は一回しか実行しない、その原因は Node.js はモジュールをメモリに保存して、その後コードの中で require したらすぐ使えるという意図で設計されました。
ソースコードからも見えて、Node.js はファイル名でキャッシュしますが、ここの filename は require のファイル名 + 絶対パス。

なので Node.js は2つモジュールとみなすが、windows だと、 filename は path.resolve で toLowerCase で同じファイル名にするが、Linux だとケースセンシティブでモジュール見つからないで弾かれますが、この問題は macOS しか出ませんね。

ま、デプロイまで問題出るよりラッキーですね。

Node-RED Version1.1 の更新まとめ (1.1 released ブログのざっくり翻訳)

$
0
0

Node-RED Version 1.1 releasedされましたね!更新内容をざっくり翻訳して実際に眺めてみましたので、簡単にまとめておきます。

Node-RED v1.1 環境を用意する

Node-RED をちょっと試したい場合、IBM Cloud の無料スターターキットか、ローカルでのフォルダを指定したインストールがお勧めです。

IBM Cloud でサービス作成してみる

IBM Cloud では無料のライトプランで Node-RED 環境を構築できるので、新規に再作成してみました。2020年7月4日現在、v1.1.0 になっています!
image.png
ちなみに、Node-RED スターターキットの作成方法が変わって、アプリ作成とデプロイなどを別に実施する必要があって、お手軽感がだいぶ薄まった気がします。でもまぁ、無料で使える環境であることは変わらないので、今後ともお世話になるとは思います。

ローカルでサービス作成してみる

ローカルで試したい場合は、こちらのページを参考に、数分あればお試し環境を用意できます。Windows の場合ですが以下のように実行しました:

md node-red-test
cd node-red-test
npm init -y
npm install --unsafe-perm --save node-red
md .node-red
echo 2> .node-red/settings.js
node_modules\.bin\node-red -u .node-red -s .node-red/settings.js

2020年7月4日現在、こちらも v1.1.0 がインストールされました。
image.png
この方法で実行すると、必要なファイルが同じフォルダ内に揃うため、不要になったらフォルダを丸ごと削除するだけでお掃除が完了します。

新要素を確認してみる

Version 1.1 releasedブログを参照しつつ、新要素を確認しましたので、ざっくり翻訳と一緒にメモを残しておきます。

エディターの更新

情報サイドバーの再設計

情報サイドバーには、フローのツリービューが含まれています。これをアウトライナーと呼びます。フローをナビゲートして、すばやく要素を見つける別の方法を提供します。
image.png
各ノードには、ワークスペースでノードに移動するためのボタン、ノードを有効/無効にするためのボタンがあります。また Inject および Debug ノードの場合は、それらのアクションをトリガーするためのボタンもあります。ノードをダブルクリックすると、編集ダイアログが表示されます。

詳細 (英語)を参照してください。

新しいヘルプ サイドバー

アウトライナーのためのスペースを作るため、サイドバーのヘルプ セクションが独自のサイドバータブに移動しました。ヘルプを独自のタブに配置することで、ワークスペースで適切なタイプのノードを選択しなくても、使用可能なすべてのヘルプトピックを参照できるようになりました。
image.png
また、将来エディターに、他のヘルプトピックを追加するスペースも提供します。
image.png

詳細 (英語)を参照してください。

ノードのグループ化

フローを整理するために、エディターでノードをグループ化できます。
image.png
グループには、カスタムの境界線と背景色、およびオプションのラベルを付けることができます。
image.png
グループは新しいタイプのノードとしてフローに追加されます。ユーザーがこの機能を使用し始めると、まだアップグレードしていないユーザーとフローを共有することが難しくなります。

これを助けるため、グループノード タイプを登録するがまったく何もしない node-red-node-group を公開しました。このモジュールをインストールすると、Node-RED の古いバージョンがグループを含むフローをインポートできるようになりますが、エディターにグループは表示されません。また、モジュールは必要のないときには登録されないため、インストールしたままで 1.1 にアップグレードしても問題はありません。

詳細 (英語)を参照してください。

ランタイム機能

node-red-admin ビルトイン

node-red-adminコマンドラインツールは、プロジェクトの開始時から存在していますが、あまり知られていませんでした。Node-RED ランタイムをリモートで管理するため使用できます。

より便利に使えるよう、この機能は node-redコマンドに統合されました。以下のように実行します:

node-red admin

この機能で提供される便利なコマンドの1つは、adminAuthのためパスワードをハッシュするものです。使用するパスワードの入力を求められ、設定ファイルに貼り付けることができるハッシュが返されます。

$ node-red admin hash-pw

Windows ローカル環境での実行例がこちら:
image.png
詳細 (英語)を参照してください。

個別の設定の上書き

node-red コマンドは、個々の設定を上書きする -D オプションをサポートするようになりました。例えば異なるレベルのロギングで一時的に実行するには、次のように指定します:

node-red -D logging.console.level=trace

詳細 (英語)を参照してください。

httpAdminMiddleware 設定

少し前に httpNodeMiddlewareオプションが追加され、カスタムミドルウェアをHTTP入力ノードルートに追加できるようになりました。詳細はこちら。今回のリリースで、エディター自体を含むすべての管理ルートに対して同じことを行う httpAdminMiddlewareを追加します。

これは例えば、すべての管理リクエストにカスタム http ヘッダーを追加するため使用できます。ほとんどのエンドユーザーが必要とするものではありませんが、独自のアプリケーションにエディターを埋め込むユーザーのための機能です。

詳細 (英語)を参照してください。

カスタムadminAuthトークンの処理

adminAuthは、admin api に渡された認証トークンの検証に使用できる、カスタムトークン関数をサポートするようになりました。これにより、Node-RED 管理セキュリティを他の認証システムと統合するため、いくつかのより柔軟なオプションを利用できます。

詳細 (英語)を参照してください。

他の場所からのノードのインストール

新しいノードをインストールするための管理 API が拡張され、「url」パラメータをサポートするようになりました。これは、インストールするノードを含む tgz ファイルへの完全な URL である必要があります。

これはまだドキュメントに記載されていませんので、現時点では、元のデザインノートを参照してください。

HTTPS証明書の更新

https 証明書を定期的に更新するようにランタイムを構成できます。この機能の利用には、Node.js 12以降が必要です。

デフォルト設定ファイルは、この構成に関するサンプルを含んでいます。

詳細 (英語)を参照してください。

ノードの更新

JSONata $moment のサポート

$moment関数により、JSONata 式内のモーメント日付/時間ライブラリのサポートを追加しました。

これにより、Node-RED のコアに、以前から要望のあったタイムゾーン認識が追加されます。例えば次の式でオークランドの現在の時刻を取得できます:

$moment().tz("Pacific/Auckland")

2時間後の時刻を取得したい場合は、次のように記述できます:

$moment().add(2, "hours")

また日付の解析で、より良い処理ができます:

$moment($.payload, "YYYY-MM-DD")

Moment ライブラリを Function ノードのデフォルトの組み込みとして利用可能にすることも検討していますが、これは将来のリリースで対応予定です。

※ JSONata に関しては、以前に 言語ガイドを翻訳しましたので、ご参照ください

ノードのプロパティを挿入する

Inject ノードは、送信するメッセージに任意のプロパティを設定できるようになりました。topicpayloadだけに限定されません。
image.png

Function ノードのライフサイクル

Function ノードでは、ノードのデプロイ時と停止時に実行する必要のあるコードを提供できるようになりました。 これにより、メッセージの処理を開始する前にノードの状態を初期化できます。
image.png
コードの各部分は別々のスコープにあることに注意してください。どれかの中で変数を宣言して、他からアクセスすることはできません。それらの間で情報を共有するには、コンテキストを使用する必要があります。

メイン関数も非同期になっているので、トップレベルで await を使用できます。

Debug ノードのステータス

Debug ノードは、Debug サイドバーに何を渡すかに関係なく、ステータスメッセージを設定できるようになりました。スペースのあるサイドバーに完全な情報を表示しながら、ステータスの短い要約をデバッグする場合に役立ちます。
image.png
デバッグノードについて補足ですが、多数のノードを一度にアクティブ化/非アクティブ化できるように、エディターにいくつかのアクションを追加しました。

アクションリスト (Ctrl / Cmd-Shift-Pまたは表示->動作一覧) でそれらを検索し、キーボードショートカットを割り当てることができます。

  • core:activate-selected-debug-nodes
  • core:activate-all-debug-nodes
  • core:activate-all-flow-debug-nodes
  • core:deactivate-selected-debug-nodes
  • core:deactivate-all-debug-nodes
  • core:deactivate-all-flow-debug-nodes

image.png

トリガーノード

トリガーノードは、オプションで別の出力に「2番目のメッセージ」を送信できるようになりました。
image.png
メッセージの個別のストリームを処理する場合、msg.topicを使用してストリームを識別する必要がなくなります。任意のメッセージプロパティを使用できます。

というわけで

Node-RED どんどん使いやすく改良されていく感じで、良いですね!更新された機能、実際にいろいろ試してみたいと思っています。

それではまた!

webpack.config.js の書き方をしっかり理解しよう

$
0
0

webpack.config.js

僕の中で少し苦手なイメージのあるwebpackについて、改めて向き合って理解していこうと思います。
webpackに苦手意識がある人のほとんどは、このwebpack.config.jsについて理解していない人がほとんど。なので、今回は下記のwebpack.config.jsについて丁寧に説明していきます。

webpack.config.js
constpath=require('path')constwebpack=require('webpack')module.exports={entry:{index:path.join(__dirname,'src','index.js')},output:{path:path.join(__dirname,'out'),filename:'main.js'},devtool:'cheap-module-eval-source-map',target:'node',module:{rules:[{test:/.js$/,loader:'babel-loader'}]},plugins:[externalPlugins]}

entryoutput

結論から言うと、
entry:は、webpackがビルドする際に開始点となるJSファイルを設定しています。
output:は、ビルドファイルの設定。どこにどのようなファイルを出力すればよいか設定しています。

具体的にみていきます。

webpack.config.js
constpath=require('path')constwebpack=require('webpack')module.exports={entry:{index:path.join(__dirname,'src','index.js')},output:{path:path.join(__dirname,'out'),filename:'main.js'},...}

entryの設定

早速説明していきます。
簡単に理解できますので、安心してください(笑)

ここでは、webpackがビルドした際に
./src/index.jsというファイルを探して読み込んでね。」という設定をしています。

まずpath.joinでパスを連結してくれていて、上記だと./src/index.jsというパスにしてくれています。

これを使うメリットとしては、
macやwindowsなどの開発環境によって/¥になったりするんですけど、それを防ぐことができます。
そしてNode.jsの標準モジュールのpathを読み込ませて使用しているので、path.joinとして使用できています。

__dirnameNode.jsで用意されているグローバル変数で、現在実行中のソースコードが格納されているディレクトリパスが格納されています。簡単に言うと、手軽に絶対パスの記述ができるものです。

outputの設定

path:filename:がありますね。

こちらも結論から言うと
path:は、どのディレクトリに出力するか指定しています。
filename:は、どのファイルに出力するか指定しています。

なので、
./srcというディレクトリ内のmain.jsというファイルに出力してね。」という設定をしています。

devtool

まず、結論です。
devtool:を設定することによって、ソースマッピングのスタイルを選択して、デバッグプロセスを強化します。指定可能な値はstringfalseです。
(参照:公式ドキュメントのdevtool

分からない用語が出てきた?ソースマッピングですかね?

分からなければ、しっかり調べていきましょう。

ソースマップについて

ソースマップとは、Babelなどトランスパイル後と前のコードの内容を紐付けしてデバッグしやするするもの。

トランスパイルについて
JavaSciprtではwebpackでコンパイルなどをする時に同時にトランスパイルという処理を行います。
具体的に何をしているのかというと、互換性のあるコードに変換をする処理。
(例)「CoffeeScriptとかを記載して、Javascriptへトランスパイルする。」みたいな感じです。
一般的にはBabelというライブラリを使います。

devtool: 'cheap-module-eval-source-map'

まとめると、ここでは'cheap-module-eval-source-map'を設定しており、公式ドキュメントによると、ビルドと再ビルトの処理速度としては遅めに処理されるようです。

webpack.config.js
...module.exports={...devtool:'cheap-module-eval-source-map',...}

target

結論から言うと、
target:を設定することによって、特定の環境をターゲットにするようにwebpackに指示してくれます。ここでは、'node'と設定しているので、Node.jsのような環境で使用するためにコンパイルしてます。

webpack.config.js
...module.exports={...target:'node',...}

module

module:オプションは、プロジェクト内のさまざまなタイプのモジュールがどのように処理されるかを設定しています。「webpack が特定のmoduleをどう扱うか」を決めるってことです。webpack ではmoduleJavaScriptCSSなどのファイルを指す。
ここでは、Ruleモジュールについて設定されているので、詳しくみていきます。

webpack.config.js
...module.exports={...module:{rules:[{test:/.js$/,loader:'babel-loader'}]},...}

Rule

まず結論から、
rule:を設定すると、「条件」、「結果」、「ネスト」されたルール3つの部分に分けることができます。

Rule.test

公式ドキュメントによると、テストアサーションに合格したすべてのモジュールを含めます。 Rule.testオプションを指定した場合、Rule.resourceも指定できません。
と書いてありましたが、ちょっと「??」のままでした。

いろいろ調べてみた結果を簡単にいうと、
Rule.testで拡張子を設定する」というイメージです。
webpackでいうmodule(JavaScriptCSSなど)を設定するってことです。
今回で言うと、拡張子が.jsなので、test: /.js$/と設定しています。

このまま一気に説明した方が理解がしやすいと思うので、一気に説明していきます。

Rule.loader

この2つですが、簡単にいうと
まずloader: 'babel-loader'と設定することで、test: /.js$/で設定したjsファイル'babel-loader'として読み込む設定をしています。

plugins

最後plugins:です。
pluginsオプションは、さまざまな方法でwebpackビルドプロセスをカスタマイズするために使用されます。externalPluginsというプラグインがカスタマイズされています。

公式ドキュメントによると、
webpackには豊富なプラグインインターフェイスがあります。 webpack自体のほとんどの機能は、このプラグインインターフェイスを使用します。これにより、Webpackが柔軟になります。

最後

最後の方は駆け足で説明することになりましたが、少しでも理解の手助けになれば幸いです。
こんなことを最後にいうことではありませんが、webpackについては公式ドキュメントに結構丁寧に説明が書いてあるので、そこをみれば理解できるかと思います。

何か間違い等ありましたら教えていただけると幸いです。


npm ERR! code ELOOP が出たときの対処法

$
0
0

npm install を使った時に

npm WARN checkPermissions Missing write access to /Users/[ユーザー名]/node_modules/[ファイル名]
npm WARN [ユーザー名]@1.0.0 No description
npm WARN [ユーザー名]@1.0.0 No repository field.
npm ERR! code ELOOP

というエラーが出現してハマりました。これを仮説で解決できたので同じエラーでハマった方向けに書いておきます。

まず一番上にnpm WARN checkPermissions Missing write access to /Users/[ユーザー名]/node_modules/[ファイル名]

と書いてあります。

この意味は「ファイルにアクセスできない」という意味です。

この理由として考えられるのは

①ファイルへのアクセス権が無い
②ファイルそのものが無い
③ファイルパスがおかしい

のどれかです。

①の場合の対処法は公式にも書いてあります。

https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally

ただこれはエラーコードが違いますし、実際にやってみても治りませんでした。

②の場合はファイルをどうにかして追加できれば治りそうですが、この場合ではインストールそのものができないので解決は無理です。

そこで、Node.jsを一旦全て削除することにしました。(パスを書き換えるだけで解決できそうでしたが、ファイルの場所がよく分からないのと確実に治すためにそうしました。)

/Users/[ユーザー名]/node_modules/[ファイル名]
に関連するファイルを全て削除しました。

具体的には

.npm-global
.nodebrew
.npmrc
.zprofile
.node-modules

の5つです。

さらに、
https://qiita.com/gaipoi/items/406d6c4b1ccd1733318a
に従ってNode.jsを全て削除しました。

その後インストーラーでNode.jsを再インストール。

最後にターミナルで
export NODE_PATH=/usr/local/lib/node_modules
を打ち込むと解決できました。

おそらく前に他のパッケージをインストールする時にパスを弄ったのが原因ではないかと思っています。

コマンドラインからjavascriptでレンダリングされたHTMLソースを取得する方法

$
0
0

curlからは、javascriptを有効にしたブラウザと同じHTMLソースを取得することが難しいことがあります。このような場合、phantomjsを使用すると便利です。

$ npm i -g phantomjs phantom

公式サイトにてバイナリも配布されてるので、nodeからのインストールが依存関係などで失敗する場合、こちらをダウンロード、解凍して実行権限を与えると良いでしょう。

https://phantomjs.org/download.html

$ curl -sLO https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2
$ aunpack phantomjs-2.1.1-linux-x86_64.tar.bz2
$ cd phantomjs-2.1.1-linux-x86_64/bin/
$ chmod +x phantomjs
$ ./phantomjs --version
set.js
varsystem=require('system');varpage=require('webpage').create();argumentvarurl=system.args[1];page.open(url,function(){console.log(page.content);phantom.exit();});
$ phantomjs set.js https://google.com

curlを使ってjavascriptを有効にした場合のhtmlソースを取得する

$
0
0

domcurlというツールがあります。webscrapingに非常に便利なツールです。phantomjsなどで要件を満たせない場合におすすめです。

domcurlはPuppeteerを使う小さなNodeJSアプリケーションで、 npm i domcurlコマンドを発行することでインストールできます。 curlコマンドのように、簡単なdomcurl [url]を発行してリソースを取得し、JSをページ上で実行することができます。

https://paul.kinlan.me/domcurl/

$ npm i domcurl
$ ./node_modules/domcurl/index.js  --url https://example.com

Vue.jsを使ってFirebaseのデータを削除する

$
0
0

Vue.jsを使ってFirebaseのデータベース firestore のデータを削除する方法をお伝えします。

概要確認

こんな感じのfirestore のデータベースがあります。
スクリーンショット 2020-07-05 11.48.46.png

このときHPはこんな感じです。
スクリーンショット 2020-07-05 11.47.26.png

今回のゴールはHP上の×ボタンを押したらデータベース上のデータも連動して消えるです。

手順

このゴールを達成するためには以下の手順でコードを書いていきます。

  1. ×ボタンを押すとindexをトリガーに、その項目のidをゲットする
  2. その項目のidを変数に設定
  3. さらにその変数をトリガーにして、削除ボタンで項目削除

1. ×ボタンを押すとindexをトリガーに、その項目のidをゲットする

削除ボタンを押すとその項目のindexをゲットします。

book-management.vue
<trv-for="(book, index) in books":key="book.bookId"><td><inputv-model="book.title"type="text"/></td><td><inputv-model="book.type"type="text"/></td><!-- レンタルの可否 --><td><selectv-model="book.rental"><optionv-if="book.rental === 'ok'"value="ok">
                OK
              </option><optionv-elsevalue="ng">
                NG
              </option></select></td><!-- 所在 --><td><inputv-model="book.currentPlace"type="text"/></td><!-- レンタルボタン --><td><buttonv-if="book.rental === 'ok'"type="button"@click="onRentBookClick()">借りる
            </button><pv-else-if="book.rental === 'ng' && book.currentPlace !== '自分'">レンタル不可
            </p><buttonv-elsetype="button"@click="onReturnBookClick()">返す
            </button></td><!-- 所有者 --><td><inputv-model="book.owner"type="text"/></td><!-- 削除ボタン --><td><buttonclass="delete"@click="switchDelateAlarm(), getIndex(index)">×
            </button></td></tr>

上記の中にあるコチラ↓

book-management.vue
<buttonclass="delete"@click="switchDelateAlarm(), getIndex(index)">×
</button>

2. その項目のidを変数に設定

ここから関数getIndex()に引数indexを渡します。

そして関数getIndex()はコチラ。

book-management.vue
    getIndex(index) {
      this.delateId = this.books[index].id
    },

これによりdelateIdが定義されました。

3. さらにその変数をトリガーにして、削除ボタンで項目削除

さて、下記の1番上の×ボタンを押します。

スクリーンショット 2020-07-05 11.47.26.png

すると、このようなポップアップが出ます。

スクリーンショット 2020-07-05 12.07.54.png

実は×ボタンを押すことで関数getIndex()以外にもうひとつ関数switchDelateAlarm()が起動するようになっています。

このポップアップはそれによるものです。

次はこのポップアップ上の削除ボタンを押すと実際に項目が削除されるようにしていきます。

下記がポップアップのtemplateです。

book-management.vue
<divv-show="showDelateAlarm"id="overlay"><divid="delateAlarm"><p>この本の情報を削除します</p><button@click="switchDelateAlarm">戻る
        </button><button@click="switchDelateAlarm(), deleteItem(delateId)">削除
        </button></div></div>

関数deleteItem()の引数に先ほど定義した変数delateIdを渡していますね。

では関数deleteItem()の内容はというと……

book-management.vue
    deleteItem(deleteId) {
      db.collection("books").doc(deleteId).delete()
    }

こんな感じです。

まとめ

以上でfirestoreと連動した削除ボタンの完成です。

Node jsでCMSを作る part1

$
0
0

はじめに

この記事は僕がNode jsでCMSを作りながらメモ代わりに更新していく予定です。
なので過度な期待はしないでください。

作りたいもの

速度に全振りした低スペックでも動くCMS

要件定義を決める

さて、作ると決めたもののどうしよう状態に陥ったのでCMSの作り方を調べてみた。

CMSを検討する際に一番大事なこと!
CMS構築をするうえで一番重要なことは、ずばりこの一言に尽きます!
【要件定義をしっかりと、漏れなく、実施すること】
です。
下の解説で、なぜ要件定義が必要なのか、わかると思います。

と書いてあったので要件定義したいと思います。

機能面の要件定義

要件定義なんてしたことないので、テキトーに書いていきます

必須

サイトを公開できる
HTML,Markdown,独自のエディタでページを書ける
プラグインなどを読み込める
ページごとにjavascript,cssを設定できる
高度な高速化機能を搭載している
word pressの記事を読み込める
pjaxを標準搭載

あればいいかな的なもの

テーマを読み込める
IoTなどと連携できる

動作環境の要件定義

conohaのRAM1GBプランで快適に動作できる
Node js 12

こんな感じでいいんですかね?(言いわけない)

終わりに

とりあえず今日はここまでにします。
少しずつ作っていくので、アイデアや意見があれば教えてほしいです

Node.jsのAPIをまとめてみた

$
0
0

はじめに

先週ぐらいからNode.jsの参考書を読み始め、途中から
■■ = require('〇〇')
というのが連発してきて、いろんな種類のAPIが使えるのだと知りました。

参考書の最初は「require('events')」や「require('http')」を使っていて、
他にどんなAPIが使えるのか気になり、一覧としてまとめてみました。

※初学者のため誤りがあると思います。
 間違いはコメントしていただけると幸いです。:bow_tone1:

本題の前に

本題の前に、「require」について少しだけ触れておきます。

requireとは、モジュール化されたJavaScriptのファイルをNodeから読み込んで利用できるようにしてくれるものです。

npmを使ってインストールしてきたパッケージを利用する際にもこの「require」を使用します。

著者は普段、C言語を使用していますので、この「require」はC言語のインクルードみたいなものだと理解しています。(あくまでもイメージです。)

本記事は、Nodeをインストールしたらデフォルトで使用できるモジュールについて一覧にしてみました。

Nodeモジュール一覧

下表はNode.js v12.18.2 ドキュメントを参考にまとめました。
公式ドキュメントにはそのAPIの安定性が記載されています。
簡単にまとめると、

安定性:0 - 非推奨
安定性:1 - 実験的
安定性:2 - 安定
(詳しくは ⇒ 公式ドキュメント)

使いたいAPIは、「require('下表のAPI名')」を書けば使えます。

APIAPI名安定性説明
Assertion Testingassert2アサーションモードの使用
Async Hooksasync_hooks1非同期リソースの追跡
Bufferbuffer ※12バイナリデータを一連のバイト形式に変換
C++ Addons./build/Release/addon ※22C++で記載されたアドオンをロード
Child Processeschild_process2子プロセスを生成
Clustercluster2サーバポートを共有する子プロセスを生成
Consoleconsole ※12単純なデバッグコンソール
Cryptocrypto2暗号化機能
DNSdns2名前解決
Domaindomain0複数の異なるIO操作の処理
Eventsevents2イベント処理
File Systemfs2ファイルシステム操作
HTTPhttp2HTTPインタフェース
HTTP/2http22HTTP/2プロトコルの実装
HTTPShttps2httpsインタフェース
Inspectorinspector1V8インスペクターとの対話
Netnet2TCPまたはIPCサーバ・クライアントの作成
OSos2OS関連のユースティリティ
Pathpath2ファイルおよびディレクトリパス操作
Processprocess ※1記載なしプロセス制御
Punycodepunycode0Punycodeモジュールのバンドル
Query Stringsquerystring2食える文字列の解析及びフォーマット
Readlinereadline2ストリームから1行ずつデータ読み取り
REPLrepl2REPLの実装
Streamstream2ストリーミングデータの操作
String Decoderstring_decoder2文字列にデコード
Timerstimers ※12スケジュール操作
TLS/SSLtls2TLSおよびSSLプロトコルの実装
Trace Eventstrace_events1トレースイベント操作
TTYtty ※32tty操作
UDP/Datagramdgram2UDPデータグラムソケットの実装
URLurl2URL解決および解析
Utilitiesutil2APIのユースティリティ
V8v8記載なしV8固有のAPI
VMvm2V8仮想マシン
Worker Threadsworker_threads2スレッド作成
Zlibzlib2圧縮機能

※1. グローバルスコープ内にあるため、requireを使用する必要はほとんどない
※2. build/Release/addon.nodeという名前でアドオンが作成
※3. ほとんどの場合、直接操作する必要はない

さいごに

調べてみると、使っていないAPIがたくさんあることに気づきました。
フレームワークもたくさんあるのでそこら辺も一回整理したいですね。

参考

Node.js: Starttls でメールの送

$
0
0

こちらと同じことを Node.js で行いました。
Python3: Starttls でメールの送信
hi-ho.ne.jp で試しました。

hi-ho.js
#! /usr/bin/node
////  hi-ho.js//// ---------------------------------------------------------------'use strict'constdotenv=require('dotenv')constnodemailer=require('nodemailer')console.error("*** 開始 ***")dotenv.config()constenv={server:`${process.env.SERVER}`,port:`${process.env.PORT}`,usr:`${process.env.USR}`,password:`${process.env.PASSWORD}`,from:`${process.env.FROM}`,to:`${process.env.TO}`,}console.log(env.from)console.log(env.to)// create reusable transporter object using the default SMTP transportconsturl='smtps://'+env.usr+':'+env.password+'@'+env.servervartransporter=nodemailer.createTransport(url)// setup e-mail data with unicode symbolsvarmailOptions={from:env.from,// sender addressto:env.to,// list of receiverssubject:'Hello Jul/05/2020 PM 14:26',// Subject linetext:'Hello world PM 14:26 plaintext',// plaintext bodyhtml:'<b>Hello world PM 14:26 html</b>'// html body}// send mail with defined transport objecttransporter.sendMail(mailOptions,function(error,info){if(error){returnconsole.log(error)}console.log('Message sent: '+info.response)console.error("*** 終了 ***")})// ---------------------------------------------------------------
.env
SERVER = 'hi-ho.mose-mail.jp'
PORT = 587
USR = '****@hi-ho.ne.jp'
PASSWORD = '****'
FROM = '****@hi-ho.ne.jp'
TO = 'sample@example.com'

実行結果

$ ./hi-ho.js
*** 開始 ***
****@hi-ho.ne.jp
sample@example.com
Message sent: 250 2.0.0 0622YNNb088216 Message accepted for delivery
*** 終了 ***

console.logで配列やオブジェクトが省略されてしまうときはconsole.dirを使おう

$
0
0

console.dirの第2引数にオブジェクト{depth: null}を渡すと深い階層も省略されずに全部見れます。

Node.js console.dir

constmenu={main:{currey:500,udon:450,rice:150},side:{soup:{misoshiru:{wakame:250,asari:250},potage:{corn:250,potato:250}},dessert:{icecream:{vanilla:100,chocolate:100}}}}console.log(menu)/*
{
  main: { currey: 500, udon: 450, rice: 150 },
  side: {
    soup: { misoshiru: [Object], potage: [Object] },
    dessert: { icecream: [Object] }
  }
}
*/console.dir(menu,{depth:null})/*
{
  main: { currey: 500, udon: 450, rice: 150 },
  side: {
    soup: {
      misoshiru: { wakame: 250, asari: 250 },
      potage: { corn: 250, potato: 250 }
    },
    dessert: { icecream: { vanilla: 100, chocolate: 100 } }
  }
}
*/

Node.js + Express + PhpStormでWordpressの投稿をWP REST APIを使って表示する

$
0
0

PhpStormでNode.js Express Appを新規作成

File -> NewProject -> Node.js Express App

この時のオプションは以下の通りです。
Options
- View Engine: EJS
- Stylesheet Engine: Plain CSS

terminalで WP APIをインストール

npm install wpapi --save

routes/index.jsを編集

varexpress=require('express');varrouter=express.Router();varWPAPI=require('wpapi');varwp=newWPAPI({endpoint:'https://localhost/my-local-test/wp-json/'});/* GET home page. */router.get('/',function(req,res,next){wp.posts().then((posts)=>{console.log(posts);res.render('index',{title:'Express'});});});module.exports=router;

エンドポイントを登録して、

varwp=newWPAPI({endpoint:'https://localhost/my-local-test/wp-json/'});

getリクエストの処理を書きます。

router.get('/',function(req,res,next){wp.posts().then((posts)=>{console.log(posts);res.render('index',{title:'Express'});});});

ローカル環境では取れましたが、やりたいサイトではエラーがー出てしまってます。

(node:25928) UnhandledPromiseRejectionWarning: TypeError: Cannot create property '_paging' on string ''
    at returnBody (C:\Users\Koji\PhpstormProjects\wordpress-api-test\node_modules\wpapi\lib\http-transport.js:244:16)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
(node:25928) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:25928) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

今日はここまで。

GithubのissueをAPI経由で作成する

$
0
0

issue管理大変ですよね。

複数のissueを一気に登録したり、システムと連携してイベントベースでissueを登録できたりすると、issueを管理するのがずっと楽になります。

node.jsで実装しているので、AWS Lambda経由で実行するといろんなイベントから呼び出せて汎用性が高そうです。

使うもの

octkitというGithubAPIクライアントのライブラリを使います。
https://developer.github.com/v3/libraries/

ドキュメントも豊富で使いやすいです。

実装

create_issue.js
const{Octokit}=require("@octokit/rest");constdotEnv=require('dotenv').config();constoctokit=newOctokit({auth:dotEnv.parsed.ACCESS_TOKEN});if(process.argv.length!==4){console.log('タイトルと本文を指定して下さい');return;}octokit.issues.create({owner:'組織名',repo:'リポジトリ名',title:process.argv[2],body:process.argv[3],}).then(({data})=>{console.log(data);}).catch(error=>{console.log(error);});

dotenvを使ってACCESS_TOKENを外から渡せるようにしてあります。

.env
ACCESS_TOKEN=アクセストークン

これでissueを作成できます。

Node.jsを使ったECS上でのTCPアプリケーションの構築

$
0
0

このチュートリアルでは、Alibaba Cloud ECSを使ってTCPクライアント/サーバのペアを作成し、Node.jsを使ってTCPアプリケーションを構築していきます。

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

Alibaba Cloud Tech Share執筆者のKunal Relanによるものです。Tech Shareは、クラウドコミュニティ内で技術的な知識やベストプラクティスを共有することを奨励するAlibaba Cloudのインセンティブプログラムです。

まず基本的なことから説明すると、オープンソースのJavaScriptランタイム環境として人気のあるものに、ChromeのV8 JavaScriptエンジン上に構築されたNode.jsがあります。Node.jsは主にサーバーサイドやネットワークアプリケーションの構築に使われています。TCP (Transmission Control Protocol) は、アプリケーション間でデータのストリームを信頼性の高い、順序立てられた、エラーチェックされた配信を可能にするネットワーキングプロトコルです。双方がデータストリームを交換するためには、TCPサーバがTCP接続要求を受け入れ、接続が確立されなければなりません。

TCP ソケットプログラムには、サーバとクライアントの 2 種類のプログラムを書くことができます。サーバの機能は、クライアントからの接続をリッスンし、処理されたデータを送り返すことです。この通信はソケットを介して行われます。

node.jsのTCPプログラミングにはnetという内部モジュールが必要で、ネットワークプログラミングの非同期ラッパーとして機能します。サーバとクライアントの構築にはAlibaba Cloud Elastic Compute Service (ECS)を使用します。

はじめに

このチュートリアルに従うためには、ubuntuやmacOSなどのlinux/unixディストリビューションが動作するマシン、コードエディタ/IDEのnode.jsがインストールされていること、node.jsの基本的な知識が必要です。このチュートリアルでは、アプリケーションを本番環境にデプロイするのではなく、開発用のマシンで実行し、そこからテストを行います。

TCPサーバの作成

まず、アプリケーションを保存するディレクトリを作成します。このチュートリアルでは、~/nodejs-tcp-appにアプリケーションを作成します。

このチュートリアルでは、ほとんどの作業をターミナルで行います。また、ターミナルでnanoエディタを使用して、すべてのプラットフォームで同じプロセスを保証します。

開始するには、ターミナルを開きます。

mkdir ~/nodejs-tcp-app

さて、新しく作成したディレクトリに切り替えて、npm initを実行してpackage.jsonファイルを作成します。

cd ~/nodejs-tcp-app && npm init

これでターミナルからプロジェクトの基本情報を聞かれるので、server.jsとして名前、作者、メインファイルを追加してファイルを作成します。これでディレクトリ内にpackage.jsonファイルが表示されるはずです。

次に、TCPサーバのコードを含むserver.jsファイルを作成します。

同じディレクトリに以下のコマンドを入力して、server.jsファイルを作成し、テキストエディタを開いてコードを書きます。

nano server.js

まず、node.jsに同梱されているnetモジュールをインポートし、サーバーを実行するポートとホストを定義して、サーバーのインスタンスを作成します。

const net = require('net');
//define host and port to run the server
const port = 8080;
const host = '127.0.0.1';

//Create an instance of the server
const server = net.createServer();
//Start listening with the server on given port and host.
server.listen(port,host,function(){
   console.log(`Server started on ${host}:${port}`); 
});

これはアプリケーションの基本的な構成要素であり、TCP サーバを起動するのに十分なものです。

次に、クライアントが接続する接続にリスナーを追加する必要があります。

サーバの宣言を編集して、onClientConnectionという接続リスナー関数を追加し、下部に関数を宣言します。

const net = require('net');
//define host and port to run the server
const port = 8080;
const host = '127.0.0.1';

//Create an instance of the server
const server = net.createServer(onClientConnection);
//Start listening with the server on given port and host.
server.listen(port,host,function(){
   console.log(`Server started on port ${port} at ${host}`); 
});

//Declare connection listener function
function onClientConnection(sock){
    //Log when a client connnects.
    console.log(`${sock.remoteAddress}:${sock.remotePort} Connected`);
     //Listen for data from the connected client.
    sock.on('data',function(data){
        //Log data from the client
        console.log(`${sock.remoteAddress}:${sock.remotePort} Says : ${data} `);
        //Send back the data to the client.
        sock.write(`You Said ${data}`);
    });
    //Handle client connection termination.
    sock.on('close',function(){
        console.log(`${sock.remoteAddress}:${sock.remotePort} Terminated the connection`);
    });
    //Handle Client connection error.
    sock.on('error',function(error){
        console.error(`${sock.remoteAddress}:${sock.remotePort} Connection Error ${error}`);
    });
};

そこで、onClientConnection関数では、接続オブジェクトのsockを期待して、datacloseerrorの3つのイベントリスナーを作成します。

データイベントリスナーでは、クライアントから受信したdataをコンソールログに記録してクライアントに送信し、closeイベントリスナーでは、接続の終了を処理してコンソールログに記録します。errorイベントリスナーはクライアントからの接続エラーを処理します。

これで server.jsのコードが完成し、これで TCP クライアントの接続を受け入れ、それらのデータをリッスンしてクライアントにエコーバックする TCP アプリケーションが動作するようになりました。ファイルを保存してnanoエディタを終了します。

同じモジュールを使って TCP クライアントを作成してみましょう。

TCP クライアントの作成

nanoコマンドを使ってclient.jsファイルを作成し、作業を開始してみましょう。

nano client.js

server.jsでやったように、netモジュールをインポートして引数を定義してみましょう。

const net = require('net');
//define the server port and host
const port = 8080;
const host = '127.0.0.1';
//Create an instance of the socket client.
const client = new net.Socket();
//Connect to the server using the above defined config.
client.connect(port,host,function(){
   console.log(`Connected to server on ${host}:${port}`);
   //Connection was established, now send a message to the server.
   client.write('Hello from TCP client');
});
//Add a data event listener to handle data coming from the server
client.on('data',function(data){
   console.log(`Server Says : ${data}`); 
});
//Add Client Close function
client.on('close',function(){
   console.log('Connection Closed');
});
//Add Error Event Listener
client.on('error',function(error){
   console.error(`Connection Error ${error}`); 
});

これでclient.jsはサーバーに接続し、接続時にメッセージを送信し、サーバーからのレスポンスをログに記録します。

ここでもサーバと同様に、データ、接続終了、接続エラーを処理するための3つのイベントリスナーを追加しています。

ファイルを保存してnanoエディタを終了します。

接続のテスト

TCPベースのサーバとクライアントアプリの作成が完了したので、サーバを起動してTCPクライアントをサーバに接続する必要があります。

このためには、2つのターミナルセッションが必要です-1つはサーバ用、もう1つはクライアント用です。

最初のセッションでは、次のコマンドを使用してサーバを起動します。

node server.js

このコマンドはTCPサーバを起動し、ターミナルにログが表示されるはずです。

Server started on 127.0.0.1:8080

次に、サーバーに接続してメッセージを送信するためにTCPクライアントファイルを起動する必要があります。別のターミナルで次のコマンドを入力します。

node client.js

これでTCPクライアントが起動し、サーバに接続してメッセージを送信しようとします。さて、あなたのターミナルには次のようなテキストが表示されているはずです。

Connected to server on 127.0.0.1:8080
Server Says : You Said Hello from TCP client

これで、クライアントがサーバに接続できて、ログを記録できるエコーを受信したことがわかりました。

次に、サーバを実行しているターミナルセッションに戻ると、このように表示されるはずです。ただし、クライアントのポートは異なる場合があります。

127.0.0.1:56330 Connected
127.0.0.1:56330 Says : Hello from TCP client 

プログラムでクライアント接続を閉じるわけではないので、close イベントリスナーはトリガーされません。しかし、クライアント端末に戻って ^c を押すと、クライアントは終了し、サーバ端末では接続終了のログを取得することができます。

127.0.0.1:56330 Terminated the connection

TCPサーバとクライアントのテストに成功しました。

結論

このチュートリアルでは、Alibaba Cloud Elastic Compute Service (ECS)インスタンス上でNode.jsを使ってTCPアプリケーションを作成しました。TCPソケットを使ってもっと多くのことができますが、これはその入門的なプログラムでした。これの高度なバージョンでは、TCPサーバを介してメッセージの送受信を可能にするチャットルームにすることができます。また、リアルタイムのデータ通信のための大きなデータストリームの塊を処理するために使用することもできます。

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

Node.js でAWS Lambdaを量産する為のサンプルソースをgithubに公開してみた

$
0
0

AWS LambdaをNode.jsで量産アレコレ

概要

AWS LambdaをNode.jsで書こうと思ったときに、良く思うのが、、、

  • AWS SDKがPromise前提で入れ子が深くなりがち
  • 継承使って汎用共通処理とオーバーライド使いたいなぁ~

である。

コールドスタート対策などで、javaでの実装は圧倒的に不利ってことで、java屋がNode.jsでLambdaを書こうと思うと、きっと同じ事を思うに違いない。(偏見)

という事で、上記が出来る汎用ソースをgithubに公開してみました。

(参考投稿)
Lambdaのコールドスタートを改めて整理する

index.js の処理構造

indexのイメージ.JPG
として、業務処理を全て外だししてシンプルにする事で、汎用的なindex.jsにする。

業務処理の処理構造

業務ロジック階層.JPG

業務処理の継承ツリーは3階層でサンプルは書いてあります。
大体、3階層作ってあれば、大抵の業務は汎化できる。(これまた偏見)

githubの公開場所

サンプルソースの github 公開場所

に置いてあります。

githubからのダウンロード.JPG

イメージ図は、別のサンプルですが、クリックする場所は一緒です。
ダウンロードしたZIPファイルを解凍すると、Lambda登録用のZipファイルが出てきますので、実行する場合は、それをLambdaとして登録してください。

設定可能な環境変数

変数名変数値
LogLevelログの出力レベルを(0~4)までの間で設定する
autoFunctionRetry省略したらエラー時再実行はしない。0より大きい値(数字)を設定すると、その回数、再実行を行う

他サンプルソース

具体的な、

  • API Gateway + Lambda + DynamoDB のサンプルソース
  • DynamoDB Stream + Lambda + SNS のサンプルソース

などは、ブログにて公開中です。

Viewing all 9063 articles
Browse latest View live