国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

探索webpack模塊及webpack3新特性

2019-11-19 15:24:25
字體:
來源:轉載
供稿:網友

本文從簡單的例子入手,從打包文件去分析以下三個問題:webpack打包文件是怎樣的?如何做到兼容各大模塊化方案的?webpack3帶來的新特性又是什么?

一個簡單的例子

webpack配置

 // webpack.config.jsmodule.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') },};

簡單的js文件

 // src/index.js console.log('hello world');

webpack打包后的代碼

一看你就會想,我就一行代碼,你給我打包那么多???(黑人問號)

// 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) {  //.. }])

好了,傳入模塊數組做了什么(其實注釋都很明顯了,我只是大概翻譯一下)

 /******/ (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');/***/ })/******/ ]);

整體流程是怎樣的呢

  • 傳入module數組
  • 調用__webpack_require__(__webpack_require__.s = 0)

構造module對象,放入緩存

調用module,傳入相應參數modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); (這里exports會被函數內部的東西修改)

標記module對象已經加載完畢

返回模塊暴露的內容(注意到上面函數傳入了module.exports,可以對引用進行修改)

  • 模塊函數中傳入module, module.exports, __webpack_require__
  • 執行過程中通過對上面三者的引用修改,完成變量暴露和引用

webpack模塊機制是怎樣的

我們可以去官網看下webpack模塊

doc.webpack-china.org/concepts/mo…

webpack 模塊能夠以各種方式表達它們的依賴關系,幾個例子如下:

  • ES2015 import 語句
  • CommonJS require() 語句
  • AMD define 和 require 語句
  • css/sass/less 文件中的 @import 語句。
  • 樣式(url(...))或 HTML 文件()中的圖片鏈接(image url)

強大的webpack模塊可以兼容各種模塊化方案,并且無侵入性(non-opinionated)

我們可以再編寫例子一探究竟

CommonJS

修改src/index.js

var cj = require('./cj.js');console.log('hello world');cj();

新增src/cj.js,保持前面例子其他不變

// src/cj.jsfunction 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__在上一節有介紹),整體上就是依賴的模塊修改了module.exports,然后主模塊執行依賴模塊,獲取exports即可

ES2015 import

新增src/es.js

// src/es.jsexport default function b() { console.log('ES Modules');}

修改src/index.js

// src/index.jsimport 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');}/***/ })/******/ ]);

我們可以看到它們都變成了嚴格模式,webpack自動采用的

表現其實跟CommonJS相似,也是傳入export然后修改,在主模塊再require進來,

我們可以看到這個

Object.defineProperty(__webpack_exports__, "__esModule", { value: true });

這個干嘛用的?其實就是標記當前的exports是es模塊,還記得之前的__webpack_require__.n嗎,我們再拿出來看看

/******/  // 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;/******/  };

為了避免跟非ES Modules沖突?沖突在哪里呢?

其實這部分如果你看到babel轉換ES Modules源碼就知道了,為了兼容模塊,會把ES Modules直接掛在exports.default上,然后加上__esModule屬性,引入的時候判斷一次是否是轉換模塊,是則引入module['default'],不是則引入module

我們再多引入幾個ES Modules看看效果

// src/es.jsexport 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');}

我們多引入esTwo和esFour,但是不使用esFour

// src/index.jsimport { 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');}/***/ })/******/ ]);

嗯嗯其實跟前面是一樣的,舉出這個例子重點在哪里呢,有沒有注意到注釋中

/* unused harmony export esThree *//* unused harmony export esFour */

esThree是我們沒有引入的模塊,esFour是我們引用但是沒有使用的模塊,webpack均對它們做了unused的標記,其實這個如果你使用了webpack插件uglify,通過標記,就會把esThree和esFour這兩個未使用的代碼消除(其實它就是tree-shaking)

AMD

我們再來看看webpack怎么支持AMD

新增src/amd.js

// src/amd.jsdefine([],function(){ return {  amd:function(){   console.log('AMD');  } };});

修改index.js

// src/index.jsdefine([ './amd.js'],function(amdModule){ amdModule.amd();});

得到

/******/ (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__));/***/ })/******/ ]);

先看amd.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__) );})

簡單來講收集define Array然后置入返回函數,根據參數獲取依賴

apply對數組拆解成一個一個參數

再看index.js模塊部分

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__) );}

其實就是引入了amd.js暴露的{amd:[Function: amd]}

css/image?

css和image也可以成為webpack的模塊,這是令人震驚的,這就不能通過普通的hack commonjs或者函數調用簡單去調用了,這就是anything to JS,它就需要借助webpack loader去實現了

像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.jsfunction 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.jsconsole.log('hello world');es();/***/ })/******/ ]);

我們可以驚喜的發現沒有什么require了,它們拼接成了一個函數,good!😃

Magic Comments

code splitting是webpack一個重點特性之一,涉及到要動態引入的時候,webpack可以使用 require.ensure去實現,后來webpack2支持使用了符合 ECMAScript 提案 的 import() 語法,但是它有個不足之處,無法指定chunk的名稱chunkName,為了解決這個問題,出現了Magic Comments,支持用注釋的方式去指定,如下

import(/* webpackChunkName: "my-chunk-name" */ 'module');

小結

webpack是一個強大的模塊打包工具,在處理依賴、模塊上都很優秀,本文從bundle.js文件分析出發去探索了不同模塊方案的加載機制,初步去理解webpack,并且對webpack3特性進行闡述,當然,webpack還有很多地方需要去探索深究,敬請期待以后的文章吧~關于本文如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對武林網網站的支持!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 洱源县| 和平区| 神木县| 即墨市| 囊谦县| 沈丘县| 安乡县| 亳州市| 广丰县| 诸城市| 揭阳市| 襄城县| 万宁市| 从化市| 长子县| 天柱县| 玉环县| 乐山市| 长丰县| 呼伦贝尔市| 吴桥县| 宁津县| 大英县| 揭东县| 马山县| 嘉荫县| 双鸭山市| 从化市| 陆河县| 九寨沟县| 灵台县| 临海市| 弥渡县| 蒙阴县| 合川市| 巴马| 广州市| 怀远县| 满城县| 射阳县| 黑龙江省|