- 投稿日:2020-03-30T23:45:25+09:00
これからはじめる、Gatsbyのインストールから静的サイトのビルドまで
Gatsbyは次のWordpressとも言われている、Reactベースのオープンソースフレームワーク。
超高速なWebサイトやブログ、アプリを簡単に作ることができ、今最も注目されているCMSツールでもあります。
ここではGatsbyをこれからはじめる人のために、インストール〜静的サイトのビルドまでをサクッと解説していきます。
Node環境のインストール
まずは環境のチェック。nodeは11.10以降にする必要がある。
brew使ってたので、brewでnodeをアップデートする。
node入ってない人はここからダウンロードできる。
brew upgrade node // nodeをインストールしてない場合 brew install nodeインストールできたらnodeのバージョンチェック。
node -v v13.11.0Gatsbyのインストール
npm install -g gatsby-cli gatsby new gatsby-site cd gatsby-site gatsby develop
http://localhost:8000
にアクセス。ページが表示されればOK。静的サイトのビルド(生成)
コマンドで自動的にファイルを作成してくれる。
gatsby buildビルドすると、puglicフォルダに静的サイトが作成される。あとはサーバーにアップすればWebサイトを表示できる。
Gatsbyのスターターライブラリを使ったインストール
Gatsbyはデフォルトだけでなく、ブログやWebサイト、ポートフォリオサイトなどのスターターライブラリがあり、効率よく開発をスタートできる。
スターターライブラリ
https://www.gatsbyjs.org/starters/?v=2ブログを作りたい場合はこちら。
gatsby new gatsby-starter-blog https://github.com/gatsbyjs/gatsby-starter-blogGatsbyのリソース
ドキュメントがしっかりしてるので、そこ見ればだいたいのことはわかる。
プラグインやライブラリなどもリンクされてるので、公式のリソース集はチェックしておきましょう。
最新情報はTwitterやRedditを活用。
- 投稿日:2020-03-30T21:54:12+09:00
discord.js最新版での罠(私的メモ)
discord.jsが11.xから12.xにアップデートされたので自分が引っかかりまくった点をサクッと書いていきます
Nodejsとdjsのバージョン
discord.js 12.xからはどうやらnodejs 12.xからじゃないと出来ないっぽくて見事にハマってました
自分はちょっと都合でnodejs8.10くらいを使ってまして、discord.jsを入れてbotを起動させようとしたら謎の場所でエラー吐いてまして…色々調べてたらバージョン関係で使えなかったことがわかって仕方なくnodejsとnpmを最新版にして使いましたdjsの仕様変更
色々と変わったので自分が知ってる限りの仕様変更部分をまとめます。
xxxs系
xxxs系は
<client>.channels
や<message>.guild.roles
などの複数の情報が入ってるやつです。
11.xでは<client>.guilds.get('channelId')
などで出来たのですが、最新版になって<client>.guilds.**cache**.get('channelId')
と、cacheをつけないとArrayとして認識されなくなれました(xxxsはmanager系になってました、それでcacheにCollection系が移動されたんだと思います。)ボイス系
ボイス系は
<message>.member.voice
です
前のバージョンは<message>.member.voiceChannel.join()
とかだったと思うんですけど、最新版だと<message>.member.voice.channel.join()
になってます。
あとはモジュールの変更ですかね
旧モジュール:
node-opus, ffmpeg-binaries
新モジュール:
@discordjs/opus, ffmpeg-static
opusscriptはまだ使えるかは不明。追記(2020/3/31)
メッセージ関連
最新版djsになって、メッセージを送信する時のやつが完全に消えました
12.xで消えたものconst ch = <message>.channel; ch.sendCode(); ch.sendEmbed(); ch.sendFile(); ch.sendFiles(); ch.sendMessage();これは11.xでもDEPRECATEDが付いていたので多分知ってた人は知ってたと思います。
ついでに、基本メッセージ送信は
<message>.channel.send();
です、リプライは<message>.reply();
です。message系に関して
embedの
RichEmbed
がMessageEmbed
に変更されています。自分的にはこれ使うよりオブジェクト型で書いた方が直感的かなーと思ってたりしてます
embed-sample.js<message>.channel.send({ title: 'Hello', description: 'Discord.js!' });こんな感じの書き方があるのでぜひこの書き方をおすすめしたい
おわり
自分が見てきたとこだとこれくらいですかね、他にもあったような気がするので思い出したら追記しようと思います。
参考
- 投稿日:2020-03-30T21:48:30+09:00
autodetect’: Could not find a JavaScript runtime. See https://github.com/rails/execjs for a list of available runtimes.
masterからサブブランチに切り替えて、
rails sをしたら、
autodetect’: Could not find a JavaScript runtime. See https://github.com/rails/execjs for a list of available runtimes.
とエラー分が表示され、Javascriptになにか関係が??初めて見るエラー分で、何かしたかと思っていると、、、、
最近、何かとこのエラーに遭遇する人が多いだとか、、、、、
私の場合は、masterからサブブランチに切り替えたときに起こりましたが、これはタイミングが被っただけではないでしょうか。
解決策としては、gemfileに
gem 'therubyracer' gem 'libv8'として、bundle installでいけるのかと、思いきやここでエラー分が出たため、node.jsをインストールすることにしました。
一度、上記のgemをインストールできるか試してみてください。
node.jsをhomebrewを使ってインストールする場合は、
brew install nodejsでインストールできます。
見事rails sが可能になりました。
- 投稿日:2020-03-30T17:35:47+09:00
AWS IoT のクライアントデバイス環境を簡単に作るスクリプト(Node.js v2 版)
ちょこっとテストするための、Node.js版のAWS IoT Device SDK v2のPubSubをすぐに試すスクリプトです。CLI上で数行でできます。
Python版はこちら だいたい同じですCloud9上での設定を想定しています。マネコンで作成するのが手間な場合に使います。
何をやっているか等は説明しません。。
あと、手動で何発かメッセージを送るだけであれば、IoT Coreのテスト機能を使うのがよいです。準備
Cloud9 の環境にはUbuntuを選びます。Amazon Linuxだと、
GLIBC_2.25
が無いというエラーが出ております。
Cloud9の環境を作成し、以下をEnvironmentディレクトリ下に置きます。setup-node-v2.shmkdir $THING_NAME cd $THING_NAME POLICY_NAME=${THING_NAME}_Policy aws iot create-thing --thing-name ${THING_NAME} git clone https://github.com/aws/aws-iot-device-sdk-js-v2.git cd aws-iot-device-sdk-js-v2/samples/node/pub_sub/ npm install wget -O rootca.pem \ https://www.amazontrust.com/repository/AmazonRootCA1.pem aws iot create-keys-and-certificate --set-as-active \ --certificate-pem-outfile certificate.pem \ --public-key-outfile public_key.pem \ --private-key-outfile private_key.pem \ --query certificateArn echo -n CERTIFICATE_ARN: read str CERTIFICATE_ARN=$str aws iot create-policy \ --policy-name ${POLICY_NAME} \ --policy-document file://../../../../../policy.json aws iot attach-thing-principal \ --thing-name $THING_NAME \ --principal $CERTIFICATE_ARN aws iot attach-principal-policy \ --policy-name $POLICY_NAME \ --principal $CERTIFICATE_ARNポリシーは適宜修正すべきですが、一旦なんでも有りで。
policy.json{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action":["iot:*"], "Resource": ["*"] }] }実行
npm install aws-iot-device-sdk-v2 aws iot describe-endpoint --endpoint-type iot:Data-ATS export ENDPOINT=yourendpoint-ats.iot.ap-northeast-1.amazonaws.com export THING_NAME=mything ./setup-node-v2.sh cd $THING_NAME/aws-iot-device-sdk-js-v2/samples/node/pub_sub node dist/index.js --endpoint $ENDPOINT --root-ca rootca.pem --cert certificate.pem --key private_key.pem別のThingで試すときは、THING_NAMEを書き換えて実行します。
- 投稿日:2020-03-30T16:43:26+09:00
Node.js(express+ejs)のWebアプリサンプルをDocker上で動かす
はじめに
- Node.jsをDockerで起動し、適当なWeb画面を表示させるところまでをやります
- Node.jsでのサンプルはAkinari Tsugoさんの記事を参考に実装しました
やったこと
- Node.js(express + ejs)の環境をdockerで構築する
- express + ejsを使用したWebアプリサンプルを作成し、docker上で起動させる
使用するフレームワークについて
expressとは
- Node.jsでWebアプリを開発する際に使用するフレームワーク
- 画面遷移とかWebアプリ開発に必要な諸々をサポートする機能あり
- expressの公式はこちら
ejsとは
- JavaScriptでHTMLを作成できるテンプレート言語
- JavaでいうところのJSPに相当する
- ejsの公式はこちら
node.jsをdockerで構築する
Dockerfileの作成
- 鉄板のalpineを選択
- express、ejsのみをnpmで投入
FROM node:alpine RUN npm install express RUN npm install ejs # 作業ディレクトリへ移動 WORKDIR /app # 3000番ポートを公開 EXPOSE 3000docker-compose.ymlの作成
- volumesの設定など、何かとdocker-composeにしておいた方がいいのでdocker-compose.ymlを作成
tty: true
としておくことで、コンテナをずっと起動状態にできるbuild: .
でDockerfileの位置を指定volumes:
の指定で、コンテナ内の/app
をホスト側にもマウントversion: '3' services: app: build: . tty: true container_name: node-sample01 volumes: - ./app:/app ports: - "8080:3000"Webアプリサンプル
ディレクトリ構成
- ディレクトリ全体構成は以下の通り
app/ ├ public/ │ └ 静的なファイル群 ├ routes │ └ index.js ├ views │ └ index.ejs └ app.js Dockerfile docker-compose.ymlapp.js
var express = require('express'); var app = express(); // テンプレートエンジンをEJSに設定 app.set('views', './views'); app.set('view engine', 'ejs'); // public配下の静的ファイルは無条件に公開 app.use('/public', express.static('public')); // URLと処理をマッピング app.use('/', require('./routes/index.js')); // ポート3000で起動 app.listen(3000); // アプリケーション開始時のログ console.log('Server running at http://localhost:3000');index.js
var express = require('express'); var router = express.Router(); // デフォルトルーティング router.get('/', function (request, response) { // パラメータに値を設定、設定したパラメータはejs内で参照可能となる response.render('index', { title: 'NodeSample01', message: 'Hello Node.js' }); }); module.exports = router;index.ejs
- index.jsで設定した
title
とmessage
をejs内で参照<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title><%= title %></title> <link rel="stylesheet" href="/public/bootstrap/bootstrap.css" /> <link rel="stylesheet" href="/public/css/index.css" /> <script type="text/javascript" src="/public/jquery/jquery.js"></script> <script type="text/javascript" src="/public/bootstrap/bootstrap.js"></script> <script type="text/javascript" src="/public/js/index.js"></script> </head> <body> <nav class="navbar navbar-inverse navbar-fixed-top"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Hello Project</a> </div> </div> </nav> <div class="container"> <div class="starter-template"> <p><%= message %></p> <p><img id="img" src="/public/images/drum.jpg" class="img-thumbnail"></p> </div> </div> </body> </html>起動方法
docker-compose up
にてコンテナを起動したら、以下でコンテナにログインdocker exec -it node-sample01 /bin/ash
- コンテナ内でNode.jsを起動
node app.jsサンプル画面の表示
- 投稿日:2020-03-30T11:09:08+09:00
Jest+CircleCIなプロジェクトにCodeCov(カバレッジレポート)を導入するまでの手順ハンズオン
概要
開発環境と構成
- 開発環境
開発言語 JavaScript(ES6)/Node.js テストフレームワーク Jest Gitホスティング GitHub CIツール CircleCI カバレッジレポート CodeCov
- 構成
全体としてはざっくり以下のような構成となりますCodeCovのサインアップとプロジェクト設定
- codecovを開く
まず、CodeCovのサインアップから。
2.プロジェクトはGithubにホストしているのでGithubを選択
3.Githubへのアクセス認可の画面がでるので、Authorize CodeDevをクリック
4.CodeCovの初期画面がでる。
リポジトリがまだ登録されていないのでAdd Repositoryをクリック。
5.Choose a new repository belowという画面がでてレポジトリ一覧が表示される。
「ここで一覧から対象のリポジトリを選択すれば良し」と思ったら、、、すべてのリポジトリが表示されていない模様
6.直接リポジトリを指定する
↑のようなメッセージがでていたので、直接指定することにする。
https://github.com/riversun/event-listener-helper
というリポジトリを設定したかったので、上のフォーマットにならい、https://codecov.io/gh/riversun/event-listener-helper
にアクセスしたら、そのプロジェクトの初期画面が表示される。7.CodeCovのトークンをメモする
初期画面に表示されているトークンをメモしておく。
あとでCircleCIの環境変数に登録する。環境変数名はCODECOV_TOKENとなる。
CircleCI用のconfig.ymlにCodeCov関係の設定を追記する
CodeCov用のOrbがあるので、その利用を前提としてconfig.ymlを編集する
ちなみに、Orbsとは
Orbs とは
CircleCI Orbs は、ジョブ、コマンド、Executor のような設定要素をまとめた共有可能なパッケージです。 CircleCI 独自の認証済み Orbs のほか、パートナー企業によるサードパーティ製 Orbs を用意しています。(出典:https://circleci.com/docs/ja/2.0/orb-intro/)
config.ymlを以下のようにした
version: 2.1 orbs: node: circleci/node@1.1.6 codecov: codecov/codecov@1.0.5 jobs: build-and-test: executor: name: node/default steps: - checkout - node/with-cache: steps: - run: npm install - run: npm test - codecov/upload: file: ./coverage/lcov.info workflows: build-and-test: jobs: - build-and-testポイント
orbsにcodecov: codecov/codecov@1.0.5を追加する
カバレッジレポートファイルのアップロードをするためのコマンドcodecov/uploadを以下のように追記する。
config.yml(抜粋)- codecov/upload: file: ./coverage/lcov.info
- 実際なにやってるか
- codecov/uploadの内部処理ではcurlコマンドでカバレッジレポートファイルlcov.infoをCircleCI(docker)→CodeCovに送信している
- lcov.info(カバレッジレポートが格納されたファイル)は
[root]/coverage/lcov.info
に生成される前提。そのように生成されるようにJestの設定(jest.config.js)を次でする。Jestの設定
念のためにJestの設定をみておく。
やりたいことは以下の2点
- Jestでテストするときにコードカバレッジも計測するようにすること
- コードカバレッジのレポートが目的の場所に生成されるようにすること
ということでjest.config.jsの設定をまるっと掲載すると以下のようになる
jest.config.jsmodule.exports = { verbose: true, testEnvironment: 'jsdom', testMatch: [ "**/test/**/*.test.js" ], testTimeout: 5000, moduleDirectories: [ "node_modules" ], transformIgnorePatterns: [ "node_modules/(?!(@riversun/event-emitter)/)" ], "coverageDirectory": "./coverage/", "collectCoverage": true };本稿で重要なところは以下の部分
jest.config.js(抜粋)"coverageDirectory": "./coverage/", "collectCoverage": truecoverageDirectoryでカバレッジ計測レポートの関連ファイルの生成先を指定する
collectCoverage:trueでテストする毎にカバレッジ計測レポートが生成されるようになる
(jestコマンドに --coverageオプションをつけて、必要なときに生成するアプローチでもアリ)CircleCIでプロジェクトをセットアップする
さてここからCircleCIでプロジェクトのセットアップをしていく。
1. https://circleci.com/ を開いてGo to Appクリック(CircleCI自体のサインアップは割愛)
2.サードパーティ製のOrbsをつかえるようにする
さきほど、CodeCovのOrbを使う記述をconfig.ymlに記述したが、サードパーティ製のOrbsを使うための設定を1度だけやっておく必要がある。
画面左の歯車アイコンをクリックすると、
Organization Settingsという画面がでるので、Allow uncertified orbsをYesにすることで、サードパーティ製Orbsの使用を許可できる。
この設定はプロジェクト横断設定なので1度だけやればOK。
3.プロジェクトを追加する
さて、サードパーティ製のOrbsの許可までできたので、ここでCIしたいプロジェクトを登録する。
以下の画面で、Add projectをクリック
↑の画面じゃなくて、↓の画面の場合もある(↑のほうは新UIのプレビュー版で↓は現行UIという位置づけかな?いずれにせよAdd projectをクリックする。)
自分のプロジェクト一覧からCircleCIしたいプロジェクトのところにあるSet Up Projectをクリック
3.CircleCI用のConfigを追加する
ここでは、CircleCIが「自動でConfig作りましょうか?」とたずねてくれるが、自前のconfig.ymlを作ってPushしてあるので、Add Manuallyをクリック。
4.さっそくビルド
既に「
circleci/config.yml
があるならビルド開始できますよ」というメッセージが出るのでStart Buildingをクリックする。5.予定通りビルド失敗
そして、CircleCI上にて、ビルドが失敗する。
CodeCovの環境変数を設定していないので最初のビルドは失敗した。
6.CodeCov用の環境変数を設定する
さきほどメモしたCodeCovの環境変数を、CircleCIにセットする。
現行UIでは以下のようにプロジェクト名の右にある歯車アイコンをクリックする
Environment Variablesを選択して、Add variableをクリック
ここで環境変数をセットできるので、環境変数名としてNameにCODECOV_TOKENをセット、ValueにはさきほどCodeCovから取得した値をセットしてAdd Variable*をクリック
無事に環境変数をセットできた模様
ちなみに、
CircleCIの新UI(プレビュー版)のほうだと、同様の操作は以下のようになる。対象のプロジェクトのPipelines画面で、Project Settingsをクリック
Environemnt Variablesを選択して、Add Variablesをクリックする
(あ、なるほど。UIレイアウト、デザインは違うけどラベルが一緒なので文字だけのドキュメンテーションにしたら同じ説明で済むようにできてますね)
CircleCIでビルドして、カバレッジレポートをCodeCovでみる
1.CircleCIでビルドする
ここまでで、CircleCIでビルドする準備ができたので、あとはコミット・プッシュするなり、ReRunするなりしてCircleCIを回すだけ。
以下のようにビルドが無事成功した模様。
2.CodeCovでカバレッジレポートを確認する
CodeCovを開き https://codecov.io/gh
さきほど登録したプロジェクトをクリックカバレッジレポートが表示された
Readme.mdにカバレッジ計測バッジをはりつける
CodeCovのプロジェクト画面でSettingsタブでBadgeを選択すると、以下のようにバッジ用のコードがあるので、GithubのReadmeにバッジをつけたいときはMarkdownの内容をコピーして、それをReadme.mdにペーストすればできあがり。
ReadmeにCodeCovのバッジが無事表示された
(本プロジェクトはこちら)まとめ
- 以下のようなJest,CircleCI,CodeCovの組み合わせの導入手順をご紹介しました
- 便利でMotivationalなクラウドサービス群に感謝感謝!
- 投稿日:2020-03-30T03:51:10+09:00
Netlify Functions でジョークアクセスカウンターをつくりました
はじめに
既にホスティングサービスが終了している懐かしの「ジオシティーズ」ですが、スケジュール上では 2020/3/31 に全ファイルの削除が行われるようです。
自分にはジオシティーズ上で 2005年くらいまで更新していたサイトがありましたので、FTP でファイルを救出し Netlify の無料枠にて記念に再ホストすることにしました。
…できたものの何かが足りない。
アクセスカウンターだ!
ということで Netlify に備わる Lambda なサービス Netlify Functions でアクセスカウンターをふとつくってみることにしました。
お気づきのように、Lambda のインスタンスが寝てしまうとカウンターが「飛ぶ」お遊びアクセスカウンターとなっていますが、現代風に JSON や SVG などを使って表示するようになっています。
Netlify Functions について
Netlify Functions は静的ファイルホスティングサービス Netlify が提供する、くだけて言えば Amazon AWS Lambda に対するプログラムの自動デプロイの仕組みで、Netlify のアカウントにて(クレジットカード登録が必要な AWS アカウントなしに)Lambda を利用することができます。
この投稿で分かること
アクセスカウンターの動きはどうだろうという感じですが、いくつかの処理が参考になるかもしれないと Qiita に投稿することにしました。何か使える部分があったら幸いです!
- Lambda でファイルシステムを操作する
- netlify-lambda で追加の webpack.config を構成する
- Lambda で jsdom を使って DOM を操作する
ソースコードと動作デモ
ここで使われているソースコードを github にコミットしてあります。ソース全容を確認しながら読んでいただくと分かりやすいかも知れません。
ソースコード一式
Netlify Functions Template. Includes joke access counter sample program.
動作デモ(しばらくアクセスがないとカウントが
1
に戻ります)Lambda でファイルシステムを操作する
Netlify Functions(Lambda) でも nodejsの
fs
オブジェクトを使ってファイルを操作することが出来ます。
fs
で作成を行ったファイルは、この「アクセスカウンター」の動きどおり、インスタンスのリビルドなどのタイミングで消されますし、スケールした場合は値が分裂しますので、アルゴリズムとしてステートの性質をあてにしてはいけません。API へのアクセス数をカウントする JSON ファイルを
/tmp
に書き込む処理抜粋:import fs from 'fs'; import * as common from '../common' // async await 版の fs オブジェクト const fsp = fs.promises; // カウンターファイル JSON 出力パス const counterJsonFile = common.tmp + "/counter.json"; /** * Lambda エンドポイント */ exports.handler = async (event) => { const now = new Date(); let counterJson = { "createDate": now, "updateDate": now, "count": 1 }; try { // カウンターファイル存在確認 const data = await fsp.readFile(counterJsonFile); // カウンターファイルが存在すれば JSON 解析してカウンターを更新 counterJson = JSON.parse(data.toString('utf-8')); counterJson.updateDate = now; counterJson.count++; } catch(e) { // カウンターファイルがなければ例外を潰して新規作成 } // カウンターファイル書き込み await fsp.writeFile(counterJsonFile, JSON.stringify(counterJson)); // ... }Lambda のハンドラーを
exports.handler = async (event)
とasync
としてfs
の操作はfs.promises
からもらったオブジェクトでawait
してあげると簡単でした。ちなみにこの処理は
readFile
からwriteFile
までに間がありますのでアトミックなカウントアップはできません。また nodejs の fs の実装を確認していませんが、ジオシティーズ世代の CGI カウンターよろしく壊れる可能性もあるでしょうか?(懐かしい)。さて、
/tmp
は Lambda で使えるテンポラリー領域となっていますが、開発を行うローカル環境でそのまま/tmp
にかかれると確認などが面倒なためちょっと小細工をしています。AWS で設定される環境変数の有無で
/tmp
の位置を切り替え:// カウンターファイルを作成するテンポラリーディレクトリ export let tmp = '/tmp' // AWS Lambda で動いていない場合はテンポラリーを dist/tmp に設定 if(!("AWS_REGION" in process.env)) { tmp = "./dist/tmp" try { fs.mkdirSync(tmp); } catch(e) { } }Netlify Functions から提供されている netlify-lambda SDK が
./dist/api
以下にビルドを出力するため、合わせてテンポラリー領域を./dist/tmp
に設定しています。netlify-lambda で追加の webpack.config を構成する
netlify-lambda SDK は内部的に webpack を使ってビルドしていますが、標準の webpack 設定をマージできる
--config
オプションが準備されています。netlify-lambda --config ./webpack.functions.js build src/functions/endpoint本アクセスカウンターでは、古では GIF 画像などで処理していたカウント画像に代わり、SVG/CSS/HTML を Lambda 上で処理し数字を描いてクライアントに返却したく、処理前の
.html
を文字列としてimport
するためraw-loader
を webpack に追加設定しています。// webpack.functions.js module.exports = { optimization: { minimize: false }, module: { rules: [ { test: /\.html$/i, exclude: /node_modules/, use: 'raw-loader' } ], } };この設定によりプログラムから
html
文字列変数としてimport
ができます。// counter.js import html from '../resources/fujilcd.html'このような追加の webpack 設定がある場合は
--config
オプションを活用すると良さそうです。なお、Lambda 上にデプロイするソースをミニマイズしてもあまり意味がないため、どのプロジェクトでもこのコンフィグで
optimization: { minimize: false },
を入れておくとビルド時間短縮に役立つかもしれません。Lambda で jsdom を使って DOM を操作する
nodejs 上で html などの DOM 操作を行う jsdom パッケージを Netlify Functions(Lambda?) 上で使う場合は少々コツが必要なようです。
通常通り
packege.json
に依存関係をいれると、Error while initializing entrypoint: { Error: Cannot find module 'canvas'というエラーで
canvas
パッケージを依存に入れても動作しませんでした。 issue を探ったところワークアラウンドがありましたので、この方法で回避しています。https://github.com/jsdom/jsdom/issues/1708#issuecomment-462990288
I was able to work around this by adding "canvas": "file:./canvas" to the dependencies section of the app's package.json and creating canvas/index.js containing simply module.exports = {}.
プロジェクト上に空の
canvas
モジュールをつくって依存に追加:// package.json { "dependencies": { "jsdom": "^16.2.1", "canvas": "file:./src/functions/canvas", "utf-8-validate": "^5.0.2", "bufferutil": "^4.0.1" }, }
jsdom
が導入できれば、先程 import したような文字列 HTML をnew JSDOM(html)
で DOM 化しウェブブラウザーと同様にdocument.querySelector
などで操作することができます。
import
したカウンター表示 HTMLを DOM 操作して CSS クラスを付けてカウント数を表示:// counter.js function updateLCD(html, number) { const dom = new JSDOM(html); const { document } = dom.window; let countString = number + "" countString = ("0".repeat(maxCount) + number); countString = countString.substring(countString.length - maxCount) for(let i = 0; i < countString.length; i++) { let number = countString.substring(i, i + 1); const digi = document.querySelector(`.digit-${i} svg`); digi.removeAttribute('class'); digi.classList.add(`num-${number}`); } return dom.serialize(); }
jsdom
はdom.serialize();
にてできた DOM を文字列化できますので、これをアクセスしてきたウェブブラウザーに返却し、// counter.js exports.handler = async (event) => { // ... // カウンター数 SVG を生成 counterJson.html = updateLCD(html, counterJson.count); return { statusCode: 200, headers: { "Content-Type": "application/json; charset=utf-8", }, body: JSON.stringify(counterJson) } };ウェブブラウザーは shadowDOM で画面にそのまま書き出しています。
/v1/counter
として Netlify Functions にデプロイした Lambda を呼び出すクライアントのソース:<!DOCTYPE html> <html> <body> <access-counter></access-counter> <script> fetch('/v1/counter').then(function(response) { return response.json() }).then(function(json) { customElements.define('access-counter', class extends HTMLElement { constructor() { super(); const shadowRoot = this.attachShadow({ mode: 'open' }); shadowRoot.innerHTML = json.html; } }) }); </script> </body> </html>終わりに
現代版ジオシティーズとも言える Netlify を今回初めて使ってみたのですが、Netlify Functions 含めいろいろできて便利でした。
試しに検索エンジン API もつくってみましたので、自分のブログになってしまっていますが、気になる方がもしいらっしゃいましたらご覧ください!
Netlify Functions で検索エンジン API をつくる
ふと思いつきまして Netlify で使える Lambda なサービス、Netlify Functions を用いて参照系検索 API を作成してみました。無料枠での挑戦です。
- 投稿日:2020-03-30T03:51:10+09:00
Netlify Functions で古のアクセスカウンター(アクセサリー)をつくる
はじめに
既にホスティングサービスが終了している懐かしの「ジオシティーズ」ですが、スケジュール上では 2020/3/31 に全ファイルの削除が行われるようです。
自分にはジオシティーズ上で 2005年くらいまで更新していたサイトがありましたので、FTP でファイルを救出し Netlify の無料枠にて記念に再ホストすることにしました。
…できたものの何かが足りない。
アクセスカウンターだ!
ということで Netlify に備わる Lambda なサービス Netlify Functions でアクセスカウンターをふとつくってみることにしました。
お気づきのように、Lambda のインスタンスが寝てしまうとカウンターが「飛ぶ」アクセスカウンター(アクセサリー)となっていますが、現代風に JSON や SVG などを使って処理するようになっています。
Netlify Functions について
Netlify Functions は静的ファイルホスティングサービス Netlify が提供する、くだけて言えば Amazon AWS Lambda に対するプログラムの自動デプロイの仕組みで、Netlify のアカウントにて(クレジットカード登録が必要な AWS アカウントなしに)Lambda を利用することができます。
この記事で分かること
アクセスカウンターの動きはどうだろうという感じですが、いくつかの処理が参考になるかもしれないと Qiita に投稿することにしました。何か使える部分があったら幸いです。
- Lambda でファイルシステムを操作する
- netlify-lambda で追加の webpack.config を構成する
- Lambda で jsdom を使って DOM を操作する
ソースコードと動作デモ
ここで使われているソースコードを github にコミットしてあります。ソース全容を確認しながら読んでいただくと分かりやすいかも知れません。
ソースコード一式
Netlify Functions Template. Includes joke access counter sample program.
動作デモ(しばらくアクセスがないとカウントが
1
に戻ります)Lambda でファイルシステムを操作する
Netlify Functions(Lambda) でも nodejsの
fs
オブジェクトを使ってファイルを操作することが出来ます。
fs
で作成を行ったファイルは、この「アクセスカウンター」の動きどおり、インスタンスのリビルドなどのタイミングで消されますし、スケールした場合は値が分裂しますので、アルゴリズムとしてステートの性質をあてにしてはいけません。API へのアクセス数をカウントする JSON ファイルを
/tmp
に書き込む処理抜粋:import fs from 'fs'; import * as common from '../common' // async await 版の fs オブジェクト const fsp = fs.promises; // カウンターファイル JSON 出力パス const counterJsonFile = common.tmp + "/counter.json"; /** * Lambda エンドポイント */ exports.handler = async (event) => { const now = new Date(); let counterJson = { "createDate": now, "updateDate": now, "count": 1 }; try { // カウンターファイル存在確認 const data = await fsp.readFile(counterJsonFile); // カウンターファイルが存在すれば JSON 解析してカウンターを更新 counterJson = JSON.parse(data.toString('utf-8')); counterJson.updateDate = now; counterJson.count++; } catch(e) { // カウンターファイルがなければ例外を潰して新規作成 } // カウンターファイル書き込み await fsp.writeFile(counterJsonFile, JSON.stringify(counterJson)); // ... }Lambda のハンドラーを
exports.handler = async (event)
とasync
としてfs
の操作はfs.promises
からもらったオブジェクトでawait
してあげると簡単でした。ちなみにこの処理は
readFile
からwriteFile
までに間がありますのでアトミックなカウントアップはできません。また nodejs の fs の実装を確認していませんが、ジオシティーズ世代の CGI カウンターよろしく壊れる可能性もあるでしょうか?(懐かしい)。さて、
/tmp
は Lambda で使えるテンポラリー領域となっていますが、開発を行うローカル環境でそのまま/tmp
にかかれると確認などが面倒なためちょっと小細工をしています。AWS で設定される環境変数の有無で
/tmp
の位置を切り替え:// カウンターファイルを作成するテンポラリーディレクトリ export let tmp = '/tmp' // AWS Lambda で動いていない場合はテンポラリーを dist/tmp に設定 if(!("AWS_REGION" in process.env)) { tmp = "./dist/tmp" try { fs.mkdirSync(tmp); } catch(e) { } }Netlify Functions から提供されている netlify-lambda SDK が
./dist/api
以下にビルドを出力するため、合わせてテンポラリー領域を./dist/tmp
に設定しています。netlify-lambda で追加の webpack.config を構成する
netlify-lambda SDK は内部的に webpack を使ってビルドしていますが、標準の webpack 設定をマージできる
--config
オプションが準備されています。netlify-lambda --config ./webpack.functions.js build src/functions/endpoint本アクセスカウンターでは、古では GIF 画像などで処理していたカウント画像に代わり、SVG/CSS/HTML を Lambda 上で処理し数字を描いてクライアントに返却したく、処理前の
.html
を文字列としてimport
するためraw-loader
を webpack に追加設定しています。// webpack.functions.js module.exports = { optimization: { minimize: false }, module: { rules: [ { test: /\.html$/i, exclude: /node_modules/, use: 'raw-loader' } ], } };この設定によりプログラムから
html
文字列変数としてimport
ができます。// counter.js import html from '../resources/fujilcd.html'このような追加の webpack 設定がある場合は
--config
オプションを活用すると良さそうです。なお、Lambda 上にデプロイするソースをミニマイズしてもあまり意味がないため、どのプロジェクトでもこのコンフィグで
optimization: { minimize: false },
を入れておくとビルド時間短縮に役立つかもしれません。Lambda で jsdom を使って DOM を操作する
nodejs 上で html などの DOM 操作を行う jsdom パッケージを Netlify Functions(Lambda?) 上で使う場合は少々コツが必要なようです。
通常通り
packege.json
に依存関係をいれると、Error while initializing entrypoint: { Error: Cannot find module 'canvas'というエラーで
canvas
パッケージを依存に入れても動作しませんでした。 issue を探ったところワークアラウンドがありましたので、この方法で回避しています。https://github.com/jsdom/jsdom/issues/1708#issuecomment-462990288
I was able to work around this by adding "canvas": "file:./canvas" to the dependencies section of the app's package.json and creating canvas/index.js containing simply module.exports = {}.
プロジェクト上に空の
canvas
モジュールをつくって依存に追加:// package.json { "dependencies": { "jsdom": "^16.2.1", "canvas": "file:./src/functions/canvas", "utf-8-validate": "^5.0.2", "bufferutil": "^4.0.1" }, }
jsdom
が導入できれば、先程 import したような文字列 HTML をnew JSDOM(html)
で DOM 化しウェブブラウザーと同様にdocument.querySelector
などで操作することができます。
import
したカウンター表示 HTMLを DOM 操作して CSS クラスを付けてカウント数を表示:// counter.js function updateLCD(html, number) { const dom = new JSDOM(html); const { document } = dom.window; let countString = number + "" countString = ("0".repeat(maxCount) + number); countString = countString.substring(countString.length - maxCount) for(let i = 0; i < countString.length; i++) { let number = countString.substring(i, i + 1); const digi = document.querySelector(`.digit-${i} svg`); digi.removeAttribute('class'); digi.classList.add(`num-${number}`); } return dom.serialize(); }
jsdom
はdom.serialize();
にてできた DOM を文字列化できますので、これをアクセスしてきたウェブブラウザーに返却し、// counter.js exports.handler = async (event) => { // ... // カウンター数 SVG を生成 counterJson.html = updateLCD(html, counterJson.count); return { statusCode: 200, headers: { "Content-Type": "application/json; charset=utf-8", }, body: JSON.stringify(counterJson) } };ウェブブラウザーは shadowDOM で画面にそのまま書き出しています。
/v1/counter
として Netlify Functions にデプロイした Lambda を呼び出すクライアントのソース:<!DOCTYPE html> <html> <body> <access-counter></access-counter> <script> fetch('/v1/counter').then(function(response) { return response.json() }).then(function(json) { customElements.define('access-counter', class extends HTMLElement { constructor() { super(); const shadowRoot = this.attachShadow({ mode: 'open' }); shadowRoot.innerHTML = json.html; } }) }); </script> </body> </html>終わりに
現代版ジオシティーズとも言える Netlify を今回初めて使ってみたのですが、Netlify Functions 含めいろいろできて便利でした。
試しに検索エンジン API もつくってみましたので、自分のブログになってしまっていますが、気になる方がもしいらっしゃいましたらご覧ください!
Netlify Functions で検索エンジン API をつくる
ふと思いつきまして Netlify で使える Lambda なサービス、Netlify Functions を用いて参照系検索 API を作成してみました。無料枠での挑戦です。
- 投稿日:2020-03-30T01:27:44+09:00
Mac HomebrewでNode.jsをインストールする
目的
- Mac端末にHomebrewを用いてNode.jsをインストールする方法をまとめる
実施環境
- ハードウェア環境
項目 情報 備考 OS macOS Catalina(10.15.3) ハードウェア MacBook Air (11-inch ,2012) プロセッサ 1.7 GHz デュアルコアIntel Core i5 メモリ 8 GB 1600 MHz DDR3 グラフィックス Intel HD Graphics 4000 1536 MB 実施条件
- Homebrewが使用できる状態になっていること。
実施方法概要
- Nodebrewのインストール
- Node.jsのインストール
- 設定
実施方法詳細
Nodebrewのインストール
下記コマンド実行してNodebrewをインストールする。
$ brew install nodebrew下記コマンドを実行してNodebrewのインストールを確認する。
nodebrew -v
Node.jsのインストール
下記コマンドを実行して最新の安定バージョンをインストールする。(エラーが出た方はこちら→Mac Nodebrewを用いてNode.jsをインストールした時にエラーが出た話)
$ nodebrew install-binary stable下記コマンドを実行してNode.jsのインストールを確認する。
$ nodebrew --version設定
先に実行したコマンド
$ nodebrew --version
の出力の「# use a specific version number」の下部に記載されているコマンドを実行する。(「vX.X.X is not installed」というエラーが出た方はこちら→Mac Node.jsのバージョン有効化する手順でvX.X.X is not installedと出力された話)(X.X.Xはバージョン名)$ nodebrew use vX.X.X >use vX.X.X下記コマンドを実行してインストールしたNode.jsのバージョンが有効化されている事を確認する。
$ nodebrew ls ・ ・ ・ >current: vX.X.X先にインストールしたバージョンが「current:」の後に記載されていれば導入完了である。
下記コマンドを実行してパスを通す。
$ echo 'export PATH=$PATH:~/.nodebrew/current/bin/' >> ~/.bashrc「.bashrc」ファイルがログイン時に読み込まれるように設定していない場合は下記の手順を実施する。
下記コマンドを実行して「.bash_profile」ファイルを開く
$ vi ~/.bash_profile下記の内容を追記する。
~/.bash_profilesource ~/.bashrc
下記コマンドを実行して「.bashrc」ファイルを読み込む
$ source ~/.bashrc下記コマンド実行してパスが通っている事を確認する(command not foundにならなければOK)
$ npm