20200327のNode.jsに関する記事は5件です。

Webサイトを運営しているミニマリストがインストールしている最低限必要なアプリ達

Overview

シンプルであることに越したことはない。
シンプルなら環境の移行や再構築も苦にならない。
シンプルなら必然的にミスする確率も低減する。
今回は環境構築メモの役割も含めて、Webサイト運営に使用しているアプリを公開しておきます。

Target reader

  • シンプルかつ低コスト&高い可用性を持つWebアプリを運用したい方。
  • Webサイトを作る上で最低限何を勉強しないといけないか知りたい方。

Prerequisite

  • OSはWindows
    • Macは1社に依存することからリスクヘッジのためWindows
    • ただし、LinuxコマンドがメジャーなのでWindowsで実行する場合にググらないといけないことがある。 (WindowsのLinux環境であるWSL2が一般的になれば格差は是正されるかもしれない)
  • 言語はNode.js
    • フロントエンドがJavaScript一択なので、バックエンドも同一言語ならパッケージも共有でき効率的。
    • クラウドベンダーのFaaS(Functions)をみた場合、Node.jsは各社採用言語の中で1,2位に属している。
  • クラウドはFirebase(Google Cloud Platform)
    • 個人でサービス提供するには可用性が命。その上でJavaScriptのコンテンツを配置するだけでいいFirebase Hostingは最善の一手。
      • PWA化することで、キャッシュ優先利用により更に可用性を高めることが可能。
      • データ転送量による完全従量制のため、ミニマムスタートにもってこい。
    • そのほかオフライン対応の完全従量制DBであるFirestore等がそろっている。
    • アプリが複雑化した際はGCPが控えているのでAWSやAzureにも決して見劣りはしない。

Body

全てのアプリ.png

Windowsにインストールしているアプリ

Chrome

https://www.google.com/intl/ja_jp/chrome/

文句なしのブラウザシェアNo.1なので、Chromeで開発しないWebアプリはありえない。

Git

https://gitforwindows.org/

Gitはソース管理のために利用する。
GitというよりGitHubはGCPにデプロイするためのハブになっているので不可欠。
GitHubに障害がおこるとデプロイできなくなるためもはや仕事不可。
(Gitはローカルで更新できるのでソースの修正を記録し続けることは可能)

Node.js

https://nodejs.org/ja/

フロントエンドもバックエンドもJavaScript言語で書けてしまうJavaScriptランタイム。
バックエンドは別言語でもいいが、あえて別の言語にする理由がないならJavaScript一つで十分。

Visual Studio Code

https://azure.microsoft.com/ja-jp/products/visual-studio-code/

Visual Studio Codeはソースコード書いたり、デバッグしたり、開発時に利用する。
WebアプリのIDEのスタンダードになりつつあるかな?
Windows開発向けに作られたVisual Studioが動作が重く、ダウンロードサイズも大きかったがこいつは軽量で人気が高い。
拡張機能も充実しており、IDEとの連携でVSCodeがないということは見たことない。

[optional]Google Cloud SDK

https://cloud.google.com/sdk/install?hl=ja

今のところgcloud functions deployコマンドで必要になるが、Cloud Buildを利用してデプロイしているだめインストールされてなくても問題ない。
ただし、各プロダクトのコマンドを使うことになるはずなので、必要になったら入れたほうがいい。
入れなくてもCloud Shellがあるため乗り越えられるかもしれないが。

[optional]Firefox

https://www.mozilla.org/ja/firefox/new/

ブラウザシェアはChromeが圧倒しているが、Firefoxも一定程度ユーザーがいる。
そのため、Firefoxでの動作確認もしておきたいところ。

[optional]Edge

https://support.microsoft.com/ja-jp/help/4501095/download-the-new-microsoft-edge-based-on-chromium

Edgeのシェアはかなりすくないが、Chromiumベースとなり標準でインストールされるようになったら今後無視できなくなるかも?
ChromiumベースでChromeと違いも少なくなると予想できることから、WindowsPCをある程度ターゲットにするなら動作確認したいところ。

[optional]Slack

https://slack.com/intl/ja-jp/downloads/windows

個人で開発しているとPC上でコミュニケーションは取る必要がないため、PCへのインストールは必須ではない。
ただし、通知はよく使うはずなので、スマホへのインストールは必須。

npmでグローバルにインストールしているパッケージ

他にtoとupdateというパッケージがインストールされていた。
手動でインストールした記憶はないが、何かのインストールでバンドルされるなら消さないほうが吉。

firebase-tools

https://firebase.google.com/docs/cli?hl=ja

firebase関連のコマンド実行の際に必要。
現状だとFirebase Hostingにデプロイする際に使用している。

npmで各プロジェクトにインストールしているパッケージ

React

https://ja.reactjs.org/docs/create-a-new-react-app.html

個人開発に重要なSPAで今構築するならVue.jsかReact。
私は仕事でReactを経験したので、それを引き継いでいるがVue.jsの採用を検討したいところ。

Material-UI

https://material-ui.com/

Reactだけでは生のHTMLで記述するため、見た目がかなり貧相になる。
そのため、見た目をよくするために必要なパッケージとして有力なのがMaterial-UI。
基本的なサンプルソースがそろっており、カスタマイズもしやすいので非常に使いやすい。

REACT ROUTER

https://reacttraining.com/react-router/web/guides/quick-start

WEBのページ遷移を管理するためライブラリ。
パスとそれに対応したコンポーネントを指定することで簡単にページ切り替えができる。
コードが多くなるとコード分割が必須になるが、導入しておくとパスごとに簡単に分割できるので便利。

VisualStudio Codeにインストールしている拡張パッケージ

Debugger for Chrome

https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome

VSCode上でChromeをデバッグするために必要な拡張機能。
個人的にはあまり使っていないが、入れておいた方がいいだろう。

Japanese Language Pack for Visual

https://marketplace.visualstudio.com/items?itemName=MS-CEINTL.vscode-language-pack-ja

VSCodeを日本語表記にしてくれる。

[optional]REST Client

https://marketplace.visualstudio.com/items?itemName=humao.rest-client

いろんなパラメータを含んだWebAPIをコールしたいときに便利。
個人的にはあまり使っていないが、入れておいた方がいいだろう。

[optional]DotEnv

https://marketplace.visualstudio.com/items?itemName=mikestead.dotenv

Reactで環境変数を使う際に.envというファイルを使うが、VS上で強調表示してくれるもの。
なくても支障はない。

[optional]VSNotes

https://marketplace.visualstudio.com/items?itemName=patricklee.vsnotes

MarkDown形式でメモできる拡張機能。
課題やメモ等をとにかく書き込んで使っている。
最低限のものしかインストールしていないので、最終的にこのVSNotesが何でも屋としてフォローしてくれている。

Google Chromeにお気に入りとしているサイト

Search Console

https://search.google.com/search-console/about?hl=ja

自身のサイトがGoogle検索に正しく登録されているか、ユーザーがどんな検索ワードで入ってきているか等がわかる。
Webサイトを公開するなら100%通る道。

Google Analytics

https://marketingplatform.google.com/intl/ja/about/analytics/

サイトに入ってから出るまでのあらゆる情報が収集されている。
サイトを成長させるうえで分析は効果的ゆえ、これも必ず導入したいものの一つ。

Create React App

https://create-react-app.dev/docs/getting-started/

Reactを新規で作るなら、もはやCreate React Appは必須といっても過言ではない。
Create React Appを用いれば、深い知識を必要とせずに簡単に本番向けのサイトを構築できる。

Google Cloud Platform

https://console.cloud.google.com/home/dashboard

GCPのダッシュボード。クラウドを扱う以上必須。

Firebase

https://console.firebase.google.com/

Firebaseのダッシュボード。クラウドを扱う以上必須。

Google Adsense

https://www.google.com/adsense/

Webサイトの収益化の筆頭。モバイルがApp StoreかGoogle PlayならWebはAdsense。
審査に通れば簡単に収益化できる反面、厳しい処置を受けることもある。
身綺麗な運営と理不尽と感じてもそれを受け入れる忍耐が必要。

Conclusion

インストールが必要なアプリやライブラリが20個未満でサイトの運用が可能です。
これらを理解したなら、その少し先に私がいるということです。
学習コスト高いものもありますが、低コスト&高い可用性実現のために頑張ってみてください。

便利なものはつい入れたくなりますが、依存関係を増やす以上のメリットがあるか考えてみるといいでしょう。
インストールしているものが一般的なものなら、クラウドベンダーが提供しているDockerイメージをそのまま利用できる場合もあります。
個人的には数年後、SurfaceGo持ち歩きながらVS Onlineで開発して、パワフルなノートPCを持たない人を目指しています:sweat_smile:

simple is best!
Have a great day!

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

Qiitaに投稿した記事をいい感じにExportする君を作った

結論ファースト

作ろうと思ったきっかけ

  • 最近Qiitaがいろいろと話題なので、自分の記事をExportしたいなと思った
  • 朝起きて、突如やろう!となった(出勤前までに)

実現したかった"いい感じ"とは

  • 記事はマークダウンを取得すること
  • 記事内に、Qiitaにアップロードした画像もダウンロードしてくること
  • 記事ごとにディレクトリを分けて写真と記事のセットをわかりやすくすること

所感

  • 作業時間が短かったため、リファクタリングが追いつかなかったしテストとかはもちろんない
  • 作業時間の大体は正規表現に奪われてしまった
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

chromeで401レスポンスが返ってきたときの不具合

背景

https://www.nnn.ed.nico/questions/14833
n予備校の教材の通りに実装を進めていたところ、このリンクと同じ状況に遭遇

問題

chromeに限り、以下のコードで表示されるはずのログアウトしましたという文とリンクが表示されない。

 function handleLogout(req, res) {
   res.writeHead(401, {
    'Content-Type': 'text/html; charset=utf-8'
   });

   res.end('<!DOCTYPE html><html lang="ja"><body>' +
     '<h1>ログアウトしました</h1>' +
     '<a href="/posts">ログイン</a>' +
     '</body></html>'
   );
 }

原因

chromeのバグ
https://bugs.chromium.org/p/chromium/issues/detail?id=992639

解決

  • とりあえず別のステータスコードを変える
function handleLogout(req, res) {
  console.log('handleLogout');
  res.writeHead(400, {
    'Content-Type': 'text/html; charset=utf-8'
  });
  res.end('<!DOCTYPE html>'+
   '<html lang="ja"><body>' +
    '<h1>ログアウトしました</h1>' +
    '<a href="/posts">ログイン</a>' +
    '</body></html>');
}
  • (ブラウザを変える)

追記

教材にこのエラーについての解決方法が追記されていた。
解決方法は、ステータスコードを302に書き換えること。

https://developer.mozilla.org/ja/docs/Web/HTTP/Status
より、

302 Found
このレスポンスコードは、リクエストされたリソースの URI が一時的に変更されたことを示します。

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

npm upTypeError [ERR_INVALID_ARG_TYPE]

状況

以下のようなメッセージが出たので実行してみました。

information.sh
   │   New patch version of npm available! 6.14.1 → 6.14.4          │
   │   Changelog: https://github.com/npm/cli/releases/tag/v6.14.4   │
   │               Run npm install -g npm to update!                |   

update.sh
$ Run npm install -g npm

updateが完了してgulpを実行しようとしたところ
変更していないタスクにて以下のエラーが発生。

error.sh
TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type object

解決方法

邪道ではありますが
gulp-combine-media-queries/index.jsの
152行目付近の以下の部分をコメントアウトします。

index.js
file.contents = new Buffer(cssJson);

自分の場合globをインストール(npm i glob)しており
gulp-combine-media-queriesがインストールされていた。
何度か踏んでいるバグだったので割とすぐ気がつけてよかった。
上記コメントアウトでタスクが実行できました。

原因

今回Run npm install -g npmの実行で
gulp-combine-media-queriesのjsファイルの
コメントアウトが外れる(上書きされる?)という事象に出会うことが出来ました。
たまたま原因が見つかったからよかったものの
エラーが出ていたタスクや直近でgulp-combine-media-queries関連の
変更はしていなかったのでハマってもおかしくない状況だったと思います。
このエラーはissueは立っているものの放置され
新しいものもフォークされているようです。
https://github.com/konitter/gulp-combine-media-queries/issues/19
しかしながらプラグインが依存しているという状態だと
そちらが変更されないといけない状況ですから応急処置として前述の回避策をしています。
gulpファイルの書き方で解消できるかもしれませんが
何かもっと良い解決方法をご存知の方はコメントいただけましたら嬉しいです。

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

jestでモックしてみたメモ

レガシーコードのテストをjestに移行していた時に、
jestだとどうやってモックしたり、追跡したりするんだ?となったのでその時のメモ

最初に

相当アホなところでハマったのだが、jest はnamespaceをそのまま読み込むため以下のようの読み込まないといけない。

import 'jest' // OK

import jest from "jest" // NG

jest.xxxx()

特定の関数をモックする

関数にもろもろについてモックの仕方です。

テスト用のモック関数の作成

const mockFunc = jest.fn().mockImplementation(() => return "mock func");
console.log(mockFunc()); // mock func

関数自体のモックは jest.fn()に集約されており、単純に何か値を返すのみの関数は mockImplemantionの引数で定義します。
また、mock関数の引数や、どういった値を返したかの検証も行えます。

関数の動作の検証

引数の検証

実際にモックした関数の引数を見たい場合はこんな感じでmock.calls を使います

const mockFunc = jest.fn().mockImplementation((message: string) => {
    return message;
});
mockFunc('test1');
mockFunc('test2');
console.log(mockFunc.mock.calls); // [ ['test1'], ['test2']] 

戻り値の検証

戻り値の場合はmock.resultsを使います。

const mockFunc = jest.fn().mockImplementation((message: string) => {
    return message;
});
mockFunc('test1');
mockFunc('test2');
console.log(mockFunc.mock.results);
/*
[
  {
    type: 'return',
    value: 'test1',
  },
  {
    type: 'return',
    value: 'test2',
  },
];

*/

value は実際に返した値で、
typeはその値が正常リターンか、エラーかを判定します。

正常の場合は return
エラーがスローされた場合は throw
となります。

また、 imcomplete というケースがありますが、これはよくわからないので省略します。

後処理

テストの後処理は2種類あり、 関数のモック自体を抹消する場合と、関数の引数などの追跡結果を抹消する場合があります。

const mockFunc = jest.fn().mockImplementation((message: string) => {
    return message;
});

mockFunc.mockClear() // どういった引数を受取、どういった値を返したかの計測結果をリセット
mockFunc.mockReset() // 実際に実装した関数や戻り値の設定をリセット

特定のオブジェクトに生えている関数を追跡、モックする

追跡対象を指定

const spy = jest.spyOn(targetObject , "do"); // オブジェクトの指定とそこから生えている関数を指定

// 関数実行処理

expect(spy).toHaveBeenCalled(); // 関数が実行されたかどうかを検証

指定した関数をモック関数にする

const spy = jest.spyOn(targetObject , "do")
    .mockImplemention(() => "spy");

↑のようにすると、指定したオブジェクトの関数は、mockImplementionの中で定義した関数に差し替えられます。
なお、mockImplementionの中には先程解説した jest.fnを渡すこともでき、その場合は引数などの検証も行えると思います(未検証)

オマケ 現在時刻のモック

特定の時刻でポイントが失効するかどうかをチェックしたい場合に現在時刻をモックする必要があったのでその時のことも書いておきます。

重要なことは、日付を扱うパッケージオブジェクト(moment, dayjsなど)はjavascriptのDateオブジェクトに依存しているため、Dateオブジェクトをモックすれば現在時刻系は騙せます。

なので、

  • jest で Dateオブジェクトをモックする
  • mockDate を使う
  • 自分でDateオブジェクトをモックする(レガシーコードはこれをやってた)

個人的に、mockDateを使うのが良いかなと思います。使いやすいしリストアなどもやりやすい他、
ドキュメントも充実しているので、情報共有もしやすいです。

最後に

時刻関連のモックをしらべるのに一番時間がかかりました。
Dateオブジェクトをいじればいいみたいな結果は出てくるのですが、なぜそれが必要なのかという理由が納得できず、
momentの初期化処理のコードを見に行ってDateオブジェクトに依存しているとわかりました。

それでは、良いjestライフを

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