Wiz テックブログ

Wizは、最新のIoTやICTサービスをお客様に届ける「ITの総合商社」です。

Snowpack 試してみました

皆さんこんにちは、フロントエンドエンジニアの高野です。

皆さんはJSのバンドラーは何を使われていますか?

私たちフロントエンドチームでは主にwebpack、一部browserifyを使用しています。

最近はReactやVueをブイブイ使いビジネスロジックをもつことも多くなっており、そのためJSのバンドルサイズは嵩む一方です。

そうなってくると気になるのはビルド時間です。

私の担当しているプロジェクトでもwebpackのビルドが34秒かかっており、今後さらにプロジェクトが大きくなれば1分越えも夢ではないです...

そこで、Snowpack v3をにチャレンジしてみました。

Snowpackとは

Snowpackは初回(v1.0.1)リリースが1年前と、比較的新しいフロントエンドのビルドツールです。

SnowpackはPikaが中心で開発しており、この団体は今よりもwebを90%早くする!!という大きな目標を掲げていて、その一環としてのプロジェクトがSnowpackのようです。

また、PikaはSkypackも開発しています。

www.pika.dev  

Pikaのaboutページに書かれている内容を一部抜粋します。

ES module syntax (ESM) is JavaScript's latest native module system. Officially ratified in 2015, its import / export syntax is more compact, more easily analyzed and more reliably optimized. This all results in smaller, faster JavaScript on the web.

Unfortunately, most sites still generate a single "oldest browser" bundle, which means that every user (even the majority using modern browsers) get over-compiled JavaScript bundles that don't support ESM.

Pika is working to build better tools and services that make modern, ESM-focused JavaScript more accessible to package authors and application developers.

 

deepL訳+細かい部分微調整したもの

ESモジュール構文(ESM)は、JavaScriptの最新のネイティブモジュールシステムです。2015年に正式に批准されたこのESMのimport/export構文は、よりコンパクトで、より解析が容易で、より確実に最適化されています。これにより、Web上でのJavaScriptの軽量化、高速化が実現します。

残念ながら、ほとんどのサイトではいまだに単一の「一番古いブラウザ用」バンドルが生成されており、これはすべてのユーザー(モダンブラウザを使用している大多数のユーザーでさえも)がESMをサポートしていない無駄にコンパイルされたJavaScriptバンドルを使用しなければならないことを意味します。

Pikaは、ESMに焦点を当てた最新のJavaScriptを、パッケージ作成者やアプリケーション開発者がより利用しやすいものにする、より良いツールやサービスの構築に取り組んでいます。

ということで、SnowpackもESMをフル活用する仕組みになっています。

ESMについて

ご存知の方はこちらの項目は読み飛ばしていただけたらと思います。

元々JSにはモジュールという仕様がなかったのですが、JSで中〜大規模な開発が行われ始めると、その必要性からモジュールの仕様がいくつか誕生しました。(CommonJS, AMDなど)

そしてさらに時は流れ、ES2015でESModule(略称ESM)という仕様が策定されました。

仕様が乱立していると色々と不便ですので、公式が仕様を定めてくれるのはありがたいことです。

当然ESModuleで一本化しようという流れになっています。

...IE(とその他レガシーブラウザ)以外は。

f:id:iricocco:20210119135256p:plain

 

つまり、ESMをフル活用する場合のSnowpackでは、IE11は切るしかありません。
(Snowpackでバンドルしてしまう方法もあります。)

JSモジュールの仕様についての歴史は、下記の記事がとても良くまとまっていたので紹介させていただきます。

uuuundefined.tokyo

最近のJSビルドツール事情

f:id:iricocco:20210119152900p:plain

www.npmtrends.com

npm trendsで確認すると、webpackの一人勝ちといった様子です。

Snowpackは新参者ということもあり、競争上はまだまだと言えます。

また、 2020年のstateofjsにおけるUsage(使用ランキング)でもwebpackはぶっちぎりです。

f:id:iricocco:20210119154403p:plain

2020.stateofjs.com

しかし特筆すべきなのは、満足度/関心で今熱いのはesbuildとSnowpackということです。

実は、何がそんなにユーザーを惹きつけているのか気になり、この記事を書くに至りました。

【Satisfaction: 満足度】

f:id:iricocco:20210119154527p:plain

【Interest: 関心】

f:id:iricocco:20210119154510p:plain

Snowpackの仕組み

通常設定では、Snowpackはバンドルを行いません。

先ほど説明したESMありきの構成なので、実際のバンドルはブラウザ標準のESMの方で行います。

これにより、従来のバンドルされた単一JSファイルでは出来ないことができるようになっています。

・全てを再ビルドする必要がない

単一JSバンドルの場合、たとえ1ファイルの一行を更新しただけだとしても、全てを再ビルドする必要があります。

しかし、ESMを利用したSnowpackであれば更新のあったファイルのみを更新し、その他はキャッシュを利用することができます。  

・自然にコードスプリッティングされる

依存パッケージが多数ある場合は、単一のJSだと初期ロードがとても重くなってしまいます。

それを解決するためにコードスプリッティングを行いますが、Snowpackだと依存ファイルはブラウザでバンドルされますので、自然にファイルが分割されます。

また、それぞれのビルドファイルは個別に作成され、無期限にキャッシュされます。  

そうはいってもnpm公開パッケージの中にはCommonJSというESM仕様でないものも多いです。

では、一つでもESMに準拠していないパッケージがあった場合は、Snowpack式を諦めてバンドルしなければいけないのでしょうか?

 

実はそうではなくて、Snowpackはそのようなパッケージを個別に処理してくれます。

一つ一つの依存関係のファイルを個別にバンドルし(例えばreact なら react.js、 react-domなら react-dom.js)、それをimportするというのです!

依存ファイルは滅多に更新されないので、こういったバンドル作業もほとんど発生しません。

 より詳しく知りたい方は公式の「How Snowpack Works」を参照ください。

www.snowpack.dev

また、小規模であればブラウザのESMによるバンドルでも問題ありませんが、大規模化してくるとやはりバンドルでの最適化が必要になってきます。

Snowpackではバンドルを行うように切り替えることも可能です。

www.snowpack.dev

Snowpackのビルドをめっちゃ早くできる話

実は2021年1月13日にSnowpack v3が公開されました🎉

このアップデートにより内部のバンドルツールにesbuildを採用できるようになりました。

esbuild.github.io

esbuildはGoで記述されたビルドツールで、本当に魔法のように早いのが売りです。

実際ベンチマークテストでは、他のツールより10~100倍早い結果となっています。

f:id:iricocco:20210119171739p:plain

私自身もesbuild単体でどれくらいスピードが上がるかテストしました。 下記がtimeコマンドで計測した結果です。

【Webpack】
real 0m4.018s 
user 0m3.989s
sys 0m0.585s

【esbuild】
real 0m0.451s
user 0m0.494s
sys 0m0.090s

real・・・プログラムの呼びだし~終了までの時間
user・・・プログラム自体の処理時間
sys・・・プログラムを処理するために、OSが処理をした時間

軽いプロジェクトで試したためなのか100倍は行きませんでした...が、

あきらかにスピードアップしています。

とは言っても、esbuildはまだバージョンがv0.8.33なので、これから成長していくプロジェクトです。

Snowpackがesbuildを採用できたのは、buildありきでバンドルはその後の最適化であるという設計に基づいていたからだと語られていました。

www.snowpack.dev

これからの成長に目が離せません。

Snowpack曰く、

esbuild is still a young project, but it’s future looks promising. In the meantime, we will also continue to invest in the existing Webpack & Rollup bundler plugins for a long time to come.

deepL訳+微調整

esbuildはまだ若いプロジェクトですが、将来性が見込めます。その間、既存のWebpack&Rollupバンドルプラグインへの投資も今後も長く続けていきます。

とのことです💰

Snowpackを実際に使ってみる

Snowpackに対するモチベーションが上がったところで、実際にReactのプロジェクトを下記のチュートリアルを参考にビルドしてみます。

www.snowpack.dev

 

まずは、craeate-snowpack-appコマンドを用いてアプリの土台を作成します。

テンプレートには今回使用するminimalのみでなく、lit-elementreactsveltevueなどが準備されています。

snowpack/create-snowpack-app/cli at main · snowpackjs/snowpack · GitHub

npx create-snowpack-app react-snowpack --template @snowpack/app-template-minimal

react-snowpackは作成するフォルダ名です。

--template @snowpack/app-template-minimal オプションをつけるとminimalというテンプレートが適用され、今回のチュートリアル用のシンプルな状態で構築してくれます。

 

下記コマンドでローカルサーバーを起動しましょう。

cd react-snowpack
npm run start

localhost:8080にて下記の画面が表示されればOKです。

f:id:iricocco:20210119161107p:plain

下記コマンドで依存パッケージをインストールします。

npm install react react-dom --save

Snowpackは.jsxextensionを見つけるとJSXをサポートしてくれます。

なので、index.jsindex.jsxにリネームします。

index.htmlのscriptタグのindex.jsはリネームする必要はありません。

なぜならコンパイル後は.js形式に変換してくれるからです。

 mv index.js index.jsx

index.htmlにidを振ったdivを配置し、reactを動かします。

-  <h1>Welcome to Snowpack!</h1>
+  <div id="root"></div>
- console.log('Hello World! You did it! Welcome to Snowpack :D');
+ import React from 'react'
+ import ReactDOM from 'react-dom'
+ ReactDOM.render(<div>"HELLO REACT"</div>, document.getElementById('root'))

 f:id:iricocco:20210119170449p:plain 無事マウントできました。

ビルドするためにほとんど設定ファイルを書かずに済んだのがわかるかと思います。

本記事ではここまでとしますが、公式チュートアルではHMRやFast Refresh、ファイル構成の変更などのやり方を学ぶことができるので、興味のある方はご確認ください。

Snowpack 3.0 で追加されたStreaming Imports

先日リリースされたver 3ですが、esbuildが組み込まれた以外にもStreaming Importsという面白い機能が追加されていました。

npm installしなくても、依存パッケージ使えるようにしちゃおうよ!

というとんでもない機能です。

import * as React from 'react'; //これを

import * as React from 'https://cdn.skypack.dev/react@17.0.1'; // こう解釈しちゃう

importを実行するとinstall済みのnode_modulesではなく、Skypack配信のCDNを読み込みに行く動作をします。

👨‍🦰「待て待て、そんなことしたらオフラインで動作できないじゃないか!」

と思われるかもしれませんが、一度ロードしたデータはキャッシュしますので、2回目以降はオフラインでも動作します。

かなり先進的な機能ですが、オプトイン式なので、使いたい人だけ使用することができます。

installしなくていい未来など想像していなかったので、個人的にとても衝撃的でした。

まとめ

シェアなどを見ると今すぐ採用するのはまだためらわれるところですが、非常に未来を感じるプロジェクトだと思いました!

今後も伸びていく予感がしています!

動向をチェックしつつ、機会があれば担当のプロジェクトに導入していきたいと思っています。

最後に...

Wizではエンジニアを募集中です。

興味のある方は是非覗いてみてください!↓

careers.012grp.co.jp