フロントエンドの最適化。 パート1。私はtreeshakingという言葉が好きではない理由、またはwebpackがあなたに嘘をついている場所



Yandex市場で購入品として使用する技術に関連しています。 仕様を確認し、レビューを読んで、プロジェクトがgithubで多くの星を受け取った場合、仕様に従って、さらに はじめに 安価な、私たち彼 私たちは買う インストールします。 この方法では、レーキハンドルを非常に強く叩くことがありますが、それでも何が起こっているのかを把握する必要があります。







背景



ロールアップ作成者の1人による記事では、2つの最適化が検討されています 。1つはデッドコード除去と呼ばれ、もう1つはツリーシェーキングと呼ばれます 。 著者は、ツリーシェーキングにはコードを圧縮するためのより多くの機能があることを示しています。 そして、証拠として、彼はケーキのレシピと壊れた卵に関するいくつかの考慮事項を挙げています。 ああ、これらの比phor!







このアイデア(パイや卵に関するものではなく、ツリーシェイキングに関するもの)はwebpack開発チームによって取り上げられ、バージョン2.0から公式にサポートし始めました。







問題



技術が実際のプロジェクトで実際の結果をもたらした場合、私は書きません。 実際には、最終アセンブリのサイズはまったく減少しないか、統計誤差のサイズだけ減少します。







もちろん、一部の人は汚いトリックを推測し、 Habrで記事を書きさえします 。 しかし、少なくとも会議の訪問者や同僚の間では、webpackのデッドコードイルミネーションに対するツリーシェーキングの利点について推測するファンは少なくありません。







これはどのように機能するはずでしたか?



アイデアはタンクと同じくらい簡単です。







  1. コレクターはモジュールツリーを調べて、未使用のインポートに特別なコメントを付けます。 このように:

    ... /* unused harmony export square */ function square(x) { return x * x;} ...
          
          



  2. UglifyJSの次のステップは、デフォルトでwebpackにテープされますが、予想されるすべてに加えて、これらの同じコメントでマークされたコードを容赦なく切り取ります。
  3. 利益!


いつ機能しないのですか?



ドキュメントにあるようなものがすべて揃っているとしましょう。 2つのindex.jsおよびmodule.jsファイル







 // index.js import {cube} from './module' console.log(cube(x))
      
      





 // module.js export function square(x) { return x * x; } export function cube(x) { return x * x * x; }
      
      





ここでwebpackを最適化および最小化モードで実行すると、すべてが期待どおりに機能します。 ( コード







 webpack --optimize-minimize index.js out.js
      
      





しかし、もしあれば、babel-loaderの存在下でのエクスポートを伴う最小クラスでさえ、モジュールを含むファイルに追加され、書き込みはなくなります。 クラスは、バベルが吐き出す関数として最終アセンブリに分類されます。 ( コード







 //module.js export function square(x) { return x * x; } export function cube(x) { return x * x * x; } export class MyClass { print(){ console.log('find me'); } }
      
      





どうして起こったの?



問題は、UglifyJSが余分なものを投げることを恐れていることです。 それは理解できる:それが壊れないなら、それが数百バイト以上良くなるようにしましょう。







そして今、UglifyJSが入力として次のコードを受け取ることを想像してください。







 /* unused harmony export MyClass */ var MyClass = function () { function MyClass() { babelHelpers.classCallCheck(this, MyClass); } MyClass.prototype.turn = function print() { console.log('find me'); }; return MyClass; }();
      
      





バベルをコンパイルした後、MyClassはどういうわけかクラスとしての自覚から抜け出しました。 一般に、UglifyJSは、BabelチームがES5でのクラスの実装をどのように見ているかについてほとんど知りません。 最終的には、この不名誉を誰にも知らないままにしてしまいます。

webpackリポジトリにもバグがあり、 4番目のバージョンのすべてを修正することを約束します。

ちなみに、ロールアップはそれほど前のことではなく、数学を使った例にしか取り組みませんでしたが、最新バージョンではバグを修正しました。 ( 壊れた例動作例 )。







道徳



そのため、ツリーシェイキングを含むwebpackを購入したので、この方向でほとんどゼロのメリットが得られました。 そして今、木を揺さぶるという言葉は、私を神経質な笑い、しゃっくり、手に負えない皮肉にします。







そして、今どうするか?



始めるには、webpackをドロップして、これらの欠点や他の多くの欠点のない新しいコレクターを使用してください。 古典的なアセンブリに加えて、彼はクラフトビールを醸造し、チャバタバーガーを作ります。







申し訳ありませんが、抵抗できませんでした。







真剣に、状況を修正する非常に簡単な方法があります:







webpackが特別なディレクティブ/*#__PURE__*/



を追加する必要があります。これは、関数の形でこの未知のモンスターを自分自身に切り取ることができることをUglifyJSに伝えます。







ああ、これらの松葉杖。







そして、それは次のようになります:







 /* unused harmony export MyClass */ var MyClass = /*#__PURE__*/ function () { function MyClass() { babelHelpers.classCallCheck(this, MyClass); } MyClass.prototype.turn = function print() { console.log('find me'); }; return MyClass; }();
      
      





さらに2、3回繰り返し、静的型付けを発明します;)







実施例







ところで、新しいバージョンのbabel 7はすでにこれを行っています。 残念ながら、それはまだベータ版です。これは、今のところ使用できないことを示唆しています。 しかし、あなたが勇敢で決定的であれば、アップグレードを試みることができます。







今後は、現在有効なソリューションがいくつかあると思います。 次の記事でそれらについてお話します。 おそらく誰かが彼らの神経と時間を節約するでしょう。 そして、結論を出さなければなりません。







結論



  1. すべてを疑います。 情報を確認してください。 この記事でも。 これにより、多くの神経と時間を節約できます。
  2. javascriptエコシステムは、技術インターフェースでクラッシュすることがあります。 そして、ここでは、babelがES5のクラス形式についてwebpackを介してUglifyJSに何も言わなかったという事実により、誤解が現れました。 同時に、babelはほぼ修正しましたが、もちろんwebpackの人たちは次のリリースで修正せず、修正したいと思っています。


PSあなたもマーケターにfellれ、問題を解決する代わりにファッショナブルなテクノロジーを選択した場合は、コメントに書いてください。







フロントエンドの最適化。 パート2








All Articles