- 投稿日:2020-06-29T22:27:03+09:00
[Node.js]カバレッジレポートを出力しよう
現場で、なんとなくistanbulを使用してCI環境を構築しておったが、
Node.jsのスプレッド公文で半端なくエラーが出力されるという自体が発生。。。なんで!?なんで!?
https://www.npmjs.com/package/istanbul
This package has been deprecated Author message: This module is no longer maintained, try this instead: npm i nyc Visit https://istanbul.js.org/integrations for other alternatives.あー。なるほど。(公式は読みましょう。はいすみません。)
いい機会なので、nycを使ってちゃんと出力してみようと思った次第で。
環境を作ってみよう
Dockerじゃないと夜も眠れないので、Dockerで構築してみる。
# 適当に $ mkdir CoverageNodejs # Create Dockerfile $ mkdir docker $ touch docker/DockerfileDockerfileを記載。Versionは適当に安定版を。
※ 内容はPJ毎によしなにどうぞ。docker/Dockerfile.FROM node:12.18.1 WORKDIR /src ENV TZ Asia/Tokyo CMD ["sh"]docker-composeも。
$ touch docker-compose.ymldocker-compose.ymlversion: '3' services: coverage_nodejs: container_name: coverage_nodejs build: docker/. volumes: - ./src:/srcとりあえず、srcを。
$ mkdir src $ touch src/index.jssrc/index.js'use strict' const execute = () => new Promise((resolve, reject) => { Promise.resolve() .then(() => { resolve('yamachita') }) .catch(reject) }) module.exports = { execute }dockerで。
$ docker-compose up -d --build $ docker-compose run --rm coverage_nodejs npm initとりあえず私がNode.jsでCI/CDする際に使用しているライブラリをinstall。
# 静的解析 # @see https://www.npmjs.com/package/standard $ docker-compose run --rm coverage_nodejs npm install -D standard # テスティングライブラリ # @see https://www.npmjs.com/package/mocha $ docker-compose run --rm coverage_nodejs npm install -D mocha # カバレッジレポート # @see https://www.npmjs.com/package/nyc $ docker-compose run --rm coverage_nodejs npm install -D nyc実際にテストをしてみよう
適当なテストフォルダを作成
$ mkdir src/test $ touch src/test/index.test.jstest/index.test.js/* eslint-disable no-undef */ const usecase = require('../index') const assert = require('assert') describe('# index', () => { it('## execute', async () => { let res await usecase.execute().then((result) => { res = result }) assert.strictEqual(res, 'yamashita') }) })テストスクリプト記載。
src/package.json〜省略〜 "scripts": { "test": "mocha --recursive", "test-coverage": "standard && nyc --reporter=html --reporter=text mocha --recursive" }, 〜省略〜テスト実行
$ docker-compose run --rm coverage_nodejs npm test > src@1.0.0 test /src > mocha --recursive # index 1) ## execute 0 passing (13ms) 1 failing 1) # index ## execute: AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + actual - expected + 'yamachita' - 'yamashita' ^ + expected - actual -yamachita +yamashita at Context.<anonymous> (test/index.test.js:8:12) npm ERR! Test failed. See above for more details.あ。テストケースミスった。
修正してもう一回。$ docker-compose run --rm coverage_nodejs npm test > src@1.0.0 test /src > mocha --recursive # index ✓ ## execute 1 passing (10ms)お次はカバレッジレポートを出力。
$ docker-compose run --rm coverage_nodejs npm run test-coverage > src@1.0.0 test-coverage /src > standard && nyc --reporter=html --reporter=text mocha --recursive # index ✓ ## execute 1 passing (14ms) ----------|---------|----------|---------|---------|------------------- File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s ----------|---------|----------|---------|---------|------------------- All files | 100 | 100 | 100 | 100 | index.js | 100 | 100 | 100 | 100 | ----------|---------|----------|---------|---------|------------------- # カバレッジレポートを開く $ open src/coverage/index.htmlこんな感じ。
まとめ
私の現職場では、このカバレッジレポートを社内専用サーバーにExpress(Node.js)の上に乗っけて、毎朝実行 + 実行結果をSlackに通知している。
時間があれば、その環境も記事にできたらいいな。
- 投稿日:2020-06-29T22:21:21+09:00
nodejsを使ってウエブサーバーを作ろう - majidai
majidaiとは
majidaiとは、nodejs用のWebフレームワークです。
サードパーティーライブラリが使っていないため非常に軽いです。
データ量 < 50KBインストール
nodejsがインストールはこの記事のスコープ外とします。
1. プロジェクトの初期化
タミナルから作業フォルダーに移動し、プロジェクトの初期化を行います。
npm init -y
2. majidaiインストール
以下のコマンドで「majidai」をインストールします。
npm install majidai
3. サーバーコード
以下のコマンドで「majidai」をインストールします。
server.js// majidaiの読み込み const majidai = require("majidai"); // インスタンス化 const server = new majidai(); // 受付開始 server.start();4. serverの起動
以下のコマンドでウエブサーバーの起動します。
node server.jsそして、ブラウザを起動し、http://localhostにアクセスします。以下の画面が表示されればOKです。
デフォルトでは80ポートで受け付けしますが、以下のようにポートを指定する事が可能です。
const config = { http: { port: 8000 } }; const server = new majidai(config);静的コンテンツの配信
デフォルトでは静的コンテンツの配信が無効にしてますが、以下のように「Document Root」指定する事で指定のフォルダーは以下のものを配信する事が可能です。
const config = { http: { documentRoot: './public' } }; const server = new majidai(config);使い方
majidaiの書き方は以下のようになります。
server.METHOD(PATH, CALLBACK)METHODとは
以下の3種類があります。
- get : http GETリクエストのみ受け付けます
- post : http POSTリクエストのみ受け付けま
- listen :複数のhttpメソッドを一つのPATHで受け付けます
※詳細についてはこちらPATHとは
"/" , "/top", "/user/dakc",..みたいにどこでリクエストを受け付けるかの事です。
CALLBACKとは
これはコールバック関数の事です。指定のPATHにリクエストを受け付けたら、この関数が実行されます。関数の引数が以下の2つです。
- request : <http.IncomingMessage>
- response : <http.ServerResponse>
majidaiが両方のオブジェクトに「mj」オブジェクトを追加します。request.mj
requestに追加したmjオブジェクトがクライアントから送られて来たデータを操作するために以下の2つの関数(メソッド)を有します。
- getParams : GETで送られて来た情報をJSONオブジェクトとして返します。キーを引数として指定することで特定のキーに対する値のみを取得する事が可能です。
- postParams: POSTで送られて来た情報をJSONオブジェクトとして返します。キーを引数として指定することで特定のキーに対する値のみを取得する事が可能です。※x-www-form-urlencoded, application/json, form-dataどれでデータが送られて来てもJSONオブジェクトとして返します。
response.mj
クライアントにレスポンスを返すために以下のメソッドを有します。
- text : plain/textとしてレスポンス
- json : application/jsonとしてレスポンス
- static : 静的コンテンツのレスポンス
- redirect : 別のURLへリダイレクト
- error : HTTPエラーとしてレスポンス
※ 詳細についてはこちら
samples
サンプルを見ながらどのようなことできるかやってみましょう!
1. GET受付
get-sample.jsconst server = new majidai(); server.get("/home", (request,response) => { // リクエストがhttp://〇〇/home?price=230) var price = request.mj.getParams("price"); console.log(price); // 230 // OR // 全データをJsonオブジェクトとして取得 var getData = request.mj.getParams(); console.log(getData); // { price: '230' } // 「price」の値を取得 var price_ = getData.price; console.log(price); // 230 return "ここで返すものがクライアントへのレスポンスになります"; }); server.start();2. POST受付
post-sample.jsconst server = new majidai(); server.post("/login", (request,response) => { // リクエストがhttp://〇〇/login // <form action="/login" method="POST"> // <input name="id" type="text" value="abc"> // <input name="pass" type="password" value="p@ss"> // </form> // 「id」の値を取得 var id= request.mj.postParams("id"); console.log(id); // abc // OR // 全データをJsonオブジェクトとして取得 var postData = request.mj.postParams(); console.log(postData); // { id: 'abc', pass: 'p@ass' } // 「id」の値を取得 var id_ = postData.id; console.log(id_); // abc return "ここで返すものがクライアントへのレスポンスになります"; }); server.start();3. 複数HTTPメソッド受付
multiple-methods.jsconst server = new majidai(); server.listen({ method: ["GET", "POST"], path: "/profile" }, (request, response) => { // GETでもPOSTでもこのの処理を実行されます。 // DO SOMETHING return "something"; }); server.start();Parameterized URL
どのような表現が分かりやすいかよくわからなかったため、上記の表記にしました。ごめんなさい。何か気付くところがありましたら是非コメントに残してやってください。
この機能がどうしても実現したかった機能です。
「http://〇〇/user?id=abdf&command=edit」より
「http://〇〇/user/abdf/edit」
ほうが好きだったからです。parameterized-url.js// {}の中のものがその名前のキーでデータを取得する事ができます。 server.get("/books/{year}/{price}", function (req, res) { // リクエストがhttp://〇〇/books/2020/5000 // {}の中のものがその名前のキーでデータを取得する事ができます。 // 「year」の値を取得 var year = req.mj.getParams("year"); console.log(year ); // 2020 // 「price」の値を取得 var price= req.mj.getParams("price"); console.log(price); // 5000 // GETと受けたものをレスポンスとして返す return req.mj.getParams(); });※post,listenの時もParameterizedURL機能が使えます。
Docker
以下の1行のコマンドを実行する事でブラウザーからmajidaiの動作を確認できます。
docker run -it --rm -p 80:80 dakc/majidai npx /data/server.js最後に
nodejsの標準の機能のみで動く軽量なフレームワークを欲しかったため、majidaiを開発しました。MITライセンスでリリースしておりますのでご自由にお使いください。
DOCUMENTATION - https://dakc.github.io/majidai.html
- 投稿日:2020-06-29T19:32:23+09:00
CLS とは?ブラウザとNode.jsで CLS を実装してみます
資料を調べる際に、CLS の存在を知りました。エンジニアリングで結構いいデカップリングのやり方と感じまして、シェアしたいと思います。
シチュエーション
ブラウザか、サーバーのNode.jsか、どっちでもエラーハンドリング、ユーザートラッキングのニーズは日常茶飯事。例えユーザーを特定しなくても、id をつけて、ユーザーの行為を追跡して、エラーの再現にも重要し、プロダクトの改善にも役たちます。
仮に今エラーハンドリングを書こうと思って、このエラーハンドリングはすべてのエラーを処理しますが、どのリクエストから生み出したエラーを知りたいと
log.error("Error occured", req);このハンドリングは req と結合しちゃった
仮に今このエラーどのユーザーから出たエラー、ユーザーが何をやったかを知りたいと
log.info("User has done xxx", user); log.error("Error occured by", user);ユーザーとも結合しちゃった
この2つの例は一見するとそんなに大きいな問題ではなさそう、ただ2つのパラメータが増えただけじゃ。
だけど、大型サービスを作る時、どんどん増えた機能に対して、関数の引数と関数の長さと共にどんどん伸びちゃって気持ち悪くてリファクタリングしようとしょうもないこと、少なくありませんでしょうか?解決してみよう
関数が同期のであれば、グローバルで変数につけたらいいじゃんー
const global = {}; $("button").click((event) => { global.event = event; log("button clicked"); }); function log(...args) { console.log(global.event, ...args); // { x: xxx, y: xxx, target: xxx } 'button clicked' // other logic }だが、非同期関数のであれば
const global = {}; $("button").click((event) => { global.event = event; setTimeout(() => { log("button clicked"); }, 1000); }); function log(...args) { console.log(global.event, ...args); // other logic }すべての global.event は同じイベントになちゃった(´;ω;`)!それはだめですね。
我々必要なのは非同期呼び出しチェーンに最初から最後まで持続的なストレージ、
もしくは今走ってる非同期関数の呼び出しの唯一の識別子。CLS が登場
他の言語では、Thread-local storageと呼ばれるものがあります。が JavaScript はマルチスレッドはありません(Web Workerなどはメインと関係ないし、自分でもマルチスレッドしない)。CLS という名前は TLS みたいに関数型プログラミングからの Continuation-passing style 名前をもらって、Continuation-local Storage、そのチェインの呼び出しの中で持続的データストレージをメンテナンスする。
ブラウザの解決 Zone.js
どうのように解決したかちょっと見てみましょう
$('button').click(event => { Zone.current.fork({ name: 'clickZone', properties: { event } }).run( setTimeout(() => { log('button clicked'); }, 1000); ); }); function log(...args) { console.log(global.event, ...args); // other logic }
Zone.js
は Angular 2.0 から誕生したもので、もちろん他の機能も持ってる。この方法は残念なところがあります
考えてみましょう、
Zone.js
はどうやってこれを実現しました。ブラウザは呼び出しに対して唯一の識別子を提供するAPIがなければ、すべての非同期関数をリライトしかできなく、そうすれば非同期が入る時と出る時 hook できて、この効果が実装できますね。自分も書いてみました。
const Zone = { _currentZone: {}, get current() { return { ...this._currentZone, fork: (zone) => { this._currentZone = { ...this._currentZone, ...zone, }; return this; }, set: (key, value) => { this._currentZone[key] = value; }, }; }, }; (() => { const _setTimeout = global.setTimeout; global.setTimeout = (cb, timeout, ...args) => { const _currentZone = Zone._currentZone; _setTimeout(() => { const __after = Zone._currentZone; Zone._currentZone = _currentZone; cb(...args); Zone._currentZone = __after; }, timeout); }; })(); for (let i = 0; i < 10; i++) { const value = Math.floor(Math.random() * 100); console.log(i, value); Zone.current.fork({ i, value }); setTimeout(() => { console.log(Zone.current.i, Zone.current.value); }, value); }また問題なさそうだけど、
angular with tsconfig target ES2017 async/await will not work with zone.js
ブラウザ今では完璧の解決方法はありません
実験をやってみましょう、console で下のコードを打ったら、
const _promise = Promise; Promise = function () { console.log('rewrite by ourselves') }; new Promise(() => {}) instanceof Promise // rewrite by ourselves // true async function test() {} test() instanceof Promise // false test() instanceof _promise // true async function test() { return new Promise() } test() instanceof Promise // rewrite by ourselves // false test() instanceof _promise // rewrite by ourselves // trueブラウザは、async 関数のリターンをネイティブの Promise で再ラッピングします。ネイティブ文法なので、async 関数はリライトできない。
もちろん transpiler で async 関数を generator もしくは Promise にすることは可能ですが、完璧とは言わないでしょう。Node.js の解決
async_hooks
Node.js バージョン 8 以降出た
async_hook
モジュール、バージョン 14 の今でもExperimental
ステータスから脱却してない。出たごろ性能に関しての議論もあったが、今はどうなってるかまだわからない状態ですがExperimental ステータスにしても安定性としては問題なさそう、大量な Node.js のトラッキング / APM が依存していて、問題があったら issue が立てられるはずです。
性能に関する問題はここは展開しない、コードの低結合と少しパフォーマンスの低下を交換するかしないかによりますね。
使い方
async_hooks
はcreateHook
という関数を提供した、これが非同期関数のライフサイクルに hook できます、しかも唯一識別子も提供してくれますので、CLS を簡単に作れます。const { executionAsyncId, createHook, } = require("async_hooks"); const { writeSync: fsWrite } = require("fs"); const log = (...args) => fsWrite(1, `${args.join(" ")}\n`); const Storage = {}; Storage[executionAsyncId()] = {}; createHook({ init(asyncId, _type, triggerId, _resource) { // log(asyncId, Storage[asyncId]); Storage[asyncId] = {}; if (Storage[triggerId]) { Storage[asyncId] = { ...Storage[triggerId] }; } }, after(asyncId) { delete Storage[asyncId]; }, destroy(asyncId) { delete Storage[asyncId]; }, }).enable(); class CLS { static get(key) { return Storage[executionAsyncId()][key]; } static set(key, value) { Storage[executionAsyncId()][key] = value; } } // --- seperate line --- function timeout(id) { CLS.set('a', id) setTimeout(() => { const a = CLS.get('a') console.log(a) }, Math.random() * 1000); } timeout(1) timeout(2) timeout(3)Node.js バージョン 13 からオフィシャルの実装も
コミュニティの中でたくさんの CLS ライブラリーがあった上に、Node.js 13.10 から
AsyncLocalStorage
の API がありました。https://nodejs.org/api/async_hooks.html#async_hooks_class_asynclocalstorage
実はこれはすでにすぐに使える CLS です。
const { AsyncLocalStorage, } = require("async_hooks"); const express = require("express"); const app = express(); const session = new AsyncLocalStorage(); app.use((_req, _res, next) => { let userId = Math.random() * 1000; console.log(userId); session.enterWith({ userId }); setTimeout(() => { next(); }, userId); }); app.use((_req, res, next) => { const { userId } = session.getStore(); res.json({ userId }); }); app.listen(3000, () => { console.log("Listen 3000"); }); const fetch = require('node-fetch') new Array(10).fill(0).forEach((_, i) => fetch('http://localhost:3000/test', { method: 'GET', }).then(res => res.json()).then(console.log)) // Output: // Listen 3000 // 355.9573987560112 // 548.3773445851497 // 716.2437886469793 // 109.84756385607896 // 907.6261832949347 // 308.34659685842513 // 407.0145853469649 // 525.820449114568 // 76.91502437038133 // 997.8611964598299 // { userId: 76.91502437038133 } // { userId: 109.84756385607896 } // { userId: 308.34659685842513 } // { userId: 355.9573987560112 } // { userId: 407.0145853469649 } // { userId: 525.820449114568 } // { userId: 548.3773445851497 } // { userId: 716.2437886469793 } // { userId: 907.6261832949347 } // { userId: 997.8611964598299 }参照
- 投稿日:2020-06-29T15:59:30+09:00
【Javascript】ワンライナーで現在時刻をフォーマットした日付で表示する
getDay()、getHours()とかやってから繋げるのめんどくさい
コード
ワンライナーnew Date().toLocaleString(undefined, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" });↑改行するとこうnew Date().toLocaleString(undefined, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" });結果8月10日 19:19別のやり方
new Intl.DateTimeFormat(undefined, { [ここにオプション] }).format(new Date());使い方
dateObj.toLocaleString([locales[, options]])詳細:Date.prototype.toLocaleString()
- locales "ja"とかが入ります。undefinedなら、OSのデフォルトです
- options フォーマットを指定できます(自由度は低い)。詳しくはMDNで
※ localesが日本だと"2-digit"で表示されないことがあります
まとめ
moment.jsのが楽です
- 投稿日:2020-06-29T13:33:44+09:00
laravel+vueプロダクトのローカル開発環境
書いてあること
Laravelでバックエンド、Vueでフロントエンドの構成のプロダクトをWindowsクライアントで開発する際のクライアントのローカル環境の構築方法。
手順
1.「Visual Studio Code(VS Code)」のインストール
公式サイトからダウンロードしてインストール
2.「VS Code」拡張機能のインストール
「VS Code」を起動する。
アクティビティバーの「Extensions(拡張)」アイコンをクリック。
以下の拡張機能名を入力し、拡張機能をインストールしていく。
拡張機能名 説明 .ejs EJSファイル(HTMLのテンプレートファイル)に対して構文をハイライトしてくれる拡張機能。 Bracket Pair Colorizer 対となるカッコ色付けして見やすくしてくれる拡張機能。 ESLint 構文チェックするために必要な拡張機能。 Japanese Language Pack for Visual Studio Code 日本語化するために必要な拡張機能。 php cs fixer PHPのコード整形するために必要な拡張機能。「PHP CS Fixer」や「PHP-CS-Fixer」など、似たような名前の拡張機能が存在するため、間違えないようにインストールしてください。 PHP Intelephense PHPのコード補完をしてくれる拡張機能。 Vetur 「.Vue」ファイルを扱うために必要な拡張機能。 GitLens Gitで管理しているファイルの変更点をショートカットキー等で開ける拡張機能。 Debugger for Chrome VSCodeでフロントサイドのデバッグするための拡張機能。 インストールを実行するには以下の「Install」ボタンを実行する。
3.「Node.js」のインストール
公式サイトからダウンロードしてインストール。
4.phpインストール
公式サイトから「php-7.3.17-Win32-VC15-x64.zip」をダウンロードし解凍して任意の場所に配置。
配置したフォルダを環境変数PATHに追加
配置したフォルダに入り”php.ini-development”を”php.ini"でコピー。
php.iniを開き以下編集[php.ini]-;extension_dir = "ext" -;extension=fileinfo -;extension=mbstring -;extension=gd2 +extension_dir = "ext" +extension=fileinfo +extension=mbstring +extension=gd2 ・・・ +extension=php_openssl +extension=php_pdo_mysql5.「Composer(コンポーザー)」のインストール
公式サイトからダウンロードしてインストール。
Developer modeはチェック入れる
phpの場所は手順4の配置フォルダ中のphp.exeを指定
update this php.iniはチェック外してスキップ
proxyは未設定のままスキップ6.「SourceTree」のインストール
公式サイトから「SourceTreeSetup-2.6.10.exe」をダウンロードしてインストール。
求められるアカウント認証は作るかグーグルアカウントがあればそれでできます。7.「SourceTree」を使ってソースの取得
以下のとおり設定し、「クローン」ボタンを実行する。
《設定内容》 《設定値》 元のパス/URL https://develop.fan-technology.com/gitlab/InHouseDev/xxx.git 保存先のパス {SourceTreeのワークパス}{リポジトリ名} 名前 リポジトリ名 Local Folder [ルート] 詳細オプション ※デフォルトのまま 8.ライブラリで利用するモジュールをインストール
「Node.js」で使用している拡張機能の物理ファイル群(「node_modules」の中身)をインストールする作業です。
「laravel」で使用している拡張機能の物理ファイル群(「vendor」の中身)をインストールする作業です。「コマンドプロンプト」を起動します。
以下のコマンドを入力して実行(Enterキー押下)し、「xxx」のソースがあるフォルダにカレントフォルダを設定します。cd C:\Work\SourceTree\xxx以下のコマンドを入力して実行(Enterキー押下)します。
npm install
初回はネットから落としてくるファイルが多いので10分ほどかかる場合があります。
つづいて以下のコマンドを入力して実行(Enterキー押下)します。composer install
初回はネットから落としてくるファイルが多いので10分ほどかかる場合があります。
9.DBセットアップ
resourceフォルダのmariadb-10.4.10-winx64.msiでデフォルト設定にて。
rootユーザのパスワードは"root"で。
※「HeidiSQL」というソフトが入ってしまうようですが、使わないので無視してください。10.DBマイグレーション
リポジトリ名のフォルダにコマンドプロンプトで入り以下実行
php artisan migrate11.初期データ投入
php artisan db:seed※「class not found」などのエラーが出る場合は「composer dump-autoload」のコマンドを実行して再度試してください。
12.実行
コマンドプロンプトを立ち上げてxxxのフォルダに移動
php artsan serveコマンドプロンプトを立ち上げてxxxのフォルダに移動
npm run watch※ビルドが終わると自動でブラウザでサイトを開いてくれます。
http://localhost:3000/また、browserSyncというホットリロードの仕組みを取り入れていますので、ソース系のファイル変更を検知してリビルドしてブラウザリロードしてくれます。
もしリロードしてほしくない場合は以下のURLでアクセスしてください。
http://localhost:8000/13.「Postman」のインストール
「Postman」はAPIの動作確認を行う際に有用なツール。
GUIで動くcurl。
公式サイトからダウンロードしてインストール。
- 投稿日:2020-06-29T10:31:29+09:00
Node.js 開発環境構築
はじめに
Node.js 未経験者が初めて開発環境を構築したときの備忘録です。
Homebrew や git はインストール済みの前提です。環境
macOS Catalina version 10.15.5 Homebrew 2.4.2 git version 2.22.0 fish, version 3.0.2nodenv
anyenv
こちらはnodenv以外にもあるpyenv等、様々なenv系のツールをまとめてくれるもの。
今回はこちらを経由して nodenv をインストールする。
https://github.com/anyenv/anyenvインストール
$ brew install anyenv初期化します。
$ anyenv init # Load anyenv automatically by adding # the following to ~/.config/fish/config.fish: status --is-interactive; and source (anyenv init -|psub)なんか出るので従います。
$ vi ~/.config/fish/config.fish # 以下を追記 status --is-interactive; and source (anyenv init -|psub)config を読み直します
$ source ~/.config/fish/config.fish ANYENV_DEFINITION_ROOT(/Users/mkitaya/.config/anyenv/anyenv-install) doesn\'t exist. You can initialize it by: > anyenv install --initまたなんかでるので従います。
$ anyenv install --init Manifest directory doesn\'t exist: /Users/mkitaya/.config/anyenv/anyenv-install Do you want to checkout ? [y/N]: y Cloning https://github.com/anyenv/anyenv-install.git master to /Users/mkitaya/.config/anyenv/anyenv-install... Cloning into '/Users/mkitaya/.config/anyenv/anyenv-install'... remote: Enumerating objects: 48, done. remote: Total 48 (delta 0), reused 0 (delta 0), pack-reused 48 Unpacking objects: 100% (48/48), done. Completed!nodenv インストール
https://github.com/nodenv/nodenv
インストール
$ anyenv install nodenv # shell 再起動 $ exec $SHELL -lNode.js インストール
# 一覧を確認 $ nodenv install -l # バージョンを指定してインストール # https://nodejs.org/ja/download/ を確認して、最新のLTSバージョンを選ぶ $ nodenv install 12.18.1 # デフォルトで使用するバージョンを設定 $ nodenv global 12.18.1 # shell 再起動 $ exec $SHELL -l # バージョンを確認 $ node -v v12.18.1ちなみに、
nodenv local
を使うと特定のディレクトリで使用するバージョンを設定できます。$ cd hoge/ $ nodenv local 12.18.0 # 上記を実行すると .node-version というファイルが作られる $ node -v v12.18.0ここまでで Node.js を使えるようになりました。
Visual Studio Code
Node.js の開発を行う際に便利なエディタ
以下よりzipをダウンロード
https://code.visualstudio.com/
解凍するとappファイルが出てくるのでApplicationsディレクトリに移動してインストール完了。
環境構築完了です。参考
- 投稿日:2020-06-29T08:17:03+09:00
今すぐ使いたいスプレッド構文、"Three-dots" Tip 集
こんにちは。また転職しますので、以前仕事で使っていたアカウントから切り離して新しいアカウントからこれを書いています。(なので現在フォロワー0からの再出発!)
この記事は10日ほど前に私が Dev.to で投稿したものと同じ内容なのですが、Must-read に選ばれるほどの好評でしたので日本語でも書いてみることにしました。
ES6 (ECMAScript 2015, the 6th edition) が標準化されて5年経ちました。この通称 ES6 は多くの新機能や、シンタックティカル・シュガーが追加され、簡潔で明瞭な構文で記述できるようになりました。
たとえば
class
構文、let
/const
、アロー関数などは、みなさんもすでに普段から使っていると思います。では、通称 "three-dots" とも呼ばれる Spread operator / スプレッド構文はどうでしょうか。あまり積極的に使っていない方が多いのではないでしょうか。私は個人的はとても便利だと感じていますので、コードを書いてて見つけた便利な使い方を紹介してみようと思います。もちろん普段はコードを書くのに StackOverflow 参考にすることも多いことは隠すつもりはないので、そうして誰かがシェアしたものの中で便利だと思ったコードは自分で普段使ってクセにしていって、そのうち自分でもいろいろ見つけた、というのが本当のところです。
Three Dots って?
ES6 で追加された "three-dots" シュガー には、可変長引数を配列で受け取る Rest parameter / 残余引数と、シンタックスが似ていますが、逆に配列を展開するスプレッド構文があります。
この記事ではスプレッド構文の方の紹介をしていきます。この定義の説明を読んで理解するよりも、これから紹介する実際の使えるコードをみてもらった方がわかりやすいと思います。
? ? ?
Concat (配列の結合)
"Con*cat*" ということで猫の毛色を含む2つの配列があります。?
const arr1 = ['solid', 'bicolor', 'tabby']; const arr2 = ['calico', 'tortoiseshell'];ES6 以前では、元来の方法で
concat()
を使ってこう書いてきました:var conCats = arr1.concat(arr2); // ['solid', 'bicolor', 'tabby', 'calico', 'tortoiseshell']ES6 スプレッド構文ではこう書くことができます:
const conCats = [...arr1, ...arr2]; // ['solid', 'bicolor', 'tabby', 'calico', 'tortoiseshell']文字列 → 配列 変換
文字を反転にせよ、もしくは、回文を作れというような問題はソフトウェア・エンジニアの面接のあるあるなのではないでしょうか。実際の問題はもっと複雑なものかもしれませんが、似たような問題で、問題を解決するには、まず文字列を配列に変換する、というようなものが結構多いかと思います。
まず文字列があります:
const str = 'kitty';ES6 以前では
split()
を使って一文字づつ配列におさめることができました:var newArr = str.split(''); // ['k', 'i', 't', 't', 'y'];ES6 スプレッド構文を使えばもっと楽に:
const newArr = [...str]; // ['k', 'i', 't', 't', 'y'];Max または Min の値
まず、このような値が与えられたとします。
10, 9, 6, 12この中から最大値(または最小値)を見つけるのは
Math.max()
(orMath.min()
) を使い、上の数値を引数としてあたえます:var max = Math.max(10, 9, 6, 12);ES6 スプレッド構文を使うとこう書くことができます:
const nums = [10, 9, 6, 12]; const max = Math.max(...nums); // 12配列のコピー
スプレッド構文と使って配列のシャローコピーを返すことができます。
例えば、こういう配列があります。
const allCatNames = ['chewie', 'leia', 'yoda', 'chewie', 'luke', 'leia'];シャローコピーを得る一つの方法として、
slice()
があります:var allCatNamesCopy = allCatNames.slice();これを ES6 スプレッド構文を使うとこうなります:
const allCatNamesCopy = [...allCatNames];配列から重複を除く
上の例の配列、
allCatNames
ではいくつかの重複 (chewie
とleia
が2つづつ)があります。重複を取り除いた配列を得るには ES5 では、何行もあるコードを書く必要があったかと思います。たとえば、配列をループし、それぞれの値をマッピングして同じ値があるか調べつつ新しい配列に push して最終的に重複を除いた新しい配列を返す、といったオペレーションをする必要がありました。これを、スプレッド構文を使うと一行で書くことができます。
const catNames = [...new Set(allCatNames)]; // ['chewie', 'leia', 'yoda', 'luke'];HTML エレメントを配列に
もしあなたが DOM 使いなフロントエンドの JavaScript ディベロッパーだったら次の例は特に便利かもしれません。
例えば、
.cat
というクラス名のついたエレメントを集めたいとします。 この時、querySelectorAll()
で DOM ノードを収集するでしょう。ただこの時
document.querySelectorAll('.cat')
はノードの集合 NodeList であり、似てはいますが配列とは異なります。ではこの NodeList を配列にしたい時はどうしますか?
ES5 では、このように一見わかりにくいハック的な方法をとっていたかもしれません:
var catElementArray = [].slice.call(document.querySelectorAll('.cat'));これを、スプレッド構文を使うとこう書くことができます:
const catElementArray = [...document.querySelectorAll('.cat')];
さて、私の記事であなたが three-dots ノーテーションが気に入ったかどうかはわからないですが、今から使ってみたい、という気になった方がいましたら幸いです。
もし他に便利な使い方を見つけた方はぜひ私にもシェアしてくれると嬉しいです。
ES.Next をもっと知りたい(さらに猫が好きな)方へ
この夏に ECMeowScript - What’s new in JavaScript Explained with Cats というトークを、7月に Forward JS (
San Francisco) そして9月に Web Directions (Sydney) でする予定。コロナウイルスの影響で両方ともリモート・カンフェランスですので興味のある方が是非参加してください ?では。
- 投稿日:2020-06-29T00:58:16+09:00
mongoose で docker でたてた MongoDB に接続するのにはまった話
はじめに
Python でせっせと実装していたものが、
npm install
すれば、あっという間に出来てしまうことを知り、少し落ち込んだりもしたけど、Node.js で書き直している私です。Node.js は超初心者です。開発は1人でやっていて、まだ試しに作ってるだけの状態で、Mac にあれこれ DB をたてるのが嫌なので、DB だけ docker でやっちゃおう!とやってみたところ、ちっとも繋がりませんでした。
mongoose の Top ページ (ココ)に書いてある
const mongoose = require('mongoose'); mongoose.connect('mongodb://localhost:27017/test', {useNewUrlParser: true, useUnifiedTopology: true}); const Cat = mongoose.model('Cat', { name: String }); const kitty = new Cat({ name: 'Zildjian' }); kitty.save().then(() => console.log('meow'));これのコピペが実行できないという絶望的な状況からのスタート。
動作環境
OS: MacOS Catalina Version 10.15.5 (19F101)
node: v12.18.1
mongoose: 5.9.20
MongoDB: 4.2.8
Docker: version 19.03.8, build afacb8b
docker-compose: version 1.25.5, build 8a1c60f6docker-compose
docker-compose.ymlversion: "3.1" services: mongo: image: mongo restart: always environment: MONGO_INITDB_ROOT_USERNAME: user MONGO_INITDB_ROOT_PASSWORD: secret1234 ports: - 27017:27017 volumes: - ./configdb:/data/configdb - mongo_local_marketing:/data/db mongo-express: image: mongo-express restart: always ports: - 8081:8081 environment: ME_CONFIG_MONGODB_ADMINUSERNAME: user ME_CONFIG_MONGODB_ADMINPASSWORD: secret1234 volumes: mongo_local_marketing: driver: localほぼ、公式(docker hub: mongo)のまま。永続化しただけ。express はなくても良いけど、MongoDB にも不慣れで便利なのでありがたく。
で、sandbox という名前の database を作っておく。
うまくいかなかったやり方
├── app.js └── config └── db.jsconfig/db.jsmodule.exports = { url: "mongodb://user:secret1234@0.0.0.0:27017/sandbox", };app.jsconst mongoose = require("mongoose"); const dbConfig = require("./config/db"); // connect mongodb mongoose .connect(dbConfig.url, { useNewUrlParser: true, useUnifiedTopology: true, }) .then(() => { console.log("successfully connected to the database"); }) .catch((err) => { console.log("error connecting to the database"); console.log(err); process.exit(); });実行するとエラー
$ node app.js error connecting to the database MongooseServerSelectionError: Authentication failed. at NativeConnection.Connection.openUri (.../node_modules/mongoose/lib/connection.js:830:32) at Mongoose.connect (.../node_modules/mongoose/lib/index.js:335:15) at Object.<anonymous> (.../app.js:10:4) at Module._compile (internal/modules/cjs/loader.js:1138:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:1158:10) at Module.load (internal/modules/cjs/loader.js:986:32) at Function.Module._load (internal/modules/cjs/loader.js:879:14) at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12) at internal/main/run_main_module.js:17:47 { reason: TopologyDescription { type: 'Single', setName: null, maxSetVersion: null, maxElectionId: null, servers: Map { '0.0.0.0:27017' => [ServerDescription] }, stale: false, compatible: true, compatibilityError: null, logicalSessionTimeoutMinutes: null, heartbeatFrequencyMS: 10000, localThresholdMS: 15, commonWireVersion: null } }reason... ナニコレ、さっぱり分からん。認証に失敗していることだけ分かった。これ、慣れたら reason 見て理由が分かるもの?!
user/password の typo か?と思ったけど、そうじゃない。user/password の渡し方がいかんのか?と思って以下のように変更。config/db.jsmodule.exports = { url: "mongodb://0.0.0.0:27017/sandbox", user: "user", pwd: "secret1234", };app.jsconst mongoose = require("mongoose"); const dbConfig = require("./config/db"); // connect mongodb mongoose .connect(dbConfig.url, { useNewUrlParser: true, useUnifiedTopology: true, user: dbConfig.user, pass: dbConfig.pwd, }) ...ダメ。
0.0.0.0
をlocalhost
に変えてみたり、docker-compose に書いたmonogo
に変えてみたりしたけど、当然ダメ。dbName を取ってみたら接続はできた
config/db.jsmodule.exports = { url: "mongodb://0.0.0.0:27017", user: "user", pwd: "secret1234", };こうすると、なんか接続はできた。しかし、MongoDB 上に Database は、
- admin
- config
- local
- sandobox
の4つが存在しており、どれにつながってるのか分からん状態。Database は増やせるし。
sandbox に最初からつながりたいんですよ、私は。たまたまつながってる状態じゃなくて、ちゃんと明示した通りにつながっていて欲しいんですよ、私は。dbName をオプションで渡す
https://mongoosejs.com/docs/connections.html#options
ここを見ると、dbName もオプションで渡せるみたいなので、そのようにしてみた。
config/db.jsmodule.exports = { url: "mongodb://0.0.0.0:27017", user: "user", pwd: "secret1234", dbName: "sandbox", };app.jsconst mongoose = require("mongoose"); const dbConfig = require("./config/db"); // connect mongodb mongoose .connect(dbConfig.url, { useNewUrlParser: true, useUnifiedTopology: true, user: dbConfig.user, pass: dbConfig.pwd, dbName: dbConfig.dbName, }) .then(() => { console.log("successfully connected to the database"); }) .catch((err) => { console.log("error connecting to the database"); console.log(err); process.exit(); }); const Cat = mongoose.model("Cat", { name: String }); const kitty = new Cat({ name: "Zildjian" }); kitty.save().then(() => console.log("meow"));実行
$ node app.js successfully connected to the database meow
にゃー。
"sandbox" database の "cats" collection にジルジャン入ってました。シンバルか!{ _id: ObjectId('5ef8b261164eb0103f341ef6'), name: 'Zildjian', __v: 0 }つながらなかった理由
わかりまsn笑
同じ症状の人が見当たらなかったので、私の環境のせい?今度暇な時にゆっくり mongoose のソースコードを追ってみるかも知れない。
今日はいったん、ここまで。あと MongoDB に突っ込めばいったん開発おしまいなので、そっちをやってから。