Panda Noir

JavaScript の限界を究めるブログでした。最近はいろんな分野を幅広めに書いてます。

バンドラなんていらない時代になりつつあるぞ

Webpackだとかbabelだとか、ダサくないですか?設定してnpm run buildして…そんなことしないで済む時代が来ているんですよ!

バンドラがなぜ必要だったのか

バンドラはたくさんあるファイルを1つにまとめ、依存関係を解消することが目的でした。

しかし、ES Modulesの普及に伴い、<script type="modules">が現実的に使えるようになりつつあります。

また、HTTP/2においてサーバープッシュという、リクエストされていないファイルを送信できる機能が登場しました。これを使うと、importするファイルをあらかじめ送ることができます。

@pika/web + サーバープッシュという選択肢

@pika/webという依存パッケージをES Modulesで読み込めるように変換するツールがあります。変換したパッケージはimport {createElement, render} from './web_modules/preact.js';のようにして読み込むことができます。

@pika/webなら$ npx @pika/webを実行するだけで、ES Modulesを使った開発ができるようになります。

依存ファイルをあらかじめ送信する

ES Modulesでは依存ファイルを以下のようにしてダウンロードします。

  1. JSファイルを読み込む
  2. 解析する
  3. ファイル内にあるimportを見つける
  4. 依存ファイルをリクエストする
  5. ダウンロード完了してから処理を再開する

サーバープッシュを使えば、依存ファイルはすでにダウンロード済みなので4の段階をスキップできます。

Nginxでサーバープッシュする

Nginxなら、つぎの設定でサーバープッシュを使用できます(参考: NginxがHTTP2サーバプッシュに対応したので試す - ASnoKaze blog)

server {
    listen 443 http2;
    # HTTPSの設定は省略します。
    server_name example.com;

    http2_push_preload on;
    location / {
        root   html;
        add_header "Link" "</main.js>;rel=preload;as=module, </web_modules/preact.js>;rel=preload;as=module";
        index  index.html;
        try_files $uri $uri.html $uri/index.html = 404;
    }
}

実際に読み込んでみる

デモを用意しました。

f:id:panda_noir:20190311155423p:plain
サーバープッシュあり

f:id:panda_noir:20190311155427p:plain
サーバープッシュなし

f:id:panda_noir:20190311162407p:plain
バンドルあり

サーバープッシュありのほうが若干速くなっています。ただし、バンドルありにはまだ勝てません。

Elixirの内包表記、内包してなくない問題

1から10まで、各数字を2乗して足すプログラムを考えます。

1..10
|> Enum.map(&(&1*&1))
|> Enum.reduce(&(&1+&2))
|> IO.inspect

こうなります。分かりやすいですね。

それが「内包表記」だと以下のように書けます

for i <- 1..10 do
  i*i
end
|> Enum.reduce(&(&1+&2))
|> IO.inspect

(for i <- 1..10, do: i*i)
|> Enum.reduce(&(&1+&2))
|> IO.inspect

どこが「内包」なんじゃい!!

カッコで囲ってないくせに内包ってなんじゃいな!!!

そもそも内包とは?

と、ココまで書いてから「そもそも内包ってなんなんだ?」と思い調べてみました。内包というのは、[]で包まれていることではなく、数学の用語の一つだそうです。

                                  終
                         --------------------
                           制作・著作 NHK

…もうちょっとだけ説明しますね。

数学で集合を定義するとき、「集合に含まれる要素をすべて列挙するやり方」と「集合に含まれる要素が満たすべき条件を定めることで定義するやり方」があります。後者を内包というそうです。

例えば、1から10それぞれの二乗という集合は、Elixirの内包表記ではつぎのようになります。

for i <- 1..10, do: i*i

数学で内包で書くとこのような集合になります。

\{x|i \in \{1,2,\cdots,10\},x=i^2\}

Elixirの内包表記は数式そのまんまだったことがわかりました。まさに「内包」表記です。

Goのコードは読みにくい

基本的に人間はFの字で文を読もうとします。そのため、重要情報は縦で揃えると読みやすくなります。

最悪な点: if文を無視して読むことが出来ない

Goでは以下のような構文が頻出します。

if err := hoge(); err != nil {
}

次の問題をこの構文は抱えています。

  1. if文なのに条件式のところが処理になってしまっている
  2. err != nilerr == nilで意味が真逆になってしまうので、最後まで読まなければ意図がつかめない

通常、if文は飛ばしならが読むことが出来ます。なぜなら、リーダブルにコードを書くと、if文は「ある特定のパターンのときのみ処理する」ように書けるからです。特定パターンのとき以外、if文を読む必要がないということです。

しかし、Goの場合はif内に処理が組み込まれてしまいます。そのため、水平に最後までifを読まなければならず、読むスピードがガクッと下がります。

良い点: 型を後ろに書ける

最悪な点を先に書きましたが、Goの構文にはいいところもあります。最高な点ではないのが残念ですが。

var x float32 = 1
func fuga(n Network) {
}

重要な情報(変数名)が先で、修飾語(型)が後ろに置いてあるので、流れるように読むことが出来ます。

ちょっとフックがあれば知ってるけど、意外と知らないJavaScript技術

JavaScript技術は10年前とは比較にならないほど膨大で緻密になっています。それらはアンテナを張っていなければ見落としてしまいます。今回はそんな技術の一端を紹介します。

紹介する技術たち

  • Web Worker + Service Worker
  • SharedArrayBuffer + Atomics API
  • manifest.json
  • WebRTC
  • WebSocket
  • SIMD.js
  • WebAssembly(wasm), asm.js

それぞれについて簡単に解説をしています。さらに深く知りたい方はおすすめ記事を参照ください。

続きを読む