Help us understand the problem. What is going on with this article?

JSの最適化ツール「Prepack」を使ってみる

More than 3 years have passed since last update.

Prepackとは

  • Facebookから公開されたJSをAOTコンパイルするツール
  • コードの最適化を行う
    • どんな変換がされるかは、こちらの例のようになる
  • コンパイル時に計算できるものは計算しておくので、ランタイム時の動作が早くなる
  • まだ出たばっかりで初期の開発段階
  • こちらのロードマップを見る限り、Prepack単体でES6が動く状態になるのは、まだ先(中期以降)
    • つまりBabelなどのトランスパイラで変換したコードに対して、Prepackを実行するようにしないと変換できない

たまたま見つけたprepack-webpack-pluginっていうのを使って、どんな感じになるか見てみたいと思います
https://github.com/TheLarkInn/prepack-webpack-plugin

ググるとeslint-plugin-prepackrollup-plugin-prepack的なのも開発中?なんですね

設定

yarn add prepack-webpack-plugin --dev
webpack.config.js
const path = require('path')
const PrepackWebpackPlugin = require('prepack-webpack-plugin').default

module.exports = {
  entry: [
    path.join(__dirname, '../src/sample')
  ],
  output: {
    path: path.join(__dirname, '../dist'),
    filename: 'bundle.js',
    publicPath: '/'
  },
  plugins: [
    new PrepackWebpackPlugin()
  ],
  module: {
    rules: [
      {
        test: /\.js$/,
        use: 'babel-loader',
        exclude: /node_modules/
      },
    ]
  }
}

実行

こちらの公式サイトの例から取ってきたコードで実行
(公式サイトには5つ例があるが、2つはPrepackのInitializationErrorで動かなかったので、それ以外のコード3つになります)

sample.js
(function () {
  function hello() { return 'hello'; }
  function world() { return 'world'; }
  global.s = hello() + ' ' + world();
})();

(function () {
  function fibonacci(x) {
    return x <= 1 ? x : fibonacci(x - 1) + fibonacci(x - 2);
  }
  global.x = fibonacci(23);
})();

(function(){
  function fib(x) { return x <= 1 ? x : fib(x - 1) + fib(x - 2); }
  let x = Date.now();
  if (x === 0) x = fib(10);
  global.result = x;
})();

webpackでビルド

webpack

変換後 ↓

bundle.js
(function () {
  s = "hello world";
  x = 28657;

  var _$0 = Date.now();

  if (typeof _$0 !== "number") {
    throw new Error("Prepack model invariant violation: " + _$0);
  }

  result = _$0 === 0 ? 55 : _$0;
})();

sは文字列が連結された状態になってる
xは計算された状態になってる
resultもかなり最適化されてる

てかfunctionも1個になってるな

ES6のコード

これが1番どうなるか、見たかったのですが
ES6で書かれたコードをwebpackのbabel-loaderでトランスパイルして、それをPrepackできるか試してみます

ES6のアロー関数に変更 ↓

sample.js
(() => {
  function hello() { return 'hello'; }
  function world() { return 'world'; }
  global.s = hello() + ' ' + world();
})();

(() => {
  function fibonacci(x) {
    return x <= 1 ? x : fibonacci(x - 1) + fibonacci(x - 2);
  }
  global.x = fibonacci(23);
})();

(() => {
  function fib(x) { return x <= 1 ? x : fib(x - 1) + fib(x - 2); }
  let x = Date.now();
  if (x === 0) x = fib(10);
  global.result = x;
})();

webpackでビルド(webpack.configは上記のと同じ)

webpack

変換後 ↓

bundle.js
(function () {
  s = "hello world";
  x = 28657;

  var _$0 = Date.now();

  if (typeof _$0 !== "number") {
    throw new Error("Prepack model invariant violation: " + _$0);
  }

  result = _$0 === 0 ? 55 : _$0;
})();

ちゃんと変換されたー

速度に関して

いつものwebpackに加えて、Prepackをするので
当然ビルド速度は落ちるのですが、どのくらい違うのか見てみました

使用するコードは、上のsample.js

Prepack有り ↓

 2017-05-09 17.57.18.png

11085ms

Prepack無し
 2017-05-09 17.59.13.png

396ms

だいぶ遅い
けど、ファイルサイズを見てもかなり最適化されたのは分かる

そのうち速度は改善されるかもしれませんが、Prepackの目指す所はそこでは無いと思うので、
今後、速度に問題が残れば、自マシンで開発時にはPrepackを使わずに、
本番やステージングにてPrepackを適用するというやり方になるかもしれません

感想

webpackなどの他のツールと併用して使うやり方になるか、Prepack単体でいけちゃうのか、
今後どうなるか分からないが、すごく強力なツールになるかもしれないので、追って見ていこうと思う

kurosame
フロントエンドが得意です
https://portfolio-kurosame.netlify.app
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away