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

首頁 > 編程 > JavaScript > 正文

淺談webpack編譯vue項目生成的代碼探索

2019-11-19 14:45:29
字體:
來源:轉載
供稿:網友

本文介紹了webpack編譯vue項目生成的代碼探索,分享給大家,具體如下:

前言

往 main.js 里寫入最簡單的 vue 項目結構如下

import Vue from 'vue'; import App from './App.vue';new Vue({   el: '#app',  template: '<App/>',  components: {    App  }})

App.vue 如下

<template>   <div id="app">    <h1>{{ msg }}</h1>    <h2>Essential Links</h2>    <ul>      <li>        <a  rel="external nofollow" target="_blank">Core Docs</a>      </li>      <li>        <a  rel="external nofollow" target="_blank">Forum</a>      </li>      <li>        <a  rel="external nofollow" target="_blank">Community Chat</a>      </li>      <li>        <a  rel="external nofollow" target="_blank">Twitter</a>      </li>    </ul>    <h2>Ecosystem</h2>    <ul>      <li>        <a  rel="external nofollow" target="_blank">vue-router</a>      </li>      <li>        <a  rel="external nofollow" target="_blank">vuex</a>      </li>      <li>        <a  rel="external nofollow" target="_blank">vue-loader</a>      </li>      <li>        <a  rel="external nofollow" target="_blank">awesome-vue</a>      </li>    </ul>  </div></template><script> export default {   name: 'app',  data() {    return {      msg: 'Welcome to Your Vue.js App'    }  }}</script><style> #app {  font-family: 'Avenir', Helvetica, Arial, sans-serif;  -webkit-font-smoothing: antialiased;  -moz-osx-font-smoothing: grayscale;  text-align: center;  color: #2c3e50;  margin-top: 60px;}h1, h2 {   font-weight: normal;}ul {   list-style-type: none;  padding: 0;}li {   display: inline-block;  margin: 0 10px;}a {   color: #42b983;}</style> 

編譯生成后得到一個316kb的文件,而在316Kb中包含著什么,我很好奇想探索一番。

npm run build> learning-in-vue@1.0.0 build /Users/everlose/workspace/github/learningInVue> cross-env NODE_ENV=production webpack --progress --hide-modulesHash: 18d868a423b48dc263e9 Version: webpack 3.9.1 Time: 3693ms     Asset  Size Chunks          Chunk Names  build.js 316 kB    0 [emitted] [big] mainbuild.js.map 399 kB    0 [emitted]     main 

代碼分解

按順序往下解讀,本篇編譯后的代碼在這兒,如果只想看結論那么請拉到最后有一張結構梳理圖。

webpack 模塊機制

前面70行還是熟悉的 webpack 模塊機制的基礎代碼,關于它的細致解讀參見上一篇webpack模塊機制,編譯后的代碼格式如下,并且我做了代碼美化,并且插上了中文注釋

/******/ (function(modules) { // webpackBootstrap/******/   // The module cache/******/   // 緩存模塊,所有被加載過的模塊都會成為installedModules對象的屬性,靠函數__webpack_require__做到。/******/   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)/******/     // 創造一個新模塊并放入緩存中,i是模塊標識,l意為是否加載此模塊完畢,exports是此模塊執行后的輸出對象/******/     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 標為true代表模塊執行完成。/******/     module.l = true;/******//******/     // Return the exports of the module 返回此模塊輸出的對象/******/     return module.exports;/******/   }/******//******//******/   // expose the modules object (__webpack_modules__)/******/   // 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) {/******/     // 如果 exports 輸出的對象本身不包含 name 屬性時,定義一個。/******/     if(!__webpack_require__.o(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/******/   // 工具方法,判斷是否object有property屬性。/******/   __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };/******//******/   // __webpack_public_path__/******/   // 大概和 webpack.config.js 的 output 有關吧,webpack 的公共路徑/******/   __webpack_require__.p = "/dist/";/******//******/   // Load entry module and return exports 執行第一個依賴模塊并且返回它輸出。/******/   return __webpack_require__(__webpack_require__.s = 0);/******/ })

0號模塊

導出一個全局變量,在web端就是指代window

/* 0 */(function (module, exports) {  var g;  // This works in non-strict mode  g = (function () {    return this;  })();  try {    // This works if eval is allowed (see CSP)    g = g || Function("return this")() || (1, eval)("this");  } catch (e) {    // This works if the window reference is available    if (typeof window === "object")      g = window;  }  // g can still be undefined, but nothing to do about it...  // We return undefined, instead of nothing here, so it's  // easier to handle this case. if(!global) { ...}  module.exports = g;  /***/}),

1號模塊

實際上做的事情很明顯,就是導出了 main.js 的代碼,一個vue實例對象

/* 1 *//***/ (function(module, __webpack_exports__, __webpack_require__) {"use strict";Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_vue__ = __webpack_require__(2);/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__App_vue__ = __webpack_require__(6);// 從2號模塊導出的一個叫a的變量,就是Vue對象本身new __WEBPACK_IMPORTED_MODULE_0_vue__["a" /* default */]({   el: '#app',  template: '<App/>',  components: {    App: __WEBPACK_IMPORTED_MODULE_1__App_vue__["a" /* default */]  }});/***/ })

2號模塊

即是 Vue 源碼本身,從114行一直到了10818行,一共是10705行代碼,嘖嘖嘖

webpack 有所配置,所以導出的 Vue 實際上是 vue/dist/vue.esm.js 的完整編譯版本。

/* 2 *//***/ (function (module, __webpack_exports__, __webpack_require__) {"use strict";/*! * Vue.js v2.5.9 * (c) 2014-2017 Evan You * Released under the MIT License. */// 作用域指向__webpack_exports__,并把__webpack_require__(0)作為global,實際上就是window// __webpack_require__(3).setImmediate)作為setsetImmediate參數傳入函數(function (global, setImmediate) {  // 省略近1w行的代碼,關于vue原本本身的解讀以后再做......  // 最終 export 出來一個叫 Vue$3的對象  /* harmony default export */  __webpack_exports__["a"] = (Vue$3);  /* WEBPACK VAR INJECTION */}.call(__webpack_exports__, __webpack_require__(0), __webpack_require__(3).setImmediate))}),

3,4,5號模塊

都和 node_modules/setimmediate 有關,由于 vue 的 DOM 異步更新機制使用到了它,所以被引入。

這里也不做詳解,只給出結構。

/* 3 *//***/(function (module, exports, __webpack_require__) {  // 省略代碼...  // setimmediate attaches itself to the global object  __webpack_require__(4);  exports.setImmediate = setImmediate;  exports.clearImmediate = clearImmediate;  /***/}),/* 4 *//***/(function (module, exports, __webpack_require__) {  /* WEBPACK VAR INJECTION */  (function (global, process) {    // 省略代碼...  }.call(exports, __webpack_require__(0), __webpack_require__(5)))  /***/}),/* 5 *//***/(function (module, exports) {  // shim for using process in browser  var process = module.exports = {};  // 省略代碼...  process.cwd = function () {    return '/'  };  process.chdir = function (dir) {    throw new Error('process.chdir is not supported');  };  process.umask = function () {    return 0;  };  /***/}),

6號模塊

和 App.vue 的解析有關,把 App.vue 中的 template 和 script 編譯為一個 vue components,并把 style 標簽內的樣式插入到DOM中。

/* 6 *//***/(function (module, __webpack_exports__, __webpack_require__) {  "use strict";  // 返回具體 App.vue 中 的script 中的代碼  var __WEBPACK_IMPORTED_MODULE_0__babel_loader_node_modules_vue_loader_lib_selector_type_script_index_0_App_vue__ = __webpack_require__(13);  // 把App.vue 的 template 解析為一堆 vue render 函數。  var __WEBPACK_IMPORTED_MODULE_1__node_modules_vue_loader_lib_template_compiler_index_id_data_v_66ce2159_hasScoped_false_buble_transforms_node_modules_vue_loader_lib_selector_type_template_index_0_App_vue__ = __webpack_require__(14);  // 注入vue文件里寫入的css函數  function injectStyle(ssrContext) {    // 由此可知7號模塊是編譯并插入vue中的css到DOM上的    __webpack_require__(7)  }  // 12號模塊用于輸出components渲染函數  var normalizeComponent = __webpack_require__(12)  /* script */  /* template */  /* template functional */  var __vue_template_functional__ = false  /* styles */  var __vue_styles__ = injectStyle  /* scopeId */  var __vue_scopeId__ = null  /* moduleIdentifier (server only) */  var __vue_module_identifier__ = null  // 編譯模塊,混雜template和script。  var Component = normalizeComponent(    __WEBPACK_IMPORTED_MODULE_0__babel_loader_node_modules_vue_loader_lib_selector_type_script_index_0_App_vue__["a" /* default */ ],    __WEBPACK_IMPORTED_MODULE_1__node_modules_vue_loader_lib_template_compiler_index_id_data_v_66ce2159_hasScoped_false_buble_transforms_node_modules_vue_loader_lib_selector_type_template_index_0_App_vue__["a" /* default */ ],    __vue_template_functional__,    __vue_styles__,    __vue_scopeId__,    __vue_module_identifier__  )  /* harmony default export */  __webpack_exports__["a"] = (Component.exports);  /***/}),

7、8、9、10、11

都和樣式有關,簡言之就是7號模塊加載8號模塊獲取css代碼作為參數,并作為參數傳入10號模塊進行插入

太長也只大意上列出結構

  1. 7號模塊由 style-loader 帶入,把所有的css插入到 style 標簽里
  2. 8號模塊加載具體的css代碼,
  3. 9號模塊由css-loader代入,用于做css的sourceMap
  4. 10號模塊返回具體插入動作函數,供7號模塊調用
  5. 11號模塊把所有的樣式組成的數組轉為字符串,給10號模塊做插入。
/* 7 *//***/(function (module, exports, __webpack_require__) {  // style-loader: Adds some css to the DOM by adding a <style> tag  // load the styles  var content = __webpack_require__(8);  if (typeof content === 'string') content = [    [module.i, content, '']  ];  if (content.locals) module.exports = content.locals;  // add the styles to the DOM  var update = __webpack_require__(10)("15459d21", content, true);  /***/}),/* 8 *//***/(function (module, exports, __webpack_require__) {  // css-loader 用于做css的sourceMap  exports = module.exports = __webpack_require__(9)(undefined);  // imports  // module  // 這就是 App.vue 文件中 style 里的的 css  exports.push([module.i, "#app{font-family:Avenir,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-align:center;color:#2c3e50;margin-top:60px}h1,h2{font-weight:400}ul{list-style-type:none;padding:0}li{display:inline-block;margin:0 10px}a{color:#42b983}", ""]);  // exports  /***/}),/* 9 *//***/(function (module, exports) {  // css base code, injected by the css-loader  module.exports = function (useSourceMap) {    // 省略代碼...  }}),/* 10 *//***/(function (module, exports, __webpack_require__) {  /*    MIT License http://www.opensource.org/licenses/mit-license.php    Author Tobias Koppers @sokra    Modified by Evan You @yyx990803  */  // ...太長只貼了關鍵步驟,總之關鍵的函數就是這些  var hasDocument = typeof document !== 'undefined'  // ...  var listToStyles = __webpack_require__(11)  // ...  var head = hasDocument && (document.head || document.getElementsByTagName('head')[0])  // ...  module.exports = function (parentId, list, _isProduction) {    // ...    var styles = listToStyles(parentId, list)    addStylesToDom(styles)    return function update (newList) {      // ...    }  }  function addStylesToDom (styles /* Array<StyleObject> */) {    for (var i = 0; i < styles.length; i++) {      // ...      domStyle.parts.push(addStyle(item.parts[j]))      // ....    }  }  // 總之先調用了addStylesToDom,接著是addStyle,再是createStyleElement插入樣式到head中。  function createStyleElement () {  var styleElement = document.createElement('style')  styleElement.type = 'text/css'  head.appendChild(styleElement)  return styleElement  }  function addStyle (obj /* StyleObjectPart */) {    // ...    styleElement = createStyleElement()    // ...  }  /***/}),/* 11 *//***/(function (module, exports) {  /**   * Translates the list format produced by css-loader into something   * easier to manipulate.   */  module.exports = function listToStyles(parentId, list) {    var styles = []    var newStyles = {}    for (var i = 0; i < list.length; i++) {      var item = list[i]      var id = item[0]      var css = item[1]      var media = item[2]      var sourceMap = item[3]      var part = {        id: parentId + ':' + i,        css: css,        media: media,        sourceMap: sourceMap      }      if (!newStyles[id]) {        styles.push(newStyles[id] = {          id: id,          parts: [part]        })      } else {        newStyles[id].parts.push(part)      }    }    return styles  }  /***/}),

12、13、14號模塊

12號做 .vue 文件中的 template 和 script 解析并供6號輸出,最終返回了一個 vue components 對象,在瀏覽器控制臺打印如下:

Object   beforeCreate: [ƒ]  data: ƒ data()  inject: {}  name: "app"  render: ƒ ()  staticRenderFns: (2) [ƒ, ƒ, cached: Array(2)]  _Ctor: {0: ƒ}  _compiled: true  __proto__: Object

而13號模塊返回具體 script 中的代碼,而14號模塊則是把 template 解析為一堆 vue render 函數。

/* 12 *//***/(function (module, exports) {  /* globals __VUE_SSR_CONTEXT__ */  // IMPORTANT: Do NOT use ES2015 features in this file.  // This module is a runtime utility for cleaner component module output and will  // be included in the final webpack user bundle.  module.exports = function normalizeComponent(    rawScriptExports,    compiledTemplate,    functionalTemplate,    injectStyles,    scopeId,    moduleIdentifier /* server only */  ) {    var esModule    var scriptExports = rawScriptExports = rawScriptExports || {}    // ES6 modules interop    var type = typeof rawScriptExports.default    if (type === 'object' || type === 'function') {      esModule = rawScriptExports      scriptExports = rawScriptExports.default    }    // Vue.extend constructor export interop    var options = typeof scriptExports === 'function' ?      scriptExports.options :      scriptExports    // render functions    if (compiledTemplate) {      options.render = compiledTemplate.render      options.staticRenderFns = compiledTemplate.staticRenderFns      options._compiled = true    }    // functional template    if (functionalTemplate) {      options.functional = true    }    // scopedId    if (scopeId) {      options._scopeId = scopeId    }    var hook    if (moduleIdentifier) { // server build      hook = function (context) {        // 2.3 injection        context =          context || // cached call          (this.$vnode && this.$vnode.ssrContext) || // stateful          (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext) // functional        // 2.2 with runInNewContext: true        if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {          context = __VUE_SSR_CONTEXT__        }        // inject component styles        if (injectStyles) {          injectStyles.call(this, context)        }        // register component module identifier for async chunk inferrence        if (context && context._registeredComponents) {          context._registeredComponents.add(moduleIdentifier)        }      }      // used by ssr in case component is cached and beforeCreate      // never gets called      options._ssrRegister = hook    } else if (injectStyles) {      hook = injectStyles    }    if (hook) {      var functional = options.functional      var existing = functional ?        options.render :        options.beforeCreate      if (!functional) {        // inject component registration as beforeCreate hook        options.beforeCreate = existing ?          [].concat(existing, hook) :          [hook]      } else {        // for template-only hot-reload because in that case the render fn doesn't        // go through the normalizer        options._injectStyles = hook        // register for functioal component in vue file        options.render = function renderWithStyleInjection(h, context) {          hook.call(context)          return existing(h, context)        }      }    }    return {      esModule: esModule,      exports: scriptExports,      options: options    }  }  /***/}),/* 13 *//***/(function (module, __webpack_exports__, __webpack_require__) {  "use strict";  /* harmony default export */  // 這就是 App.vue 中 script 的部分  __webpack_exports__["a"] = ({    name: 'app',    data: function data() {      return {        msg: 'Welcome to Your Vue.js App'      };    }  });  /***/}),/* 14 *//***/(function (module, __webpack_exports__, __webpack_require__) {  "use strict";  // 把template 解析為一堆 render 函數,扔給vue處理最終編譯成Vnode節點在渲染成DOM輸出到視圖  var render = function () {    var _vm = this;    var _h = _vm.$createElement;    var _c = _vm._self._c || _h;    return _c('div', {      attrs: {        "id": "app"      }    }, [_c('h1', [_vm._v(_vm._s(_vm.msg))]), _vm._v(" "), _c('h2', [_vm._v("Essential Links")]), _vm._v(" "), _vm._m(0, false, false), _vm._v(" "), _c('h2', [_vm._v("Ecosystem")]), _vm._v(" "), _vm._m(1, false, false)])  }  var staticRenderFns = [function () {    var _vm = this;    var _h = _vm.$createElement;    var _c = _vm._self._c || _h;    return _c('ul', [_c('li', [_c('a', {      attrs: {        "href": "https://vuejs.org",        "target": "_blank"      }    }, [_vm._v("Core Docs")])]), _vm._v(" "), _c('li', [_c('a', {      attrs: {        "href": "https://forum.vuejs.org",        "target": "_blank"      }    }, [_vm._v("Forum")])]), _vm._v(" "), _c('li', [_c('a', {      attrs: {        "href": "https://chat.vuejs.org",        "target": "_blank"      }    }, [_vm._v("Community Chat")])]), _vm._v(" "), _c('li', [_c('a', {      attrs: {        "href": "https://twitter.com/vuejs",        "target": "_blank"      }    }, [_vm._v("Twitter")])])])  }, function () {    var _vm = this;    var _h = _vm.$createElement;    var _c = _vm._self._c || _h;    return _c('ul', [_c('li', [_c('a', {      attrs: {        "href": "http://router.vuejs.org/",        "target": "_blank"      }    }, [_vm._v("vue-router")])]), _vm._v(" "), _c('li', [_c('a', {      attrs: {        "href": "http://vuex.vuejs.org/",        "target": "_blank"      }    }, [_vm._v("vuex")])]), _vm._v(" "), _c('li', [_c('a', {      attrs: {        "href": "http://vue-loader.vuejs.org/",        "target": "_blank"      }    }, [_vm._v("vue-loader")])]), _vm._v(" "), _c('li', [_c('a', {      attrs: {        "href": "https://github.com/vuejs/awesome-vue",        "target": "_blank"      }    }, [_vm._v("awesome-vue")])])])  }]  var esExports = {    render: render,    staticRenderFns: staticRenderFns  }  /* harmony default export */  __webpack_exports__["a"] = (esExports);  /***/})

總結

結構梳理,一圖勝千言

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 阿拉善右旗| 宁城县| 开封市| 安丘市| 桐庐县| 化德县| 江门市| 泰安市| 文成县| 阜康市| 曲阳县| 左贡县| 容城县| 德格县| 汉寿县| 闽清县| 沾化县| 娄烦县| 巨鹿县| 祁连县| 监利县| 延吉市| 河西区| 观塘区| 民县| 通州区| 开江县| 英超| 平乐县| 平远县| 耿马| 健康| 敦煌市| 台东市| 武宣县| 鸡泽县| 贺兰县| 浦县| 松潘县| 军事| 宁化县|