Node.jsのCLIツール開発時のリンクの貼り方・外し方

自分でNode.jsのCLIツールを使うときは、npmを使って明示的にリンクを貼る。

package.jsonに下記のようなbinの記述があるかどうかを確認。

{
  "bin": {
    "iconfont-gen": "./bin/iconfont-gen"
  }
}

その後、下記のコマンドを実行し、リンクを貼る。

$ npm link

外すときは、下記のようにunlinkを実行する。

$ npm unlink -g iconfont-gen

テンプレートリテラル

ES6から利用できるようになったテンプレートリテラルは、単純にバッククォートで囲むだけ。

いままで制御文字を入れて改行していたところを、そのままの改行で表現できる(いままで通り制御文字を使っても大丈夫)。

let test1 = "Hello \n World!";
let test2 = `Hello
World!`;
conosle.log(test1 === test2); // true

また「${〜}」の記法を使うことで、変数や計算式を入れることも可能。

let hoge = 'World';
let test = `Hello ${hoge}!`;
console.log(test); // Hello World!

JavaScriptの型の復習

JavaScriptのプリミティブ型は下記の5つのみ。
それ以外の配列や関数などは全てobjectとなる。

  • boolean
  • number
  • string
  • undefined
  • null

よく同一視されるundefinedとnullの違いとしては、

  • undefinedは未定義の状態、つまり何も設定されていない状態
  • nullは何もない状態

であり、undefinedは変数宣言を行って値を入れていない状態でセットされるが、nullは意図的に設定しなければ、その値を示さない。
またES5以前の環境ではundefinedはグローバルオブジェクトで値を書き換えることができたため、void 0などの記法を用いて確実にundefinedを指すようにすることが多かったが、モダンブラウザでは単純な同値比較でOK。
typeof演算子を使った場合には、他のプリミティブ型と同じく、undefinedはundefinedを指すが、nullはobjectを指す(ちなみにobjectの中で関数のみfunctionを指す)。

入門書でtypeof演算子と一緒に紹介されるinstanceof演算子は、オブジェクトのプロトタイプチェーンを辿って、指定されたコンストラクタがあるかどうかを調べるもので、つまり全てのオブジェクトはObjectとの比較がtrueになる。
またそのオブジェクトのコンストラクタの名前を取得するには、コンストラクタで生成された全てのオブジェクトが持つ、object.constractorプロパティを参照すればいい。

nodebrewでNode.jsのバージョン管理

HomebrewのNode.jsをアンインストール

$ brew uninstall node

nodebrewをHomebrewでインストール

$ brew install nodebrew

nodebrewの初期設定

インストールしたときにメッセージが表示されるので、それに合わせて設定

$ /usr/local/opt/nodebrew/bin/nodebrew setup

「Export a path to nodebrew:」で示されたパスを「~/.bashrc」に追記

export PATH=$HOME/.nodebrew/current/bin:$PATH
# あるいは
export PATH=/usr/local/var/nodebrew/current/bin:$PATH

「~/.bashrc」の読み込み

$ source ~/.bashrc

パスが通っているかを確認

$ nodebrew -v

Node.jsの最新版をバイナリでインストール(バイナリじゃないと時間がかかる)

$ nodebrew install-binary latest (安定板の場合はstable)

インストールできるバージョンは下記のコマンドで確認

$ nodebrew ls-remote

現在インストールされているものを確認

$ nodebrew ls

インストールされたものでどのバージョンを使うかを指定

$ nodebrew use v10.0.0

Node.jsのバージョン確認

$ node -v

※下記のようにエラー発生した場合

-bash: node: command not found

「~/.bashrc」はパスは書き込まれている場合には読み込まれていない。
そのため自動で読み込まれる「.bash_profile」の方に、「~/.bashrc」を自動で読み込ませる下記の設定を記述。

if [ -f ~/.bashrc ] ; then
. ~/.bashrc
fi

やる気の法則

船井総研の創始者である船井幸雄氏が提唱した経験則。
これに当てはめると、モチベーションの高い仕事ができる環境はやらされている仕事よりも2.5倍ほど作業効率が違うということになる。

仕事の内容 成果
やらされている仕事 1.0
納得している仕事 1.6
自ら進んでする仕事 1.6の2乗

ブラウザで求められるクロスサイトのアクセス制限

JavaScriptでドメインを超えたデータのやりとりを行う場合のブラウザに求められるクロスサイトのアクセス制限の種類

FORM 制限なし(制限する場合はCSRF対策が必要)
SCRIPT 制限なし(JSONPへの応用が可能)
IMG インライン表示はできるが、SCRIPTから画像の中身は読めない
CSS レンダリングできるがSCRIPTから中身は読めない
IFRAME クロスサイトのDOM操作を禁止
XMLHttpRequest クロスサイトのリクエストを発行できない
XMLHttpRequest Level 2 クロスサイトのリクエストを条件付きで許可

http://labs.cybozu.co.jp/blog/kazuho/archives/2007/01/crosssite_security.php

XMLHttpRequest Level 2について

XMLHttpRequest Level 2に対応しているブラウザで外部サイトに対してXMLHttpRequest通信を行うと、ブラウザから送られるHTTPリクエストにOriginヘッダが付加される。Originヘッダにはドメイン名が設定される。

サーバー側から返されるHTTPレスポンスのAccess-Control-Allow-Originヘッダにアクセスを許可するリクエスト送信先のドメインを指定する。

XMLHttpRequest Level 2に対応しているブラウザは、Access-Control-Allow-Originヘッダの内容を確認して、それが現在のリクエスト送信元のドメインと一致している場合にのみ、レスポンスを受け取る。

通常は.htaccessなどでAccess-Control-Allow-Originヘッダに許可するドメインを羅列するが、その値に*を指定すると、すべてのドメインから利用できるようになる。

 

position:fixedについて

position:fixedが効いている要素は、スクロールするたびに固定要素のビットマップと、重なりの下にあるほかの要素のビットマップをCPU上で合成する必要があり、広範囲の再描画を必要とする。

そのため、GPUアクセラレーションを有効にする下記のCSSハックを行うと描画スピードが向上する。

transform: translate3d(0, 0, 0);

※上記ハックはあらゆる要素に適用できるが、CPUからGPUへの要素の転送はブラウザにとって負荷の高い処理であるため、広い領域を持つ要素や多数の要素にむやみに利用すべきではない

 

HSTS(HTTP Strict Transport Security)について

2010年に公開されたFiresheepというFirefoxのアドオンの登場により、暗号化されていない同一ネットワーク上の通信をパケットキャプチャすることによって、HTTP Cookie情報を盗みとり、簡単になりすまし(セッションハイジャック)ができることが周知の事実となった。

そのため、今日ではほとんどのWebサイトがすべてのページでSSLによるHTTPS通信を行うような流れとなり、各サイトのサーバー側でHTTPでアクセスしてきた場合、HTTPSにリダイレクトさせるコードを書いて対応していた。

しかし、その場合一時的にHTTPでアクセスするため、その瞬間のセッション情報が盗み出される危険がある。

そこでHTTPではなく、HTTPSに直接アクセスしてほしいことをブラウザに支持するための規定ができた。それがHSTSである。

具体的な対応

HTTP通信を行っているWebサーバー側からStrict-Transport-Securityヘッダを返すことで強制的にHTTPSにアクセスさせる。

具体的な.htaccessでの記述例

Header set Strict-Transport-Security "max-age=31536000; includeSubDomains"

DOMについての復習

DOMはHTMLとほとんど同型のツリー構造をとるが、HTMLにおける要素ノード以外にも、いくつか種類がある。下記にDOMノードの種類を示す。

要素ノード

HTMLの要素に対応するノード。複数の属性を持ち、さらに子ノードを持つ。
具体的にはelement.getElementsByTagName()やdocument.getElementById()で取得できる。

ルートノード

HTMLではhtml要素が全ての要素のルートとなっているが、DOMではさらに上位にdocumentというルートノードが存在する。

テキストノード

文字列を格納するノード。子ノードを持たない。

 

上記のノードを取得・変更・追加・削除するためのAPIの規定がDOMである。
次にDOMを操作・取得するための関数を下記に示す。

DOMの関数

指定したid属性の値を持つ要素ノードを取得するメソッド

document.getElementById(id)

呼び出し元のノードの子孫要素の中で、指定した要素の名前を持つ要素ノードをリストとして取得するメソッド

element.getElementsByTagName(name)

呼び出し元のノードの子孫ノードの中から、指定したクラス属性の値を持つ要素ノードをリストとして取得するメソッド

element.getElementsByClassName(name)

呼び出し元のノードの指定した属性の値を取得するメソッド(ただし、ほとんどの属性には同名のプロパティが用意されている)

element.getAttribute(name)

呼び出し元のノードの直下のすべてのノード(テキストノード含む)のリストを取得するプロパティ

element.childNodes

呼び出し元のノードの直下の最初のノードを取得するプロパティ(element.childNodes[0]と同じ)
※ちなみにelement.firstElementChildとすると、最初の要素ノードの取得になる

element.firstChild

(例)子要素すべてを削除

let $el = document.getElementById('hoge');
while ( $el.firstChild ) {
    $el.removeChild($el);
}

指定した要素名の要素ノードを生成(生成後はappendChild()やinsertBefore()を使って、任意の場所に挿入)

document.createElement(name)

指定した文字を格納したテキストノードを生成(生成後はappendChild()やinsertBefore()を使って、任意の場所に挿入)

document.createTextNode(text)

呼び出し元のノードの子ノードの一番最後に指定したノードを追加

element.appendChild(node)

呼び出し元のノードの指定した子ノードを削除

element.removeChild(node)

指定したノードの直前にノードを挿入

insertBefore(node, ref)

 

より簡単にノードを取得できるAPIとしてSelectors APIがある。
今はこちらの方が主流。
上記の「element.getElementsByClassName(name)」「element.getElementsByTagName(name)」また「document.forms」などのDOM APIとSelectors APIの大きな違いとしては、上記の場合はLive NodeList(単純にNodeListと呼ばれることもある)を取得するのに対してSelectors APIはStatic NodeList(HTMLCollectionと呼ばれることもある)を取得する。

両者の違いは、別の概念で言い換えると、要素のコピーを取得するかポインタを取得するかの違いだと筆者は思っている。
それぞれ使用できるメソッドの違いがもちろんあり、混合することでよく発生するエラーは、下記のような感じ。

Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.

Selectors APIはjQueryライクにかけるので、まだjQuery使っている人でも簡単に導入できると思う。

Selectors API

呼び出し元のノードの子ノードの中から、指定したセレクタで一番最初の要素ノードを取得

document.querySelector(selector)

呼び出し元のノードの子ノードの中から、指定したセレクタのすべての要素ノードを取得

document.querySelectorAll(selector)