ホームページ > 記事 > ウェブフロントエンド > webpackモジュールとwebpack3の新機能の詳細説明
この記事は簡単な例から始まり、パッケージング ファイルから次の 3 つの質問を分析します: webpack パッケージング ファイルはどのようなものですか?主要なモジュラー ソリューションとの互換性を実現するにはどうすればよいですか? webpack3 によってもたらされる新機能は何ですか? Webpack は、依存関係とモジュールの処理に優れた強力なモジュール パッケージ化ツールです。この記事では、bundle.js ファイルの分析から開始して、さまざまなモジュール ソリューションの読み込みメカニズムを調査し、最初に webpack を理解し、webpack3 の機能について詳しく説明します。 。
簡単な例
webpack構成
// webpack.config.js module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, };
簡単なjsファイル
// src/index.js console.log('hello world');
webpackパッケージ化後のコード
これを見ると、コードは1行しかないのに、こんなにたくさんパッケージ化してくれるの? ? ? (黒い疑問符)
// dist/bundle.js /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports) { console.log('hello world'); /***/ }) /******/ ]);
まずコードのこの部分を分析して単純化してみましょう。実際、全体は自己実行関数であり、次にモジュール配列を渡します
(function(modules) { //... })([function(module, exports) { //.. }])
それでは、渡されたモジュールは何をするのかを説明します。 array do (実際、コメントはすべて一目瞭然です。大まかに翻訳しただけです)
/******/ (function(modules) { // webpackBootstrap /******/ // The module cache 缓存已经load过的模块 /******/ var installedModules = {}; /******/ /******/ // The require function 引用的函数 /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache 假如在缓存里就直接返回 /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) 构造一个模块并放入缓存 /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, //模块id /******/ l: false, // 是否已经加载完毕 /******/ exports: {} // 对外暴露的内容 /******/ }; /******/ /******/ // Execute the module function 传入模块参数,并执行模块 /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded 标记模块已经加载完毕 /******/ module.l = true; /******/ /******/ // Return the exports of the module 返回模块暴露的内容 /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) 暴露模块数组 /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache 暴露缓存数组 /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports 为ES6 exports定义getter /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { // 假如exports本身不含有name这个属性 /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules 解决ES module和Common js module的冲突,ES则返回module['default'] /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ webpack配置下的公共路径 /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports 最后执行entry模块并且返回它的暴露内容 /******/ return __webpack_require__(__webpack_require__.s = 0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports) { console.log('hello world'); /***/ }) /******/ ]);
全体的なプロセスは何ですか?
モジュール配列を渡します
Call __webpack_require__(__webpack_require__.s = 0)
モジュールオブジェクトを構築してキャッシュに入れます
モジュールを呼び出し、対応するパラメータを渡します modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); (ここでのエクスポートは次のようになります)関数内のものによって変更されます)
モジュールオブジェクトをロード済みとしてマークします
モジュールによって公開されたコンテンツを返します (module.exports が上記の関数に渡され、参照が変更できることに注意してください)
Passモジュール関数の module、module.exports、__webpack_require__
実行プロセス中に、上記 3 つの参照を変更して変数公開と参照を完了します
webpack モジュールのメカニズムとは何ですか? webpack モジュールを確認するには、公式 Web サイト
doc.webpack-china.org/concepts/mo…
webpack モジュール さまざまな方法で依存関係を表現できます。いくつかの例を以下に示します。
調べるための別の例
CommonJS
src/index.js を変更します
var cj = require('./cj.js'); console.log('hello world'); cj();
src/cj.js を追加し、前の例を変更しないでください
// src/cj.js function a() { console.log("CommonJS"); } module.exports = a;
webpack を再度実行します
/******/ (function(modules) { // webpackBootstrap //... 省略代码 /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports, __webpack_require__) { let cj = __webpack_require__(1); console.log('hello world'); cj(); /***/ }), /* 1 */ /***/ (function(module, exports) { function a() { console.log("CommonJS"); } module.exports = a; /***/ }) /******/ ]);
追加のインポートがあることがわかりますファイルをモジュール配列に追加し、index.js モジュール関数にはそのファイルを参照するための追加パラメーター __webpack_require__ が含まれています (__webpack_require__ については前のセクションで説明しました)。次に、メイン モジュールが依存モジュールを実行します。モジュールを取得し、exports
ES2015 import
Add src/es.js
// src/es.js export default function b() { console.log('ES Modules'); }
Modify src/index.js
// src/index.js import es from './es.js'; console.log('hello world'); es(); webpack.config.js不变,执行webpack /******/ (function(modules) { // webpackBootstrap // ... 省略代码 /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__es_js__ = __webpack_require__(1); console.log('hello world'); Object(__WEBPACK_IMPORTED_MODULE_0__es_js__["a" /* default */])(); /***/ }), /* 1 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony export (immutable) */ __webpack_exports__["a"] = b; function b() { console.log('ES Modules'); } /***/ }) /******/ ]);
これらはすべて strict モードになっていることがわかり、自動的に webpack が採用されています
のパフォーマンスこれは実際には CommonJS のものと似ていますが、インポートしてエクスポートし、それをメイン モジュールで要求します
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
これは何に使用されますか?実際、これは現在のエクスポートを ES モジュールとしてマークするためのものです。以前の __webpack_require__.n を覚えていますか? 非 ES モジュールとの競合を避けるために、取り出して見てみましょう。どこに紛争があるのでしょうか?
実際、ESモジュールを変換するBabelのソースコードを見ると、この部分がわかると思いますが、モジュールとの互換性を保つために、ESモジュールはexports.defaultに直接ハングされ、__esModule属性が設定されます。導入時に変換モジュールかどうかを判断し、そうでない場合はmodule['default']を導入します
効果を確認するためにさらにいくつかのESモジュールを導入します/******/ // getDefaultExport function for compatibility with non-harmony modules 解决ES module和Common js module的冲突,ES则返回module['default'] /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ };さらに esTwo と esFour を紹介しますが、esFour は使用しません
// src/es.js export function es() { console.log('ES Modules'); } export function esTwo() { console.log('ES Modules Two'); } export function esThree() { console.log('ES Modules Three'); } export function esFour() { console.log('ES Modules Four'); }結果
// src/index.js import { es, esTwo, esFour} from './es.js'; console.log('hello world'); es(); esTwo();さて、実際には前と同じですが、この例のポイントは
/******/ (function(modules) { // webpackBootstrap // ... /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__es_js__ = __webpack_require__(1); console.log('hello world'); Object(__WEBPACK_IMPORTED_MODULE_0__es_js__["a" /* es */])(); Object(__WEBPACK_IMPORTED_MODULE_0__es_js__["b" /* esTwo */])(); /***/ }), /* 1 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony export (immutable) */ __webpack_exports__["a"] = es; /* harmony export (immutable) */ __webpack_exports__["b"] = esTwo; /* unused harmony export esThree */ /* unused harmony export esFour */ function es() { console.log('ES Modules'); } function esTwo() { console.log('ES Modules Two'); } function esThree() { console.log('ES Modules Three'); } function esFour() { console.log('ES Modules Four'); } /***/ }) /******/ ]);esThree であることに気づきましたか?導入しなかったモジュール、esFour は参照したが使用しなかったモジュール、webpack はそれらをすべて実行します。実際、webpack プラグインを使用すると、このマークを介して 2 つが削除されます。 esThreeとesFourの未使用コードは削除されます(実際にはツリーシェイクです)AMDWebpackをもう一度見てみましょうAMDをサポートする方法src/amd.jsを追加します
/* unused harmony export esThree */ /* unused harmony export esFour */index.jsを修正します
// src/amd.js define([ ],function(){ return { amd:function(){ console.log('AMD'); } }; });Get
// src/index.js define([ './amd.js' ],function(amdModule){ amdModule.amd(); });まずはamd.jsを見てコードを整理します
/******/ (function(modules) { // webpackBootstrap // ... 省略代码 /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [ __webpack_require__(1) ], __WEBPACK_AMD_DEFINE_RESULT__ = function(amdModule){ amdModule.amd(); }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); /***/ }), /* 1 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [ ], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return { amd:function(){ console.log('AMD'); } }; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); /***/ }) /******/ ]);簡単に言うと、配列の定義を集めてパラメータ取得の依存関係に従ってreturn関数を入れますapplyは配列を一つずつパラメータに分解します
index.js モジュール部分を見てください
function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__; !( __WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function() { return { amd: function() { console.log('AMD'); } }; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__) ); })実際には、amd.js によって公開される {amd:[Function: amd]}css/image? が導入されており、画像も webpack のモジュールになることができます。これは衝撃的です。これは通常のハック commonjs や関数呼び出しを通じて単純に呼び出すことはできず、webpack ローダーの助けを借りて実装する必要があります。
像css就是转换成一段js代码,通过处理,调用时就是可以用js将这段css插入到style中,image也类似,这部分就不详细阐述了,有兴趣的读者可以深入去研究
webpack3新特性
我们可以再顺便看下webpack3新特性的表现
具体可以看这里medium.com/webpack/web…
Scope Hoisting
我们可以发现模块数组是一个一个独立的函数然后闭包引用webpack主函数的相应内容,每个模块都是独立的,然后带来的结果是在浏览器中执行速度变慢,然后webpack3学习了Closure Compiler和RollupJS这两个工具,连接所有闭包到一个闭包里,放入一个函数,让执行速度更快,并且整体代码体积也会有所缩小
我们可以实际看一下效果(要注意的是这个特性只支持ES Modules,是不支持CommonJs和AMD的)
使用上面的例子,配置webpack.config.js,增加new webpack.optimize.ModuleConcatenationPlugin()
const path = require('path'); const webpack = require('webpack'); module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, module: { }, plugins: [ new webpack.optimize.ModuleConcatenationPlugin(), ] };
打包
/******/ (function(modules) { // webpackBootstrap // ... 省略代码 /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); // CONCATENATED MODULE: ./src/es.js function es() { console.log('ES Modules'); } function esTwo() { console.log('ES Modules Two'); } function esThree() { console.log('ES Modules Three'); } function esFour() { console.log('ES Modules Four'); } // CONCATENATED MODULE: ./src/index.js // src/index.js console.log('hello world'); es(); /***/ }) /******/ ]);
我们可以惊喜的发现没有什么require了,它们拼接成了一个函数,good!
以上がwebpackモジュールとwebpack3の新機能の詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。