- 投稿日:2020-12-08T22:34:34+09:00
UdemyでNode.jsとExpressを学んでみて
この記事は
「あなたの学びをシェア!2020年までにUdemyで学んだこと03【PR】Udemy Advent Calendar 2020」
に向けて書きました。
8日目の記事となります。自分の経験等
・Laravel + Vue.jsの構成を自主学習と実務合わせて約1年程度
受講した講座
Node.js + Express で作る Webアプリケーション 実践講座
https://www.udemy.com/course/web-application-with-nodejs-express/講師:津郷 晶也 氏
総時間:14時間1分受講前に知っておくと良い知識
HTTPリクエスト・レスポンス
HTML・CSS
javascript
クライアント・サーバー演習の前にポイントとなる技術については解説をしていただけますが、
まったく知らない状態からだと進めるのは大変なはずです。
javascriptを全く知らない方は先にそちらを学習してから取り組んだ方が良いと思います。受講したキッカケ
実務でLaravel+Vue.jsの構成での開発経験は多少あったのですが、
Node.jsのみでの開発は経験したことがありませんでした。
また、Node.jsを理解することでVue.jsに対する理解も深まるかと感じました。受講して得られる技術・知識
- Node.js
- node_moduleの基本的な使い方, アプリケーションを構築するためのパッケージ
- Express
- Node.js+Expressでのクライアントサイド、サーバーサイドを構築する基本
- EJS
- 各テンプレートエンジンについて(当講座ではEJSを使用します)
- gulp
- タスクランナーについて タスクの作成の仕方
- MongoDB
- NoSQL, Node.js+Express+MongoDBによるCRUD処理, ログイン処理の実装
- Security
- CSRF, XSSなどへの対策
製作出来るもの
一通りNode.js+Expressの基本を学んだ仕上げとして、
画像のようなシンプルな見た目のブログアプリケーションを作成します。
少しカスタムすれば自分だけのブログ・サイトを作ったり、
会員制のSNSサイトを作ったりと応用が色々と効きそうな制作物でした。記事の検索画面
新規記事の作成画面
受講を終了して
講師の方は丁寧に説明するために割とゆっくりと講義をされていますので、
動画での学習に慣れている方は2倍速まで挙げて、ところどころ止めつつ打ち込んでいくようにした方が
スムーズに講義を進めていけるかもしれません。1.75~2倍速で講義を進めていきましたが、コードの打ち込みをトータルで12時間以上掛かりました。
しかし、土日の2日を注ぎ込めば十分に終了できるボリュームで、Node.js+Expressだけではなく
MongoDBやセキュリティの基礎など、Webアプリケーションを製作する上で
必要な知識を広く学習することができましたので、個人的には非常に満足のいく学習となりました。ただし、作成したアプリケーションのデプロイについては触れられていないので、
別途学習する必要があります。次は以下の講義を通じて、Node.jsのアプリケーションのデプロイまで学んでいきたいと思います。
AWSで作るWEBアプリケーション 実践講座
- 投稿日:2020-12-08T22:29:16+09:00
Hexo 4.2.0 から 5.2.0 にアップデートしたら Netlify のデプロイが失敗した話
Hexo 5.x.x リリース
https://hexo.io/news/2020/07/29/hexo-5-released/
According to our benchmark (which we run in every pull request to detect regression), Hexo 5 processed 500 posts in 16 seconds, whereas 4.2.0 processed 300 posts at the same time.
しばらく見ないうちに Hexo のメジャーバージョンが上がって、記事執筆時点では5.2.0がリリースされていました。いろいろ改善されているらしく、特に4系に固執する理由もないのでアップデートすることにした次第です。
まずはアップデート
公式 に従っています。hexo-cli はついでに上げました。このあたりは特に問題なかったです。
hexo-cli の更新
$ yarn global add hexo-cli yarn global v1.22.4 [1/4] Resolving packages... [2/4] Fetching packages... info fsevents@2.1.2: The platform "win32" is incompatible with this module. info "fsevents@2.1.2" is an optional dependency and failed compatibility check. Excluding it from installation. [3/4] Linking dependencies... [4/4] Building fresh packages... warning Your current version of Yarn is out of date. The latest version is "1.22.5", while you're on "1.22.4". info To upgrade, download the latest installer at "https://yarnpkg.com/latest.msi". success Installed "hexo-cli@4.2.0" with binaries: - hexo Done in 2.18s.package.json の修正
- "hexo": "^4.2.0", + "hexo": "^5.2.0",_config.yml 修正
非推奨の設定を修正しています。
- external_link: true + external_link: + enable: trueyarn install 実行
$ yarn install yarn install v1.22.4 warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json. [1/4] Resolving packages... [2/4] Fetching packages... info fsevents@2.1.2: The platform "win32" is incompatible with this module. info "fsevents@2.1.2" is an optional dependency and failed compatibility check. Excluding it from installation. info fsevents@1.2.11: The platform "win32" is incompatible with this module. info "fsevents@1.2.11" is an optional dependency and failed compatibility check. Excluding it from installation. warning hexo-generator-robotstxt@0.2.0: The engine "hexo" appears to be invalid. [3/4] Linking dependencies... [4/4] Building fresh packages... success Saved lockfile. Done in 4.21s.ローカルで確認
hexo s
してローカルで確認した限りは特に問題も見られませんでした。しかしデプロイ時にエラー発生
エラー内容
error hexo@5.2.0: The engine "node" is incompatible with this module. Expected version ">=10.13.0".nodeのバージョンが足りない?
いまいくつなのか
Netlifyのサイトから確認できるデプロイのログによると v8.17.0 でした。たしかに足りてないです。ローカル環境ではv12.16.2を使っていたので失敗しなかったと思われます。ということは Netlify 側での node.js バージョンをどうにかしないといかんてことですね。
Now using node v8.17.0 (npm v6.13.4)Netlify 側の Node.js バージョンをどうにかする
幸いなことに公式サイトであっさりやり方が見つかりました。
https://docs.netlify.com/configure-builds/manage-dependencies/#node-js-and-javascriptいくつかやり方が載ってましたので紹介します。例えば
v12.16.2
を指定するなら以下のようになります。1. 環境変数で対応
ここでは設定ファイルを使っていますが、
Site settings > Build & deploy > Environment > Environment variables
でNetlifyのサイト上で設定するでもOKかと思います。.netlify.tomlNODE_VERSION=v12.16.22. .nvmrc(or .node-version) で設定
プロジェクト直下に
.nvmrc
または.node-version
を作る方法でもOKです。.nvmrc|.node-versionv12.16.2環境変数でも .nvmrc でもどちらでも良いですが今回は
.nvmrc
を追加する方向で対応してみました。再デプロイして無事成功
ログから一部抜粋しています。無事 v12.16.2 でデプロイが実行・終了しました。ページも確認しましたがいまのところHexo5系に上げた影響もなく問題なさそうです。
Attempting node version 'v12.16.2' from .nvmrc Downloading and installing node v12.16.2... Downloading https://nodejs.org/dist/v12.16.2/node-v12.16.2-linux-x64.tar.xz... Now using node v12.16.2 (npm v6.14.4) Site is live ✨ Finished processing build request in 1m37.644297015sもし似たようなことがあったらご参考ください。
参考
- 投稿日:2020-12-08T20:51:38+09:00
Amazon Rekognitionでユーザーがアップロードしたアレな画像を<del>収集</del>ブロックする
AWSのML系のサービスにAmazon Rekognitionというのがあり、画像の認識に使えるAPIが用意されています。
ユーザーからアップロードされた画像をサイト上に表示する場合などに、まあ何というかいろいろとアウトな感じの画像をアップロードされるとよろしくないですね。そこでこのRekognitionを使うと、inappropriateな要素にタグ付けをしてくれます。
実装例
Node/TypeScriptでの実装例です。画像をBufferで受け取って、アウトっぽい画像なら
false
を返します。以下のドキュメントの内容を基にしています。https://docs.aws.amazon.com/rekognition/latest/dg/procedure-moderate-images.html
import * as AWS from 'aws-sdk'; AWS.config.update({ region: 'ap-northeast-1' }); export class RekognitionModerator { public async moderate(image: Buffer): Promise<boolean> { const rekognition = new AWS.Rekognition({apiVersion: '2016-06-27'}); const params: AWS.Rekognition.DetectModerationLabelsRequest = { Image: { Bytes: image, }, MinConfidence: 99.5 }; const res: AWS.Rekognition.DetectModerationLabelsResponse = await rekognition.detectModerationLabels(params).promise(); if (res.ModerationLabels && res.ModerationLabels.length > 0) { return false; } return true; } }ユーザーがアップロードしてきた画像をこのクラスでチェックすれば、いかがわしい画像をブロックできます。登録はさせないけどサーバーのどこかに保存しておく、みたいな邪悪なことをやるのはやめましょう。
いくらなんでもここにテスト用画像貼ると怒られるので貼りませんが、画像いくつか集めてきて試してみると
健全なしずかす絵
{ ModerationLabels: [], ModerationModelVersion: '4.0' }不健全なしずかす絵
{ ModerationLabels: [ { Confidence: 99.9688949584961, Name: 'Explicit Nudity', ParentName: '' }, { Confidence: 99.9688949584961, Name: 'Illustrated Explicit Nudity', ParentName: 'Explicit Nudity' } ], ModerationModelVersion: '4.0' }7ct Kindle版11ページ
{ ModerationLabels: [], ModerationModelVersion: '4.0' }Rekognitionからはこんな感じのレスポンスが返ってきます。
Confidence
は結果の信頼度、どのくらいの精度でアウトなのかを示す数値です。高いほど結果が信頼できるということになります。サンプルコードでは
MinConfidence: 99.5
という指定をしていました。この場合RekognitionはConfidence
が99.5以上の結果しか返さない、という動きになります。ちなみにデフォルト値は50なので相当緩く設定しています。いろいろ試してみた感じ、特に二次元にはわりと厳しいようで、別にR指定が付くような画像でなくても露出度高めの衣装とかだと98とか99とかそんな値が返ってくることが時々あります。二次元の画像を主に扱う場合は99.5あたりを機械検出の閾値にして、後は人間がモデレーションする(適宜巡回する、通報を受け付ける)のが現実的なところかな、というのが個人的な感覚です。
- 投稿日:2020-12-08T19:59:00+09:00
CentOS 8にNode.js 14をインストール(AppStream)
はじめに
Application Stream(AppStream)を利用してCentOS8にNode.js 14をインストール
参考:RHEL8のパッケージ構成 - BaseOSとApplication Stream - 赤帽エンジニアブログ
第4章 新機能 Red Hat Enterprise Linux 8 | Red Hat Customer Portalサポート
本手法で導入した場合、Red Hat Enterprise Linux 8 Application Streams Life Cycle - Red Hat Customer Portalより、2023-04がEOLだと思われる。
それ以降に報告された脆弱性や不具合への対応は実施されない可能性がある。LOG
インストール
# cat /etc/redhat-release CentOS Linux release 8.3.2011 # yum module install nodejs:14 ... 略各種確認
# which node /usr/bin/node # node -v v14.11.0 # yum module info nodejs:14 Failed to set locale, defaulting to C.UTF-8 Last metadata expiration check: 0:02:16 ago on Tue Dec 8 10:56:12 2020. Name : nodejs Stream : 14 [e] [a] Version : 8030020200924204355 Context : 30b713e6 Architecture : x86_64 Profiles : common [d] [i], development, minimal, s2i Default profiles : common Repo : appstream Summary : Javascript runtime Description : Node.js is a platform built on Chrome's JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices. Requires : platform:[el8] Artifacts : nodejs-1:14.11.0-1.module_el8.3.0+516+516d0fc0.src : nodejs-1:14.11.0-1.module_el8.3.0+516+516d0fc0.x86_64 : nodejs-debuginfo-1:14.11.0-1.module_el8.3.0+516+516d0fc0.x86_64 : nodejs-debugsource-1:14.11.0-1.module_el8.3.0+516+516d0fc0.x86_64 : nodejs-devel-1:14.11.0-1.module_el8.3.0+516+516d0fc0.x86_64 : nodejs-docs-1:14.11.0-1.module_el8.3.0+516+516d0fc0.noarch : nodejs-full-i18n-1:14.11.0-1.module_el8.3.0+516+516d0fc0.x86_64 : nodejs-nodemon-0:2.0.3-1.module_el8.3.0+402+6f8dd522.noarch : nodejs-nodemon-0:2.0.3-1.module_el8.3.0+402+6f8dd522.src : nodejs-packaging-0:23-3.module_el8.3.0+402+6f8dd522.noarch : nodejs-packaging-0:23-3.module_el8.3.0+402+6f8dd522.src : npm-1:6.14.8-1.14.11.0.1.module_el8.3.0+516+516d0fc0.x86_64 Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled, [a]ctive
- 投稿日:2020-12-08T18:50:27+09:00
iOSでNode.jsを動かしたい(ついでにWebRTCシグナリングサーバーも)
はじめに
これは Node.jsアドベントカレンダー2020の記事です。実用性皆無のネタ記事ですが、リラックスしてお楽しみください。
twitterで「iPadでLinuxが動く」というツイートを見たことがきっかけで、iPad/iPhone上でNode.jsを動かしてみました。内容は次の通りです。
- iSH Shell で Node.jsを動かす
- Node.jsでWebサーバーを動かし、Safariでアクセスする
- オマケ:WebRTCのシグナリングサーバーを動かして、iPadとiPhoneで通信する
iSH Shell
iSH Shellとは
利用するアプリは、「iSH Shell」(App Store)というアプリです。私は知りませんでいたが、以前からあるアプリのようです。
名前は「Shell」とありますが、実際にはアプリケーションレイヤーでlinuxをエミュレーションしています。利用されているディストリビューションは、Alpine Linuxです。ちなみに使用するには、Bluetoothキーボードがあった方が便利です。
iSH Shellのインストール
普通にApp Storeからインストールします。
中身の確認
- デフォルトのユーザーは root
- /etc/issue をみると、Alpine Linux 3.12
- CPUアーキテクチャーは、i686(インテル系32ビット)
シェルで操作~# whoami root ~# cat /etc/issue Welcome to Alpine Linux 3.12 Kernel \r on an \m (\l) ~# uname -m i686パッケージマネージャーの追加
アプリをインストールした状態では、Alpineのパッケージマネージャー apk はインストールされていません。どうやらApp Storeの規約上、取り除く必要があったようです。
(※2020.12.15現在、App Store版でもapkがインストール済みになったようです)こちらの手順に従い、apkをインストールします。
- GitHub ... https://github.com/ish-app/ish/
- Wiki ... https://github.com/ish-app/ish/wiki
- Tutorial:Installing apk ... https://github.com/ish-app/ish/wiki/Installing-apk
- ※手順はこのページに記載
シェルで操作~# wget -qO- http://dl-cdn.alpinelinux.org/alpine/v3.12/main/x86/apk-tools-static-2.10.5-r1.apk | tar -xz sbin/apk.static && ./sbin/apk.static add apk-tools && rm sbin/apk.static && rmdir sbin 2> /dev/null ~# apk --version apk-tools 2.10.5, compiled for x86.Node.js を動かす
Node.jsのインストール
iSHとapkが用意できたら、念願のNode.jsをインストールします。
~# apk add nodejs ~# apk add npm ~# node -v v12.18.4 ~# npm -v 6.14.62020/12/5現在、node v12.18と、npm 6.14がインストールされました。(※npmは応答が返ってくるまで、時間がかかります。何かのタイムアウトが発生している?)
REPLの利用
さっそくREPL(対話モード)を動かしてみます。
~# node Welcome to Node.js v12.18.4. Type ".help" for more information. > 1+2+3 6 > console.log('Hello Node.js') Hello Node.js undefined > .exit ~#Webサーバーを動かす
次はNode.jsを使って、簡単なWebサーバーを動かしてみます。
server.jsconst http = require('http'); const server = http.createServer((req, res) => { res.end('<html><h1>Hello World!</h1></html>'); }); server.listen(8000);シェルから起動します。
~# node server.jsiPadの場合
iSHがバックグラウンドに回ってしまうと、内部のプロセスの実行が停止してしまいます。そのためiPadの場合はSplit View(Appleの説明)を使って、iSHとSafariを横に並べて使います。
- iSH上で、サーバーを起動
- Split Viewで、Safariを同時に表示
- Safariで、http://localhost:8000/にアクセス
- 「Hello World!」と表示されればOK
iPadなら、そこそこ実用的にNode.jsを動かすことができます。
iPhoneの場合
iPhoneでは、Split Viewが使えず、同時に2つのアプリを動かすことができません。そこで次の手順で無理やり実行します。
- iSH上で、サーバーを起動
- Safarを起動し、http://localhost:8000/にアクセス
- ロード待ちになる
- iSHに切り替えると、サーバーがリクエストを処理する
- 再びSafariに切り替えると、Safari上でページが表示される
リクエストが飛ぶたびに、iSHとSafariを切り替えてやる必要があります。iPhoneではかなり厳しいです。
iSH Shellの制約
iSH Shellではx86をエミュレーとしてLinuxが動いていますが、一部デバイスに近い部分では使えない機能があるようです。具体的には、ネットワーク周りの機能では動かないものがありました。
例えば、Node.jsで次のコードを実行しようとすると、エラーが発生します。コードの抜粋const os = require('os'); const interfaces = os.networkInterfaces();エラーUncaught: SystemError [ERR_SYSTEM_ERROR]: A system error occurred: uv_interface_addresses returned Unknown system error 22 (Unknown system error 22)ネットワークスインターフェイスの情報が取れていないようです。
オマケ:WebRTCのシグナリングサーバーを動かす
ここからは、完全に個人の興味によるオマケです。
WebRTC とシグナリング
Node.js が動くなら、WebRTCのシグナリングを動かしたくなるのが性分です。
- WebRTC ... Web Realtime Communitaion
- Web上で、音声/映像/データをやり取りするための仕組み
- P2Pでのユースケースを想定して規格が作られたが、いまはサーバー経由の利用が増えている
- シグナリング
- これから通信を始める2者が、通信開始に必要な情報を交換するための手続き
- WebRTCではやり方は規定されていない
- サーバー経由で、WebSocket等の双方向通信の仕組みでやり取りすることが多い
ここでは説明は省略します。興味がある方は(ちょっと古いですが)こちらをご参照ください。
- WebRTCハンズオン 概要編 ... https://qiita.com/massie_g/items/916694413353a3293f73
シグナリングサーバーとWebサーバー
よくあるケース
通常はシグナリングのサーバーはローカルネットワーク内のPC上か、インターネット上で動かし、通信したい2つの端末で接続します。
iOSデバイスだけで動かしたい
今回はPC(Mac)やインターネット上のサーバーを利用せず、2台のiOSデバイスだけでシグナリングサーバーを動かし、WebRTC通信を行ってみます。
- iPad と iPad
- または、iPad と iPhone
(不自然ではありますが、そういう縛りのある状況でデモしなければならない、という設定をご想像ください汗)
また、ブラウザでメディア通信で使うカメラ/マイクにアクセスするには、セキュリティ上の制限により次の場所にあるWebページの必要があります。
- https://~
- または、 http://localhost:ポート番号/~
そのため、2台のデバイスそれぞれでWebサーバーは動かします。
iSH でWebサーバー/シグナリングサーバーを動かしてみる
Webサーバー/シグナリングサーバは、Node.js + express + ws(WebSocket) で実装しています。
準備(セットアップ)
- 2台のiOSデバイスを用意 (iPad + iPad, or iPad + iPhone)
- それぞれに、iSH Shell をインストール、apk, node.js もインストール
- それぞれに、gitもインストール
- apk add git
- それぞれに、コードを取得(ブランチを指定してください)
コードを取得~# apk add git ~# git clone https://github.com/mganeko/webrtc_1to1.git ~# cd webrtc_1to1 ~# npm install準備(情報収集)
今回シグナリングサーバー役のデバイス1は、iPadを利用する必要があります。(iSHをバックグラウンドに回さないように)。一方、デバイス2側からは、デバイス1のIPアドレスを知っておく必要があります。
- (A) 両方が、同じWiFi環境にいる場合
- デバイス1側で、割り振られているIPアドレスを確認
- 「設定」-「Wi-Fi」- 詳細情報(iボタン)で、ネットワークの情報を確認
- IPV4アドレスの表から、自分のIPアドレスを取得
- 192.168.0.xxx など
- (B) それ以外の場合
- デバイス1側で、「インターネット共有」(テザリング)をオンに
- デバイス2側で、デバイス1で共有したWiFiに接続
- デバイス2側で、接続情報を確認
- IPV4アドレスの表から、「ルーター」のアドレスを確認
- 172.20.xxx.1 など
- ※テザリングしているデバイス1でなく、そこのぶら下がるデバイス2側で確認します
(A),(B)それぞれに応じた方法で取得したシグナリングサーバー(デバイス1)のIPアドレスを、次のステップで利用します。
実行
(1) サーバーの起動
デバイス1、2の両方で、サーバーを起動します。
起動~# npm start > webrtc_1to1@1.0.0 start /root/work/webrtc_1to1 > node server_1to1.js websocket server start. port=8080 Web server start. http://localhost:8080/(2) SafariでWebサーバーにアクセス
起動したらそれぞれのデバイスでWebサーバーにつなぎますが、デバイスごとにURLが異なります。
- デバイス1(ローカルのシグナリングサーバーに接続する)
- デバイス2(シグナリングサーバーのURLを別途指定する)
- http://localhost:8080/sub.html
- ※デバイス2がiPhoneの場合は、SahariとiSHを交互に切り替えながら、Webページをロードしてください
※iOSデバイスがスリープしてしまうと、サーバーの実行が止まります。再度起動し直してください。
(3) カメラ映像の取得
- デバイス1で、[Start Video]ボタンをタップ
- アクセス許可を求められたら、[許可]をタップしてください
- 同様にデバイス2でも、[Start Video]ボタンをタップ
- アクセス許可を求められたら、[許可]をタップしてください
(4) 接続
接続はデバイス2 (sub.html)側から行います
- デバイス2側で、テキストエリアにシグナリングサーバーのURLを入力
- 例えば、「ws://192.168.0.10:8080」
- ※ポート番号は 8080 です
- デバイス2側で[Connect]ボタンをタップ
- 接続情報が交換され、通信が開始します。
(5) 切断
- デバイス1,2 どちらでも良いので、[Hang Up]ボタンをタップします
- ※この状態で[Connect]ボタンをタップすると、再接続できます
コード
https://github.com/mganeko/webrtc_1to1.git にあります。
おわりに
「iOSでNode.jsを動かしたい」という何の実用性もない記事でした。もし不幸にも(?)そういう状況に陥ったら思い出してみてください。
- 投稿日:2020-12-08T18:07:36+09:00
QRを作ってストレージに置く。
やりたいこと
ある文字列のQRコードを作って、ストレージ上に配置する。
定義と実際に置く
const QRCode = require('qrcode'); const {Storage} = require('@google-cloud/storage'); const bucketName = 'bucket_name'; const storage = new Storage(); const bucket = storage.bucket(bucketName); var filename ='shashin.png'; var filepath = path.join(os.tmpdir(), filename); console.log(filepath); await QRCode.toFile(filepath, 'QRにしたい文字列'); await storage .bucket(bucketName) .upload(filepath, {gzip: false}) .then(res => { console.log(res[0].metadata); console.log(`${filename} uploaded to ${bucketName}.`); }) .catch(err => { console.error('ERROR:', err); });
- 投稿日:2020-12-08T15:33:15+09:00
猪木の名言で元気をくれるbotを作ったら、想定外の応答で笑いが止まらなくなったから、ぜひ試して欲しい。
元気が出ない朝は、猪木さんの出番です。
例えば、月曜日の朝だとか、どうしても『元気が出ない朝』とかってあるじゃないですか。
そんなとき、皆さんはどうされていますか??そんな朝は、やっぱり、猪木さんですよね??
ということで、今回の完成形は以下の通りです。
特に、最後の『ダー!』が、想定の斜め上を行くので、ぜひ皆さん一度ご賞味ください。
クローバーの、最後の「ダー!」がジワるので、最後まで見てください。#protoout#元気があればなんでもできる pic.twitter.com/ryRnjqsweJ
— 北城雅照@足立慶友整形外科 (@kutuyanomusuko) December 4, 2020ちなみにこのボットは、猪木さんの名言をランダムに返してくれるように設定しました。
ランダムに返信するようにも設定完了。
— 北城雅照@足立慶友整形外科 (@kutuyanomusuko) December 4, 2020
「元気が出るbot:猪木名言編」#protoout #元気ですか pic.twitter.com/ZNQQ4Bk05u最後の名言(迷言)『ダー!』は共通です。
では行きましょう。開発環境の下準備
1) VScodeのインストール
VScodeのインストールついては、googleなどで他の記事を検索してください。
2) node.jsとnpmのインストール
Macでの環境作りは、こちらの別の記事にまとめてあります。
参考にしてください。
Macにnode.js,npmのインストール方法今回の開発の手順
開発の手順に関しては、下記の記事を参考に行いました。
是非参考に進んでください。
Clova CEKでのスキル開発の始め方〜Node.jsで開発スタート編〜ハマったところ:スキルがうまく発動しない
スキルを発動する際に、「ねぇクローバー、<スキル名>を起動して。」の声かけで、登録したスキルが発動するのですが、この認識能力が低いように感じます。うまくスキルが発動されない場合は、下記の点を確認してください。
1) スキル名を変更する
スキル名が特定の用語を示す名詞の場合、うまくスキルとして認識されません。
その場合は、「〜bot」と名付けるとうまくいくことがあります。
今回の場合、開発当初はスキル名を「元気があればなんでもできる」にしていました。
そこで、「ねぇクローバー、<元気があればなんでもできる>を起動して。」と話しかけたところ…。
「そうですね!」
とクローバーに明るく返答されました。
クローバー、確かに返答としては正解だけど、機能としては失敗だよ…。2) スキル名と呼び出し方の設定を確認する
CLOVA Develper Center→スキル設定→基本情報とすすみ、
基本情報の中にある、呼び出し名(メインと)
次に、CLOVA Develper Center→スキル設定→ユーザー設定とすすみ、
代表サンプル発話の1つ目の部分のスキル名が必ず一致しているかを確認してください。
この部分が異なっていると、スキルが発動されないので、注意が必要です。
inoki.jsのコード
inoki.jsconst clova = require('@line/clova-cek-sdk-nodejs'); const express = require('express'); const clovaSkillHandler = clova.Client .configureSkill() //起動時に喋る .onLaunchRequest(responseHelper => { responseHelper.setSimpleSpeech({ lang: 'ja', type: 'PlainText', value: '猪木さん、元気ですか?と聞いてください。', }); }) //ユーザーからの発話が来たら反応する箇所 .onIntentRequest(async responseHelper => { const intent = responseHelper.getIntentName(); const sessionId = responseHelper.getSessionId(); console.log('Intent:' + intent); if(intent === 'InokiIntent'){ const slots = responseHelper.getSlots(); console.log(slots); //デフォルトのスピーチ内容を記載 - 該当スロットがない場合をデフォルト設定 let speech = { lang: 'ja', type: 'PlainText', value: `猪木さん、元気ですか?と聞いてください。` } if(slots.inokiwords === '元気ですか'){ switch(~~(5 * Math.random())) { case 0: speech.value = `元気があれば、何でもできる。いくぞー!1、2、3、だー!`; break; case 1: speech.value = `夢を持て!でかければでかいほどいい。とにかく、夢を持て。いくぞー!1、2、3、だー!`; break; case 2: speech.value = `人は歩みを止めたときに、そして挑戦をあきらめたときに、年老いていくのだと思います。いくぞー!1、2、3、だー!`; break; case 3: speech.value = `踏み出せば、その一足が道となる。いくぞー!1、2、3、だー!`; break; case 4: speech.value = `迷わず行けよ。行けば分かるさ。いくぞー!1、2、3、だー!`; break; } } responseHelper.setSimpleSpeech(speech); responseHelper.setSimpleSpeech(speech, true); } }) //終了時 .onSessionEndedRequest(responseHelper => { const sessionId = responseHelper.getSessionId(); }) .handle(); const app = new express(); const port = process.env.PORT || 3000; //リクエストの検証を行う場合。環境変数APPLICATION_ID(値はClova Developer Center上で入力したExtension ID)が必須 const clovaMiddleware = clova.Middleware({applicationId: 'Extention ID'}); app.post('/clova', clovaMiddleware, clovaSkillHandler); app.listen(port, () => console.log(`Server running on ${port}`));応用として
僕は猪木さんの名言で元気になれますが、皆さんの中には、猪木さんの言葉では元気になれない方も変わった方もいらっしゃると思います。
そこで、ご自身の好きな曲をMP3データに変換し、ランダムに再生することも可能です。返答を記載している部分である、
inoki.jsspeech.value = `返答したい言葉`を下記のように書き換えれば、曲の再生が可能です。
inoki.jsclova.SpeechBuilder.createSpeechUrl('MP3のURL')是非ためして見てください。
その他の記事
近すぎると小池都知事が『密です。』と連呼するデバイスを作ったら腹筋が崩壊したので、皆さんにも試して欲しい。
誰が使うかわからないけど、膝のレントゲン写真を送ったら、その膝がどの程度痛んでいるのか教えてくれるラインbotを作ってみた。
- 投稿日:2020-12-08T14:40:28+09:00
Herokuを実行した時のエラー
エラー状況
Node.js(Express)をHeroku実行を試みる。
細かな手順は割愛、Herokuにpushする。
$ git push heroku masterビルドエラー
remote: ERROR in [copy-webpack-plugin] unable to locate '~~~/static' at '~~~/static' remote: remote: Build failed with errors.環境
version Node.js v11.15.0 Heroku heroku-20 原因
プロジェクト直下にある
static
がない。この
static
ディレクトリ、ローカルでは見かけは空のディレクトリ。「いつの間にこんなディレクトリ作ったっけ?」なノリで、削除していた。またstatic
ディレクトリには隠しファイル.gitkeep
があり、消してはいけない(戒め)対処
static
と.gitkeep
を用意してあげる。$ mkdir static $ touch static/.gitkeep
- 投稿日:2020-12-08T14:40:28+09:00
ERROR in [copy-webpack-plugin] unable to locate '~~/static' at '~~/static'
エラー状況
Node.js(Express)をHeroku実行を試みる。
細かな手順は割愛、Herokuにpushする。
$ git push heroku masterタイトルのようなビルドエラー
remote: ERROR in [copy-webpack-plugin] unable to locate '~~~/static' at '~~~/static' remote: remote: Build failed with errors.環境
version Node.js v11.15.0 Heroku heroku-20 原因
プロジェクト直下にある
static
がない。この
static
ディレクトリ、ローカルでは見かけは空のディレクトリ。「いつの間にこんなディレクトリ作ったっけ?」なノリで、削除していた。またstatic
ディレクトリには隠しファイル.gitkeep
があり、消してはいけない(戒め)対処
static
と.gitkeep
を用意してあげる。$ mkdir static $ touch static/.gitkeep
- 投稿日:2020-12-08T09:10:24+09:00
DenoとNodeのDual Package開発
概要
最近 dino というminimalなJS用DIライブラリを作りました。このライブラリはES標準の機能のみで作られているのでDeno/Node/Browserのいずれでも動かせます。しかしコードが動いてもDenoとNodeではパッケージのインストール方法が異なるのでライブラリの公開方法を変えないといけません。
というわけで今回はDeno/Nodeの両方で使えるライブラリを管理する方法を考えていきます。
コードベース
まずDenoとNode.jsの一番の違いとして、モジュールシステムに互換性が無いという点が挙げられます。DenoはESM/TSMのみで構成されており、tsのimportにも対応していますが、Node.jsはCommonJS/ESMという2つの非互換モジュールシステムで構成されています。tsは読み込めません。
ライブラリを公開するにあたってモジュールシステムに互換性がないというのはかなり面倒です。なぜかというと、Deno/NodeのDual Package構成にしようとすると、単一構成のプロジェクトのように普通にコードを書いただけでは対応が出来ません。Deno形式で書いたコードはnpmに公開してもimportできませんし、Node.js形式で書いたものも同様です。
ですので、いずれにしても公開時に何かしらの工夫をしなくてはいけません。
公開先
Nodeの公開先は基本的にはnpmになります。最近ではGithub Package Registryなども選択肢として挙げられます。
Denoの公開先はhttps://deno.land/xが一番簡単です。
アプローチその1: CDNに任せる
この方法が最も簡単です。まずNode/TypeScriptで普通にパッケージを作り、npmに公開します。そのうえで、Denoから読み込む際にjspm.ioなどのCDNから読み込むという方法です。jspm.ioはCommonJSのnpmパッケージをESMに変換してくれるCDNで、ランタイムでNodeへの依存がなければNodeパッケージもDenoで読み込めます。
難点としては、npmへ公開したパッケージの、TypeScriptファイルを直接CDNからimportすることが出来ないという点です。jspm.ioがESM変換を行ってくれるのはpackage.jsonの
main
から参照されているJSファイルのみなので、Denoで普通に読み込んでもTypeScriptの型定義が読み込めません。ちなみにこれはJSファイルにDenoのtriple slash directiveを記述しておけば解決できるかもしれません。
また、明示的にDeno用のファイルを用意しないので、Denoistとしては激おこ案件かもしれません。
アプローチその2: バンドル
2つ目のアプローチは公開ファイルをバンドルする方法です。Denoで書いたファイルをバンドルしてNode.js向けにする、またはNode.jsで書いたファイルをバンドルしてDeno向けにするかのいずれかになります。この方法では、Denoで書いてもNodeで書いてもいいのでかなり楽な方法になります。このアプローチではバンドリングの手法がより整っているNode.jsの方で記述することが好ましいでしょう。
注意点としては、
- バンドルする側にはプラットフォームに合わせて型定義の参照をバンドルファイルに残しておく必要がある
- Deno向けバンドルファイルはESM、Node向けバンドルは
.mjs
になっている必要があるなどの点が挙げられます。また、このアプローチでは開発上バンドルしない方のプラットフォームを優遇するためバンドルする方の開発体験を向上するために面倒なことが多くなるかもしれません。
アプローチその3: mjs
3つ目のアプローチは、Deno/Nodeの区別なくコードをmjs(JS/ESM)で記述することです。以下に例を示します。
mod.mjs/// <reference types="./mod.d.ts" /> import { other } from "./other.mjs" export function some() { return other(); }このように記述したJSファイルは、見た目上DenoとNodeの区別はなく、特別なことをせずにどちらでもそのまま動きます。ブラウザでもimportできるでしょう。
Deno/Node対応JSには、3つの注意点があります。1. JSファイル拡張子を
.mjs
にするJSで書いたファイルを、
.mjs
拡張子にします。mjsはNode.jsがCommonJSとESMを両立するために策定した悲しき拡張子で、jsファイルがCommonJSではなくESMで記述されているということを明示する拡張子です。mjsファイルの中には
module.exports
やrequire
は記述できませんので、モジュールシステム上は、ESMであることが保証されます。そしてDenoでも.mjs
拡張子はサポートされているので(Denoの場合.js
でもESM限定ですが)、JSとして実行が可能になります。2. import文のmodule識別子をDeno形式で書く
module識別子とは、
import { other } from "./other.mjs"の、
./other.mjs
の部分のことです。つまりファイルパスですね。Node.jsのモジュールシステムではCJS/ESMどちらでも./other
という識別子でimportが可能ですが、これだとDenoでは読み込めないので拡張子を省略せずに記述することでDeno Friendlyにします。3. 型定義の用意
使う側がtsの場合を考慮して、mjsファイルごとに型定義ファイルを準備します。
mod.mjs // モジュール mod.d.ts // 型定義このようなファイル構成になっている場合、Node.jsプロジェクトでは
mod.mjs
をimportした場合自動的にmod.d.ts
が読み込まれて補完が効くと思います(エディタによる?)。また、Denoのコンパイル時の型定義参照として、tsのtriple slash directiveを記述します。/// <reference types="./mod.d.ts" />これでファイルごとに型定義のマッピングができます。
なぜTSではダメなのか?
ESMの縛りであれば、tsconfigのmodule設定をesmoduleにしてNodeで書けば良いのではないかと思われるかもしれませんが、Node.js形式のESMでは、モジュール識別子にts拡張子をつけることは出来ません。
// Denoでは有効、Nodeでは無効 import "./other.ts"Nodeで有効な識別子を記述するには以下のようにしますが、
import "./other"これはtscでのコンパイル後も拡張子が無いままになってしまい、Denoで読み込めません。なので、どのアプローチでも同じTSファイルでDeno/Nodeに対応させる書き方は現状ありません。一つの例外を上げるとすれば、import文を使わず、全ての内容を1つのtsファイルに書くことでしょうか。
まとめ
DenoとNodeのDeual Package開発のアプローチを3つ紹介しました。まともな方法が1つもないということがおわかりいただけたでしょうか。そもそもDeno/Nodeの両対応パッケージというものにどういう需要があるのか?という問題もあるのですが、せっかくPure ECMA Scriptで書いたコードが有るのにどちらでも使えるようにする普通の方法がない現状はどうなのかと思うわけです。
DenoとNodeのモジュールの非互換性というのはコードの再利用という観点からはかなり深刻な問題で、どこかの時点で何かしらの統合があっても良いのかなと思います。アプローチ3のように
mjs
で記述すればいいのですが、やはりTypeScriptを使いたい…
- 投稿日:2020-12-08T01:39:00+09:00
AWS Lambda(Node.js)でSORACOMのAPIを使うための準備
AWS LambdaからSORACOMのSIM情報などを取得する場合、Naotaka SaitoさんのSORACOM APIのライブラリを使うと便利です。
本記事は自らの備忘を兼ねて残しておきます。前提
Lambdaでライブラリを使用する場合、Zipファイルでアップロードする必要があるようです。
Zipファイルの作成にはあらかじめNode.js、npmが動作する環境が必要となります。
本記事ではLinux環境(CentOS7)を前提とした手順を説明します。Linuxでの操作
例として、lambdaディレクトリを作成し、Zipファイルを作成します。
mkdir ~/lambda cd ~/lambda npm install soracom_api vi index.js zip -r lambda.zip * mv lambda.zip ../index.jsは適当にデフォルトソースでも書いておきます。
exports.handler = async (event) => { // TODO implement const response = { statusCode: 200, body: JSON.stringify('Hello from Lambda!'), }; return response; };AWSでの操作
作成したZipファイル(例ではlambda.zip)をAWSコンソールを操作するPCにコピーしておきます。
その後の手順は以下の通り。
- AWS ConsoleでLambdaを開き、「関数の作成」をクリックする。
- 「一から作成」を選択し、任意の関数名を指定し、ランタイムで「Node.js …」を選択し、「関数の作成」をクリックする。
![]()
- 「アクション」「.zipファイルをアップロード」をクリックする。
![]()
- 作成しておいたZipファイルをアップロードし、保存する。
![]()
以上でsoracom_apiのライブラリが使えるようになります。
使い方
ライブラリの詳細についてはGitHubのドキュメントを参照してください。
- 投稿日:2020-12-08T00:39:05+09:00
Vue Routerでページを更新or直接アクセス→CannotGETの対処 。Node.js(Express)の例
Vue Routerでページを更新すると
zukan
画面にいるときに、ページをリロードするとみたいになる。
SPAは常にindex.html一枚で処理をしている。
にもかかわらず、URLが見かけ上の
zukan
のPATHにアクセスしようとするため、エラーになる。環境
version Node.js v11.15.0 OS macOS Catalina v10.15.7 プロセッサ Intel Core i5 原因
historyを設定してURLから
#
を削除していると起こる。
ちなみにhistoryとは下で設定したやつ。router.jsconst router = new Router({ mode: 'history', base: process.env.BASE_URL, //...略対処
#
を削除しつつ、問題を解決する方法は公式サイトに解説されている。Node.js(Express)の場合
自分が作ったものがこれだったのでもう少し詳しく。
公式にもあるように、connect-history-api-fallbackを使うと良い。
install
npm install connect-history-api-fallbackserver.jsの例
app.use(history())
を追加する位置に注意。
app.use(serveStatic(__dirname + "/docs"))
よりも後に書くと動作しなくなった。server.jsconst express = require('express') const serveStatic = require('serve-static') const history = require('connect-history-api-fallback') // 追加 const port = process.env.PORT || 5000 app = express() app.use(history()) // 追加 app.use(serveStatic(__dirname + "/docs")) app.listen(port) console.log('server started '+ port)