Webpack 4によるフロントエンド配送の最適化


最新の主要なWebpackのリリース(バージョン4 . x)では、私たちは、あなたが始めるために設定を必要としない点にいます.これはデフォルトで調整されています.ので、手動で追加し、設定のようなプラグインCommonsChunkPlugin , UglifyjsWebpackPlugin , ETCは、自動的に生命をより簡単にするフードの下でWebpackによってインスタンス化されます!
いくつかのことがありますが、我々はまだWebPackを最大限に利用していることを確認するために行うことができます.一人ずつやりましょう.

モード
Webpack 4には2つのモードがあります.production and development . Webpackをフラグで実行する--mode development|production または設定ファイルの設定をデフォルトで最適化することができます.
オプション
説明development提供process.env.NODE_ENV 値付きでdevelopment . 許可NamedChunksPlugin and NamedModulesPlugin .production提供process.env.NODE_ENV 値付きでproduction . 許可FlagDependencyUsagePlugin , FlagIncludedChunksPlugin , ModuleConcatenationPlugin , NoEmitOnErrorsPlugin , OccurrenceOrderPlugin , SideEffectsFlagPlugin and UglifyJsPlugin .
ので、手動でこれらのプラグインを含めるか、設定する必要はありませんNODE_ENV 使用DefinePlugin , それはすべて使用するときに注意したmode .
ところで、あなたはまだカスタムparamsUglifyJsPlugin , 私が望むのは、インストールすることでできます.npm install uglifyjs-webpack-plugin --save-dev 次に、WebPack設定でカスタムパームを指定します.
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');  

if (process.env.NODE_ENV === 'production') {  
  config.optimization = {  
    minimizer: [  
      new UglifyJsPlugin({  
        parallel: true,  
        cache: true,  
        sourceMap: true,  
        uglifyOptions: {  
          compress: {  
            drop_console: true  
          }  
        },  
      }),  
    ],  
  };  
}
それは基本的にWebpackのデフォルトのミニマイザのインスタンスを自分自身でオーバーライドします.
この設定では、Ullifierが並列モードで動作し、次のビルドで再利用する出力がキャッシュされ、ソースマップを生成し、生産モードで実行するときにコンソール内のコメントを抑制します.あなたは利用可能なオプションの完全なリストを見つけることができますhere .

ハッシュ
デフォルトでは、webpackは出力ファイル名にキャッシュバッシングハッシュを追加しません.index.7eeea311f7235e3b9a17.js ). それで、あなたのユーザーはあなたが奇妙な振舞いとバグの多くをもたらすことができたリリースをする次の時、最新のコードを得ないかもしれません.
だから、すべてのビルド後にあなたの資産をリフレッシュするにはhash ファイル名:
module.exports = {
  entry: {
    vendor: './src/vendor.js',
    main: './src/index.js'
  },
  output: {
    path: path.join(__dirname, 'build'),
    filename: '[name].[hash].js'
  }
};
あなたがそれについて考えるならば、それは少し重い手であるようです.どのような変更がない場合はvendor.js , Webpackがスマートで、変更されたチャンクのハッシュだけを更新するならば、それは素晴らしいでしょう.そのように、クライアントは、何も変化しなくても、新しいビルドを出すたびに、再びすべての資産をダウンロードする必要はありません.
それを確実にするために、Webpackは提供しますchunkhash . ChunkHashは、すべてのビルドではなく、各エントリポイントの内容に基づいています.これは簡単です.
module.exports = {
  ...
  output: {
    ...
    filename: '[name].[chunkhash].js'
  }
};
これは、我々が両方の世界の最高を得ていることを確認します.新しいリリースが出ると、クライアントはまだ変更されていないファイルのキャッシュされたバージョンを使用している間、更新されたファイルを取得します.

バベル
蒸散
すべてのブラウザがES 6/7/次の機能をサポートしていないので、何が動作し、ブラウザ上では、すぐにはminefield :

それで、それはバベルが入るところです.これは、近代的なJavaScriptを風を書くようにいくつかの驚くべきプラグインを提供して近代的なJSを変換することによって、我々は指定したすべてのブラウザで動作するようになります.
インストールするには以下のように設定します:npm install babel-core babel-loader babel-preset-env --save-dev今、あなたは我々が平易な英語で目標にしたいBabelを話すことができますbrowserslist 構文.babelrc プロジェクトフォルダのルートで
{  
  "presets": [  
    ["env", {  
      "targets": {  
        "browsers": ["last 2 versions", "safari >= 9"]  
      }  
    }]  
  ]
}
これはenv preset 自動的に、あなたが指定した環境に基づいて必要なBabelプラグインを決定します.
最後に、Webpackでは、JavaScriptをBabelと入れ替えたいものを知っておきたいと思います.
module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {  
            cacheDirectory: true  
          }
        }
      }
    ]
  }
};
今すぐBabelとしてブラウザの互換性の世話をするすべての最新のJavaScriptの構文を自由に使用することができます.
ダイナミックインポート
だから、バベルを使用する次の利点は、パフォーマンスに関連する.我々はそれを使用することができますdynamic import plugin あなたがそれらを必要とするときだけ、大きい依存関係を非同期にロードするために、別名怠惰なローディング.これはWebpackが依存性ツリー全体を一度にロードする必要がないため、エントリポイントファイルのサイズに劇的な影響を与える可能性があります.
インストールするには以下のように設定します:npm install syntax-dynamic-import --save-dev そして、あなたにそれを加える.babelrc
{  
  "presets": [  
    ...
  ]
  "plugins": ["syntax-dynamic-import"]
}
では、以下のようなモジュールを作ります:
import foo from 'foo'
import bar from 'bar'
import baz from 'baz'

const myfun = () => {  
  //Do something with the modules here  
}
に変換できます.
const myfun = () => {  
  return Promise.all([  
    import('foo'),  
    import('bar'),  
    import('baz'),  
  ]).then(([foo, bar, baz]) => {  
    //Do something with the modules here  
  });  
};
Webpackはこれらの動的なインポートを認識し、コードを別々のチャンクに分割します.これらは一旦Asyncmyfun が実行時に呼び出されます.これは、我々の最初のチャンクサイズが小さいままであることを確認します、そして、クライアントはそれさえ必要としないかもしれないリソースをダウンロードする必要はありません.
サイドノートは、Vueを使用している場合、これはボックスからサポートされていますAsync Components しかし、もちろん、あなたがこのような一般的な解決を必要とするように、単独で十分でない様々なフレームワークで大きなアプリケーションを扱っているならば.

予圧
私たちが最適なコード分割をしたので、1つの欠点はクライアントがまだ実行時にそれらの依存関係をロードしなければならないということです.したがって、上の例ではmyfun , クライアントが最初にロードする必要がありますfoo , bar and baz 関数を実行する前に.
バックグラウンドでこれらの依存関係をpreloadすることができるならば、我々が呼ぶ時間によってmyfun これらの依存関係はすでに利用可能であり、準備ができていますか?それがどこだpreload plugin 入る.

これはPreload Web標準は、ブラウザーに、特定のリソースがすぐにそれをロードすることができるようにすぐに必要とされることを知っているようにします.
インストールするには以下のように設定します:npm install --save-dev preload-webpack-plugin html-webpack-plugin それから、あなたのwebpack configにそれを加えてください:
const PreloadWebpackPlugin = require('preload-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin')

plugins: [
  new HtmlWebpackPlugin(),
  new PreloadWebpackPlugin({
    rel: 'preload',
    include: 'asyncChunks'
  })
]
それだ!今、すべてのasyncチャンクがHTMLに追加され、このようにプリロードされます.
<link rel="preload" as="script" href="chunk.31132ae6680e598f8879.js">
<link rel="preload" as="script" href="chunk.d15e7fdfc91b34bb78c4.js">
<link rel="preload" as="script" href="chunk.acd07bf4b982963ba814.js">
Webpack 4.6 +のように、これは来ますbuilt in Webpackが上記のプラグインをインストールする必要なしに自動的にリソースヒットとして出力するインラインインポートディレクティブを使用してプリロードまたはプリフェッチする依存関係を手動で指定できます.
したがって、上記のインポート文で変更する必要があります.
import("foo");
import("bar")
次のようになります.
import(/* webpackPrefetch: true */ "foo");
import(/* webpackPreload: true */ "bar")
ですから、Preloadプラグインを使用してプロジェクト全体の設定ファイルからプリロードの優先度を管理するかどうか、または個々の開発者に任せたい場合、どの依存関係をプリロード/プリフェッチしなければならないかを決めることができます.
最後に、プリフェッチまたはプリロードを使用する場合は、慎重に考慮する必要があります.これはリソースとアプリケーションコンテキストに依存します.あなたにポイントしますthis 優れたライティングAddy Osmani 両者の微妙な違いを理解する.一般的には

Preload resources you have high-confidence will be used in the current
page. Prefetch resources likely to be used for future navigations
across multiple navigation boundaries.



アナライザ
WebPackの設定を最適化する方法をいくつか見てきましたので、さらに最適な状態であることを確認するために、より多くのコードと依存関係を追加するように、バンドルに目を向けたいと思います.私の二つの好きなツールは以下の通りです.
Webpack Bundle Analyzer

インストールするには以下のように設定します:npm install --save-dev webpack-bundle-analyzer それから、あなたのwebpack configにそれを加えてください:
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

if (process.env.NODE_ENV !== 'production') {
  config.plugins.push(new BundleAnalyzerPlugin())
}
次に、開発モードでWebPack devサーバーを起動すると、次のように移動できますhttp://localhost:8888 上記のようなバンドル可視化を見るには
Webpack Monitor

これは私の2番目のお気に入りのツールですが、それはWebpackバンドルアナライザと同じ情報を示しますが、わずかに異なる方法で時間をかけてバンドルの履歴を監視する方法を提供することに加えて.
インストールするには以下のように設定します:npm install --save-dev webpack-monitor それから、あなたのwebpack configにそれを加えてください:
const WebpackMonitor = require('webpack-monitor');

// ...

plugins: [
  new WebpackMonitor({
    capture: true, // -> default 'true'
    target: '../monitor/myStatsStore.json', // default -> '../monitor/stats.json'
    launch: true, // -> default 'false'
    port: 3030, // default -> 8081
    excludeSourceMaps: true // default 'true'
  }),
],
あなたは以前のプラグインのような開発でこれを実行したり、生産ビルドのためにこれを実行したり、どこかに出力をエクスポートすることができますので、どのように生産バンドルが変更されたかを分析することができます.

結論
それはすべての人々です!うまくいけば、すべてのこれらのテクニックを使用すると大幅にバンドルのサイズを削減し、パフォーマンスを向上させることができます.どうやって行けばいいか教えてください.私が逃した他のテクニックはありますか?コメントを残す!
この投稿は当初公表されたmy blog . あなたがこのポストが好きであるならば、それをソーシャルメディアと共有してください!