モジュール化の概念は、ほとんどの最新のプログラミング言語に固有の部分です。ただし、JavaScriptには、最新バージョンのECMAScript ES6が登場するまで、モジュール化への正式なアプローチがありませんでした。
今日最も人気のあるJavaScriptフレームワークの1つであるNode.jsでは、モジュールバンドラーで読み込みが可能です NPMモジュール Webブラウザーでは、コンポーネント指向のライブラリ(Reactなど)がJavaScriptコードのモジュール化を促進および促進します。
Webpack です 利用可能なモジュールバンドラーの1つ そのプロセス JavaScript コード、およびスタイルシート、画像、フォントなどのすべての静的アセットをバンドルファイルにまとめます。処理には、コンパイル、連結、縮小、圧縮など、コードの依存関係を管理および最適化するために必要なすべてのタスクを含めることができます。
ただし、Webpackとその依存関係の構成はストレスを伴う可能性があり、特に初心者にとっては必ずしも簡単なプロセスではありません。
これらのどれがサーバー側のWebアプリケーションの保護が難しい理由ではありません
このブログ投稿では、さまざまなシナリオに合わせてWebpackを構成する方法のガイドラインと例を示し、Webpackを使用したプロジェクトの依存関係のバンドルに関連する最も一般的な落とし穴を指摘しています。
このブログ投稿の最初の部分では、プロジェクトの依存関係の定義を単純化する方法について説明します。次に、複数ページおよび単一ページのアプリケーションのコード分割の構成について説明し、デモンストレーションします。最後に、プロジェクトにサードパーティのライブラリを含める場合は、Webpackを構成する方法について説明します。
相対パスは依存関係に直接関連していませんが、依存関係を定義するときに使用します。プロジェクトファイルの構造が複雑な場合、関連するモジュールパスを解決するのが難しい場合があります。 Webpack構成の最も基本的な利点の1つは、プロジェクト内の相対パスの定義を簡素化するのに役立つことです。
次のプロジェクト構造があるとしましょう。
- Project - node_modules - bower_modules - src - script - components - Modal.js - Navigation.js - containers - Home.js - Admin.js
必要なファイルへの相対パスによって依存関係を参照できます。ソースコードのコンテナーにコンポーネントをインポートする場合は、次のようになります。
Home.js
Import Modal from ‘../components/Modal’; Import Navigation from ‘../components/Navigation’;
Modal.js
import {datepicker} from '../../../../bower_modules/datepicker/dist/js/datepicker';
スクリプトまたはモジュールをインポートするたびに、現在のディレクトリの場所を把握し、インポートするものへの相対パスを見つける必要があります。ネストされたファイル構造を持つ大きなプロジェクトがある場合、または複雑なプロジェクト構造の一部をリファクタリングしたい場合、この問題がどのように複雑になるかを想像できます。
この問題はWebpackのresolve.alias
で簡単に処理できますオプション。いわゆるエイリアス(ディレクトリまたはモジュールの名前とその場所)を宣言できます。プロジェクトのソースコード内の相対パスには依存しません。
webpack.config.js
resolve: { alias: { 'node_modules': path.join(__dirname, 'node_modules'), 'bower_modules': path.join(__dirname, 'bower_modules'), } }
Modal.js
でファイル、datepickerをはるかに簡単にインポートできるようになりました。
import {datepicker} from 'bower_modules/datepicker/dist/js/datepicker';
スクリプトを最終バンドルに追加したり、最終バンドルを分割したり、オンデマンドで個別のバンドルをロードしたりする必要があるシナリオがあります。これらのシナリオのプロジェクトとWebpack構成のセットアップは、簡単ではない場合があります。
Webpack構成では、Entry
オプションは、Webpackに最終バンドルの開始点を指示します。エントリポイントには、文字列、配列、オブジェクトの3つの異なるデータ型を指定できます。
開始点が1つしかない場合は、これらの形式のいずれかを使用して同じ結果を得ることができます。
複数のファイルを追加する必要があり、それらが相互に依存していない場合は、配列形式を使用できます。たとえば、analytics.js
を追加できます。 bundle.js
の終わりまで:
webpack.config.js
module.exports = { // creates a bundle out of index.js and then append analytics.js entry: ['./src/script/index.jsx', './src/script/analytics.js'], output: { path: './build', filename: bundle.js ' } };
index.html
などの複数のHTMLファイルを含む複数ページのアプリケーションがあるとします。およびadmin.html
。エントリポイントをオブジェクトタイプとして使用することで、複数のバンドルを生成できます。以下の構成では、2つのJavaScriptバンドルが生成されます。
webpack.config.js
module.exports = { entry: { index: './src/script/index.jsx', admin: './src/script/admin.jsx' }, output: { path: './build', filename: '[name].js' // template based on keys in entry above (index.js & admin.js) } };
index.html
admin.html
CommonsChunkPlugin
webpack.config.js
両方のJavaScriptバンドルは、共通のライブラリとコンポーネントを共有できます。そのために、var commonsPlugin = new webpack.optimize.CommonsChunkPlugin('common.js'); module.exports = { entry: { index: './src/script/index.jsx', admin: './src/script/admin.jsx' }, output: { path: './build', filename: '[name].js' // template based on keys in entry above (index.js & admin.js) }, plugins: [commonsPlugin] };
を使用できます。これは、複数のエントリチャンクで発生するモジュールを検索し、複数のページ間でキャッシュできる共有バンドルを作成します。
require.ensure
System.import
ここで、バンドルされたスクリプトの前に追加することを忘れてはなりません。
Webpackは静的アセットを小さなチャンクに分割でき、このアプローチは標準の連結よりも柔軟性があります。大きなシングルページアプリケーション(SPA)がある場合、1つの大きなバンドルの読み込みに時間がかかる可能性があり、ユーザーは通常、各ビューのすべての依存関係を必要としないため、1つのバンドルに単純に連結することは適切なアプローチではありません。
ロボットのコーディング方法
アプリケーションを複数のバンドルに分割し、共通の依存関係を連結し、ブラウザーのキャッシュ動作から利益を得る方法については、前に説明しました。このアプローチは、マルチページアプリケーションでは非常にうまく機能しますが、シングルページアプリケーションでは機能しません。
SPAの場合、現在のビューをレンダリングするために必要な静的アセットのみを提供する必要があります。 SPAアーキテクチャのクライアント側ルーターは、コード分割を処理するのに最適な場所です。ユーザーがルートを入力すると、結果のビューに必要な依存関係のみをロードできます。または、ユーザーがページを下にスクロールするときに依存関係を読み込むこともできます。
この目的のために、admin.jsx
を使用できますまたはimport React, {Component} from 'react'; export default class Admin extends Component { render() { return Admin ; } }
Webpackが静的に検出できる関数。 Webpackは、この分割ポイントに基づいて個別のバンドルを生成し、オンデマンドで呼び出すことができます。
この例では、2つのReactコンテナーがあります。管理ビューとダッシュボードビュー。
dashboard.jsx
import React, {Component} from 'react'; export default class Dashboard extends Component { render() { return Dashboard ; } }
/dashboard
/admin
ユーザーがindex.jsx
のいずれかを入力した場合またはif (window.location.pathname === '/dashboard') { require.ensure([], function() { require('./containers/dashboard').default; }); } else if (window.location.pathname === '/admin') { require.ensure([], function() { require('./containers/admin').default; }); }
URL、対応する必要なJavaScriptバンドルのみがロードされます。以下に、クライアント側ルーターがある場合とない場合の例を示します。
index.jsx
ReactDOM.render( {props.children} }> { require.ensure([], function (require) { cb(null, require('./containers/dashboard').default) }, 'dashboard')}} /> { require.ensure([], function (require) { cb(null, require('./containers/admin').default) }, 'admin')}} /> , document.getElementById('content') );
style-loader
css-loader
Webpackでは、 ローダー 、ExtractTextWebpackPlugin
のようにおよびwebpack.config.js
、スタイルシートを前処理して出力JavaScriptバンドルに埋め込みますが、場合によっては、 スタイルのないコンテンツのフラッシュ (FOUC) 。
var ExtractTextPlugin = require('extract-text-webpack-plugin'); module.exports = { module: { loaders: [{ test: /.css/, loader: ExtractTextPlugin.extract('style', 'css’)' }], }, plugins: [ // output extracted CSS to a file new ExtractTextPlugin('[name].[chunkhash].css') ] }
でFOUCを回避できますこれにより、すべてのスタイルを最終的なJavaScriptバンドルに埋め込むのではなく、個別のCSSバンドルに生成できます。
$
jQuery
同じコンポーネントを最初から開発することに時間を費やしたくないため、多くの場合、サードパーティのライブラリ、さまざまなプラグイン、または追加のスクリプトを使用する必要があります。アクティブに維持されておらず、JavaScriptモジュールを理解しておらず、事前定義された名前でグローバルに依存関係が存在することを前提としている、利用可能なレガシーライブラリやプラグインが多数あります。
以下は、jQueryプラグインの例と、最終的なバンドルを生成できるようにWebpackを適切に構成する方法の説明です。
ほとんどのサードパーティプラグインは、特定のグローバル依存関係の存在に依存しています。 jQueryの場合、プラグインは$(‘div.content’).pluginFunc()
に依存しますまたはProvidePlugin
変数が定義されており、var $ = require('jquery')
を呼び出すことでjQueryプラグインを使用できます私たちのコードで。
Webpackプラグインを使用できます$
付加するwebpack.config.js
グローバルに遭遇するたびにwebpack.ProvidePlugin({ ‘$’: ‘jquery’, })
識別子。
$
require
Webpackがコードを処理するとき、プレゼンス$
を探し、this
で指定されたモジュールをインポートせずにグローバル依存関係への参照を提供します。関数。
一部のjQueryプラグインはwindow
を想定していますグローバル名前空間で、またはimports-loader
に依存しますexample.js
であることオブジェクト。この目的のために、$(‘div.content’).pluginFunc();
を使用できますこれは、グローバル変数をモジュールに挿入します。
モバイルアプリの設計のベストプラクティス
$
imports-loader
次に、require('imports?$=jquery!./example.js');
を注入できます。 var $ = require('jquery');
を構成して、モジュールに変数を追加します。
example.js
これは単にwebpack.config.js
の前に付けますmodule: { loaders: [{ test: /jquery-plugin/, loader: 'imports?jQuery=jquery,$=jquery,this=>window' }] }
へ。
2番目のユースケース:
=>
this
window
を使用する記号(と混同しないでください ES6矢印関数 )、任意の変数を設定できます。最後の値はグローバル変数を再定義します(function () { ... }).call(window);
this
を指すオブジェクト。これは、ファイルのコンテンツ全体をwindow
でラップするのと同じです。と呼び出し// CommonJS var $ = require('jquery'); // jquery is available // AMD define([‘jquery’], function($) { // jquery is available });
jquery-plugin.js
で機能する引数として。
CommonJSまたはAMDモジュール形式を使用してライブラリを要求することもできます。
(function(factory) { if (typeof define === 'function' && define.amd) { // AMD format is used define(['jquery'], factory); } else if (typeof exports === 'object') { // CommonJS format is used module.exports = factory(require('jquery')); } else { // Neither AMD nor CommonJS used. Use global variables. } });
一部のライブラリとモジュールは、さまざまなモジュール形式をサポートできます。
次の例では、AMDおよびCommonJSモジュール形式を使用し、jQuery依存関係を持つjQueryプラグインがあります。
s corp c corpllcの違い
webpack.config.js
module: { loaders: [{ test: /jquery-plugin/, loader: 'imports?define=>false,exports=>false' }] }
define
false
特定のライブラリに使用するモジュール形式を選択できます。 exports
を宣言するとfalse
と等しくなると、WebpackはモジュールをAMDモジュール形式で解析せず、変数expose-loader
を宣言するとwebpack.config.js
と等しい場合、WebpackはCommonJSモジュール形式のモジュールを解析しません。
モジュールをグローバルコンテキストに公開する必要がある場合は、module: { loaders: [ test: require.resolve('jquery'), loader: 'expose-loader?jQuery!expose-loader?$' ] }
を使用できます。これは、たとえば、Webpack構成の一部ではなく、グローバル名前空間のシンボルに依存する外部スクリプトがある場合や、ブラウザのコンソールでシンボルにアクセスする必要があるブラウザプラグインを使用している場合に役立ちます。
window.$ window.jQuery
externals
jQueryライブラリは、Webページ上の他のスクリプトのグローバル名前空間で使用できるようになりました。
webpack.config.js
外部でホストされているスクリプトのモジュールを含める場合は、構成でそれらを定義する必要があります。そうしないと、Webpackは最終バンドルを生成できません。
externals: { react: 'React', 'react-dom': 'ReactDOM' }
を使用して外部スクリプトを構成できますWebpack構成のオプション。たとえば、CDNのライブラリをseparatetagを介して使用しながら、プロジェクトでモジュールの依存関係として明示的に宣言することができます。
project | |-- node_modules | |-- react |-- react-plugin | |--node_modules | |--react
react-plugin
サードパーティのライブラリと依存関係を管理するために、フロントエンド開発でNPMパッケージマネージャーを使用するのは素晴らしいことです。ただし、同じライブラリの複数のインスタンスが異なるバージョンで存在する可能性があり、それらが1つの環境でうまく連携しない場合があります。
これは、たとえば、Reactライブラリで発生する可能性があります。Reactライブラリでは、NPMからReactをインストールでき、後で、追加のパッケージまたはプラグインを使用して別のバージョンのReactを利用できるようになります。プロジェクト構造は次のようになります。
webpack.config.js
module.exports = { resolve: { alias: { 'react': path.join(__dirname, './node_modules/react'), 'react/addons': path.join(__dirname, '/node_modules/react/addons'), } } }
からのコンポーネントプロジェクト内の他のコンポーネントとは異なるReactインスタンスがあります。これで、Reactの2つの別々のコピーができましたが、それらは異なるバージョンにすることができます。このアプリケーションでは、このシナリオによってグローバルな可変DOMが混乱する可能性があり、Webコンソールログにエラーメッセージが表示されます。この問題の解決策は、プロジェクト全体で同じバージョンのReactを使用することです。 Webpackエイリアスで解決できます。
react-plugin
node_modules
console.log(React.version)
の場合Reactを要求しようとすると、プロジェクトの
|_+_|のバージョンが使用されます。使用しているReactのバージョンを知りたい場合は、
|_+_|を追加できます。ソースコードで。
この投稿は、Webpackのパワーとユーティリティのほんの一部にすぎません。
他にもたくさんのWebpackがあります ローダー そして プラグイン これは、JavaScriptのバンドルを最適化および合理化するのに役立ちます。
初心者の場合でも、このガイドはWebpackの使用を開始するための確固たる基盤を提供します。これにより、バンドル構成ではなく開発に集中できるようになります。
関連: 制御の維持:WebpackとReactのガイド、Pt。 1