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 で乱数を生成し、文字列を連結する方法の例

この記事では、MySQL が乱数を生成し、文字列を連結する方法について例を使用して説明します。ご参考...

HTMLボタンを中央に配置する方法

HTML ボタン自体を中央に配置するにはどうすればよいでしょうか? このアイデアは簡単に見つかります...

JavaScriptはシンプルな計算機能を実装します

この記事では、参考までに、簡単な計算機を実装するためのJavaScriptの具体的なコードを紹介しま...

Centos での TCPWrappers アクセス制御の実装

1. TCP ラッパーの概要TCP Wrappers は TCP サービス プログラムを「ラップ」し...

この記事では、VUE の複数の DIV とボタン バインディングの Enter イベントを実装する方法を説明します。

現在、OK ボタンをクリックしたときやキーボードの Enter キーを押したときに操作を実行するとい...

よく知られているブラウザのDOCTYPEモード選択メカニズム

ドキュメントの範囲この記事では、Firefox やその他の Gecko ベースのブラウザ、Safar...

CSS変数がJSインタラクティブコンポーネント開発にもたらす改善と変更のサンプルコードの詳細な説明

1. CSS変数がもたらす質的変化CSS 変数によってもたらされる改善は、CSS コードの節約や C...

Docker+nextcloudで個人用クラウドストレージシステムを構築

1. Dockerのインストールと起動 yum で epel-release をインストールします ...

Vue パッケージ化後の空白ページの解決策

1. vue-cli がプロジェクト パッケージを作成した後にページが空白になる問題の解決方法コマン...

ウェブサイトのコードブロックのpreタグにコピーコードボタンコードを追加します

他のよりプロフェッショナルなブログ システムを参照すると、コード ブロックにコードのコピー ボタンが...

Vue の新しい組み込みコンポーネントの使用方法の詳細な説明

目次1. テレポート1.1 テレポートの紹介1.2 テレポートの使用1.3 プレビュー効果2. サス...

Vue が学ぶべき知識ポイント: forEach() の使用

序文フロントエンド開発では、目的のコンテンツを取得するためにループをトラバースする必要がある状況に頻...

ハイパーリンクAタグを学ぶ

聞く: CSS を使用してハイパーリンクのスタイルを設定しましたが、ホバーしても機能しません。なぜこ...

MySQLパスワードを変更するいくつかの方法

序文:データベースを日常的に使用すると、パスワードが単純すぎて変更する必要がある場合、パスワードの有...

DockerにrockerChatをインストールし、チャットルームを設定するための詳細な手順

包括的なドキュメントgithubアドレスhttps://github.com/RocketChat/...