ホームページ  >  記事  >  ウェブフロントエンド  >  webpackモジュールとwebpack3の新機能の詳細説明

webpackモジュールとwebpack3の新機能の詳細説明

小云云
小云云オリジナル
2018-02-09 13:30:291439ブラウズ

この記事は簡単な例から始まり、パッケージング ファイルから次の 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 モジュール さまざまな方法で依存関係を表現できます。いくつかの例を以下に示します。

    ES2015 import ステートメント
  • CommonJS require() ステートメント
  • AMD ファイル内のステートメントと require ステートメント
  • css/sass/less @import ステートメント。
  • HTML ファイル () 内のスタイル (url(...)) または画像リンク (画像 URL)
  • 強力な 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の未使用コードは削除されます(実際にはツリーシェイクです)

AMD

Webpackをもう一度見てみましょう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 サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。