Webpack3+React16コード分割の実装

Webpack3+React16コード分割の実装

プロジェクトの背景

最近、webpackのバージョンが古いプロジェクトがあります。 リーダー層では今のところアップグレードやフレームワークの変更が受け入れられないのでo(╥﹏╥)o、現状のままで最適化するしかありません。

webpack3 + react16

webpack v3 構成チェック

プロジェクト構成が v1 から継承されていることは明らかです。v1 から v3 へのアップグレードは比較的簡単です。公式 Web サイト https://webpack.js.org/migrate/3/ を参照できます。

ローダーがルールになる
連鎖ローダーはサポートされなくなり、json-loaderを設定する必要がなくなりました。
UglifyJsPluginプラグインは最小化を有効にする必要があります

既存のパッケージの問題を分析する

図に示すように、webpack-bundle-analyzerを使用してパッケージをビルドした後

問題は明らかです:

より大きなパッケージ zxcvbn を除き、コードはベンダーとアプリに単純にパッケージ化されており、ファイルは非常に大きくなります。

動的インポート分割ベンダー

ベンダー コードを分析します。libphonenumber.js などの一部の大きなパッケージは頻繁に使用されません。それらを取り出して、関連する機能が使用されるときに要求します。

公式のReactコード分割ガイドを参照してください。https://react.docschina.org/docs/code-splitting.html#import

'google-libphonenumber' から { PhoneNumberUtil } をインポートします
関数usePhoneNumberUtil(){
  // PhoneNumberUtil を使用する
}

動的import()メソッドに変更すると、非同期データを取得するためにasync/awaitの両方がサポートされます。

const LibphonenumberModule = () => import('google-libphonenumber')
関数usePhoneNumberUtil(){
  LibphonenumberModule().then({PhoneNumberUtil} => {
    // PhoneNumberUtil を使用する
  })
}

Webpack はこの構文を解析すると、自動的にコード分割を実行します。

変更された効果:

libphonenumber.js (1.chunk.js) はベンダーから分離されており、プロジェクトの実際の動作では、usePhoneNumberUtil プロセスに入るときにのみ、libphonenumber.js ファイルがサーバーに要求されます。

ルートベースのコード分割

リアクトレイジー

React の公式コード分割ガイド「ルートベースのコード分割」(https://react.docschina.org/docs/code-splitting.html#route-based-code-splitting) を参照してください。

分割前の例:

'react' から React をインポートします。
'react-router-dom' から Route、Switch をインポートします。
const Home = import('./routes/Home');
About = import('./routes/About');

定数App = () => (
<ルーター>
 <Suspense fallback={<div>読み込み中...</div>}>
  <スイッチ>
   <ルートの正確なパス="/" コンポーネント={Home}/>
   <ルート パス="/about" コンポーネント={About}/>
  </スイッチ>
 </サスペンス>
</ルーター>
);

分割後の例:

React をインポートします。{ lazy } から 'react';
'react-router-dom' から Route、Switch をインポートします。
const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));

定数App = () => (
// ルーティング設定は変更されません)

分割後の効果:

app.js はルートに応じて webpack によって自動的に別のファイルに分割されます。ルートが切り替えられると、対象のルートコードファイルがプルされます。

名前付きエクスポート

この段落は https://react.docschina.org/docs/code-splitting.html#named-exports から引用されています。

React.lazy現在、デフォルトのエクスポートのみをサポートしています。インポートされたモジュールで名前付きエクスポートを使用する場合は、デフォルト モジュールとして再エクスポートする中間モジュールを作成できます。これにより、ツリー シェイキングが失敗せず、不要なコンポーネントが含まれないことが保証されます。

// 多くのコンポーネント.js
エクスポート const MyComponent = /* ... */;
エクスポート const MyUnusedComponent = /* ... */;
// MyComponent.js
"./ManyComponents.js" から { MyComponent をデフォルトとして } をエクスポートします。
// MyApp.js
React をインポートします。{ lazy } から 'react';
const MyComponent = lazy(() => import("./MyComponent.js"));

AsyncComponent を自分で実装する

React.lazy でラップされた遅延読み込みルーティング コンポーネントは Suspense を追加する必要があります。強制したくない、または遅延実装を自由に拡張する必要がある場合は、AsyncComponent を定義および実装し、遅延と同じように使用できます。

'./components/asyncComponent.js' から AsyncComponent をインポートします。
const Home = AsyncComponent(() => import('./routes/Home'));
const About = AsyncComponent(() => import('./routes/About'));
// 非同期ロードコンポーネント
関数 AsyncComponent(getComponent) {
 戻りクラスAsyncComponentはReact.Componentを拡張します{
  静的コンポーネント = null
  状態 = { コンポーネント: AsyncComponent.Component }

  コンポーネントマウント() {
   if (!this.state.Component) {
    getComponent().then(({ デフォルト: コンポーネント }) => {
     AsyncComponent.Component = コンポーネント
     this.setState({ コンポーネント })
    })
   }
  }
  // コンポーネントはアンマウントされます
  コンポーネントのマウントを解除します(){
   // setState 関数を書き換え、何も返さない
   this.setState = () => {
    戻る
   }
  }
  与える() {
   const { コンポーネント } = this.state
   if (コンポーネント) {
    <Component {...this.props} /> を返します。
   }
   nullを返す
  }
 }
}

一般的なビジネスコード分割

ルートベースのコード分割が完了した後、パッケージ サイズを注意深く確認したところ、パッケージの合計サイズが 2.5M から 3.5M に増加していることがわかりました。

Webpack 分析ツールから、各ルーティング コードがコンポーネント、ユーティリティ、ロケールなどの個別のパブリック ファイルでパッケージ化されていることが原因であることが分かります。

webapck 構成を使用して、共通部分を個別にパッケージ化します。

コンポーネントファイルのマージとエクスポート

この例では、コンポーネントの下にあるすべてのファイルをまとめてエクスポートします。他のファイルについても同様です。

関数 readFileList(dir, filesList = []) {
 定数ファイル = fs.readdirSync(dir)
 files.forEach((item) => {
  fullPath = path.join(dir, item) とします。
  const stat = fs.statSync(fullPath)
  (stat.isDirectory())の場合{
   // すべてのファイルを再帰的に読み取る readFileList(path.join(dir, item), filesList)
  } それ以外 {
   /\.js$/.test(fullPath) && filesList.push(fullPath)
  }
 })
 ファイルリストを返す
}
exports.commonPaths = readFileList(path.join(__dirname, '../src/components'), [])

共通から抽出されたWebpack構成

'**' から conf をインポートします。
モジュール.エクスポート = {
 エントリー: {
  共通: conf.commonPaths、
  インデックス: ['babel-polyfill', `./${conf.index}`],
 },
 ... //その他の設定プラグイン:[
  新しい webpack.optimize.CommonsChunkPlugin('common')、
  ... // その他のプラグイン
 ]
}

CommonsChunkPlugin は、webpack3 でサードパーティのライブラリと共通モジュールを抽出するために使用されます。渡されるパラメータcommonは既存のエントリのチャンクであり、共通モジュールのコードがこのチャンクにマージされます。

共通コードから抽出

各ルートの重複コードを抽出すると、パッケージの合計サイズは再び 2.5M になります。追加の共通バンドル ファイルがあります。 (コモンは大きすぎるので、実際にはさらに分割できます)

要約する

webpack パッケージングには、最適化できる領域がまだたくさんあります。また、webpack のバージョンによっても違いがあります。アンパックの考え方は、共通するものを抽出し、使用シナリオに応じてオンデマンドでロードすることです。

Webpack3+React16 コード分割の実装に関するこの記事はこれで終わりです。Webpack3+React16 コード分割に関するより関連性の高いコンテンツについては、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き閲覧してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • Reactはページコード分割とオンデマンド読み込みを実装します
  • React でコード分割を実装する 4 つの方法

<<:  インストールされていないバージョンの MySQL を使用する手順とパスワードを忘れた場合の解決策

>>:  Linux で仮想コンソール セッションをロックする方法

推薦する

mysql の認証、起動、およびサービスの起動のための一般的なコマンド

1. 4つの起動方法: 1.mysqld MySQL サーバーを起動します: ./mysqld --...

Vueプラグインの実装で発生した問題の概要

目次シーン紹介プラグインの実装問題1: 重複したヘッダーコンポーネント質問2: 別の実装アイデア質問...

jQueryは従業員情報の追加と削除の機能を実装します

この記事では、従業員情報の追加と削除の機能を実装するためのjQueryの具体的なコードを参考までに共...

Vue で親コンポーネントから子コンポーネントにデータを渡すいくつかの方法

最近、Vue のソースコードを勉強していて、Vue で親コンポーネントと子コンポーネント間でデータを...

MySQL 5.7 解凍版のインストール、アンインストール、および文字化けしたコードの問題のグラフィック解決

1. 解凍版のインストール(1)圧縮パッケージをダウンロードし、ディスクの場所に解凍します。圧縮パッ...

CentOS7 で docker を使用して Apollo 構成センターをデプロイする実装

Apollo オープンソース アドレス: https://github.com/ctripcorp/...

Python の MySQL データベース LIKE 演算子の詳細な説明

LIKE 演算子は、列内の指定されたパターンを検索するため、WHERE 句で使用されます。文法: 列...

LED を使って Linux カーネルを使い始める方法を探る

目次序文LEDトリガー探索を始めるLEDデバイス登録LEDディレクトリ類推によって理解するクラスディ...

Alibaba Cloud サーバーの購入とインストール方法

1. サーバーを購入するこの例では、購入したサーバーはAlibaba Cloudです。大学生はAli...

ウェブページの画像を素早く表示する方法とテクニック

1. .jpg ではなく .gif を使用します。GIF は JPG に比べてサイズが小さくなります...

ブラウザの自動更新を実装するReactサンプルコード

目次フロントエンドルーティングとは何ですか?フロントエンドルーティングを実装するにはどうすればいいで...

Vue.js フロントエンドフレームワークにおけるイベント処理の概要

1. v-onイベント監視DOM イベントをリッスンするには、v-on ディレクティブを使用します。...

固定ボトムコンポーネントを実装した Vue の例

目次【効果】 【実施方法】 【効果】 【実施方法】 <テンプレート> <div i...

CSS の ::before と ::after 疑似要素について知らないこと

CSS には、一般的には使用されない 2 つの疑似クラス、before と :after があります...

Linux で MySQL のルート パスワードを変更する方法

序文このサービスは数か月前からMySQLに導入されています。私の仕事は基本的にターミナルで行われるた...