weex 原始碼解析(二) -- vue 檔案轉為js(Android視角)

林s發表於2018-03-27

通過上一篇 weex 原始碼解析(一) -- 整體實現思路(Android視角) ,大家應該可以看到主要的實現方式了,接下來,就根據這個主框架,一步一步進行深入分析。

本篇主要是講解第一步,vue檔案的編寫,以及js檔案的生成。將vue編譯為js,如果要執行在android端,需要使用weex-loader.

首先,我們需要知道,vue為什麼要先轉換為bundle js 檔案(bundle的中文意思是捆綁,打包),用什麼工具轉的,以及bundle js檔案裡,又有哪些內容呢?接下來我們一步一步解析。

webpack

1.vue檔案為什麼要轉換為bundle js檔案。

由於weex是跨平臺的框架,所以要可以執行在瀏覽器上,而瀏覽器不能識別vue檔案,所以只能將vue轉為瀏覽器所能識別的js檔案。

2.vue是用什麼工具來轉為bundle js檔案的。

vue是使用webpack來進行轉換的

3.webpack的簡介

本質上,webpack 是一個現代 JavaScript 應用程式的靜態模組打包器(module bundler)。當 webpack 處理應用程式時,它會遞迴地構建一個依賴關係圖(dependency graph),其中包含應用程式需要的每個模組,然後將所有這些模組打包成一個或多個 bundle。

4.打包後的bundle js檔案裡有哪些內容呢?

為了能夠更加清晰的看到最簡單的版本,大家可以先看看這篇《深入剖析 webpack 打包生成的bundle js》,後面我再將這篇文章直接整合到本文中。

看完上面的基礎,接下來先貼幾份weex 建立好專案後的helloworld程式碼:

1.entry.js,這個是入口檔案。 在webpack的配置裡指定好。

import Vue from 'vue';

import weex from 'weex-vue-render';

// import render-core.
// import weex from 'weex-vue-render/dist/index.core';

// need to run `npm i weex-vue-slider weex-vue-stream --save` frist.
// import the plugins (components and modules) you want to use.
// import slider from 'weex-vue-slider';
// import stream from 'weex-vue-stream';

// install the plugins.
// weex.install(slider);
// weex.install(stream);

weex.init(Vue);

複製程式碼

2.我們初始化weex工程裡的helloworld頁面,預設的index.vue,入口檔案會引用該頁面。雖然在上面的entry.js裡沒有看到引用,但從entry.js生成的臨時檔案(.temp/index.js)裡是可以看到引用的。

.temp/index.js

import Vue from 'vue';

import weex from 'weex-vue-render';

// import render-core.
// import weex from 'weex-vue-render/dist/index.core';

// need to run `npm i weex-vue-slider weex-vue-stream --save` frist.
// import the plugins (components and modules) you want to use.
// import slider from 'weex-vue-slider';
// import stream from 'weex-vue-stream';

// install the plugins.
// weex.install(slider);
// weex.install(stream);

weex.init(Vue);

const App = require('../src/index.vue');
App.el = '#root';
new Vue(App);
複製程式碼

src/index.vue

<template>
  <div class="wrapper">
    <image :src="logo" class="logo"></image>
    <text class="greeting">The environment is ready!</text>
    <text class="message">Now, let's use Vue.js to build your Weex app.</text>
  </div>
</template>

<script>
  export default {
    data () {
      return {
        logo: 'https://gw.alicdn.com/tfs/TB1yopEdgoQMeJjy1XaXXcSsFXa-640-302.png',
      }
    }
  }
</script>

<style scoped>
  .wrapper {
    justify-content: center;
    align-items: center;
  }
  .logo {
    width: 424px;
    height: 200px;
  }
  .greeting {
    margin-top: 70px;
    font-size: 50px;
    color: #41B883;
  }
  .message {
    margin: 30px;
    font-size: 32px;
    color: #727272;
  }
</style>


複製程式碼

3.webpack打包後,生成的bundle js檔案,bundle的中文意思,就是捆綁,打包。以下程式碼經過格式化,再加上相關的註釋,以便大家可以看得更加清晰。

// { "framework": "Vue"}  //該註釋不可刪除,主要是告訴JS Framework 使用什麼編譯器來解析該js檔案。


//js普通函式function (args){、、、}
//js普通函式定義後,自己執行自己,叫做自執行函式,可以這麼寫,(function (args){、、、})(args)
// 程式碼精簡之後,如下:
// (function(modules) { 
//     //...
// })([function(module, exports) {
//     //..
// }])
//下面就只是一個[自執行函式](https://segmentfault.com/a/1190000003985390)
(function (modules) { // webpackBootstrap,這裡的modules就是上面的args,在這裡,是一個module資料,module代表模組,例如,一個js檔案,一個vue檔案,一個template,一個style等。。。
  
  // The module cache,module生成後,快取在之類,以便重複使用
  var installedModules = {};

  // 一個方法內,還可以定義一個內部的方法
  // The require function,通過一個moduleId,建立模組的方法,moduleId一般從0開始,在webpack打包的時候,就指定每個module的id了。
  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: {}  //對外暴露的內容。
    };

    //下面是一個j 的 call方法,使用call方法,是為了改變this的指向。
    // 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;

  // Object.defineProperty(obj, keyName, value);對某個obj的某個key,進行設定。
  // define getter function for harmony exports,這裡的getter是一個方法。
  __webpack_require__.d = function (exports, name, getter) {
    if (!__webpack_require__.o(exports, name)) {
      Object.defineProperty(exports, name, {
        configurable: false, //設定false後,該value的enumerable,get等不能再被修改。
        enumerable: true, //是否可以被列舉獲取到該key和value。
        get: getter //其他地方呼叫獲取該key的值的時候,會返回getter方法裡的return值。

      });

    }

  };

  // 獲取預設的export物件,如果是es6規範語法,則返回module.default,否則,就返回module。
  // 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配置下的公共路徑
  __webpack_require__.p = "";

  // Load entry module and return exports,這裡載入入口module,並返回export物件。
  return __webpack_require__(__webpack_require__.s = 0);

})
  /************************************下面是modules************************************//
  ([
/* 0 */ // 這個modules是入口模組,moduleId為0
/***/ (function (module, exports, __webpack_require__) {

      var __vue_exports__, __vue_options__
      var __vue_styles__ = []

      /* styles */ //獲取styles modules
      __vue_styles__.push(__webpack_require__(1))

      /* script */ //獲取script module
      __vue_exports__ = __webpack_require__(2)

      /* template */ //獲取template module
      var __vue_template__ = __webpack_require__(3)
      
      //__vue_exports__ || {}意思是如果__vue_exports__為空,就執行||後面那一項,即返回{},否則就返回__vue_exports__
      __vue_options__ = __vue_exports__ = __vue_exports__ || {} 
      if (
        typeof __vue_exports__.default === "object" ||  //typeof是用來判斷某個obj的型別的。
        typeof __vue_exports__.default === "function"
      ) {

    //下面這裡有2個方法,一個是Object.keys(obj),是將obj裡的所有成員變數的key放在陣列中,並返回例如返回['key1','key2','key3']
    //另一個是陣列的some方法,array.some(function(key){xxx}),這裡會將array中的每個key傳給function,進行執行判斷,返回boolean值。只要有一個值為true,那array.some(function(key){xxx})就為true,否則為false。
        if (Object.keys(__vue_exports__).some(
          function (key) {
            return key !== "default" && key !== "__esModule"
          }
        )
        ) {
          console.error("named exports are not supported in *.vue files.")
        }
        __vue_options__ = __vue_exports__ = __vue_exports__.default
      }


      if (typeof __vue_options__ === "function") {
        __vue_options__ = __vue_options__.options
      }
      __vue_options__.__file = "/home/linshaoyou1/work/patch-code/flyme5/flyme5_base/meizu/SDK/ali-weex5/src/index.vue"
      __vue_options__.render = __vue_template__.render
      __vue_options__.staticRenderFns = __vue_template__.staticRenderFns
      __vue_options__._scopeId = "data-v-6cc2e18e"
      __vue_options__.style = __vue_options__.style || {}
      __vue_styles__.forEach(function (module) {
        for (var name in module) {
          __vue_options__.style[name] = module[name]
        }
      })
      if (typeof weex === "object" && weex && weex.document) {
        try {
          weex.document.registerStyleSheets(__vue_options__._scopeId, __vue_styles__)
        } catch (e) { }
      }

      module.exports = __vue_exports__
      module.exports.el = 'true'
      new Vue(module.exports)


      /***/
    }),
/* 1 */
/***/ (function (module, exports) {

      module.exports = {
        "wrapper": {
          "justifyContent": "center",
          "alignItems": "center"
        },
        "logo": {
          "width": "424",
          "height": "200"
        },
        "greeting": {
          "marginTop": "70",
          "fontSize": "50",
          "color": "#41B883"
        },
        "message": {
          "marginTop": "30",
          "marginRight": "30",
          "marginBottom": "30",
          "marginLeft": "30",
          "fontSize": "32",
          "color": "#727272"
        }
      }

      /***/
    }),
/* 2 */
/***/ (function (module, exports, __webpack_require__) {

      "use strict"; //使用嚴苛模式,所以如果沒有遵循語法,會報異常。例如,某個變數不宣告,就開始使用,會報異常。


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

      exports.default = {
        data: function data() {
          return {
            logo: 'https://gw.alicdn.com/tfs/TB1yopEdgoQMeJjy1XaXXcSsFXa-640-302.png'
          };
        }
      };

      /***/
    }),
/* 3 */
/***/ (function (module, exports) {

      module.exports = {
        render: function () {
          var _vm = this;
          var _h = _vm.$createElement; 
          var _c = _vm._self._c || _h; //這裡_c就是建立元素,也就是建立虛擬節點的方法。
          return _c(
            'div', //type 標籤
            {
              staticClass: ["wrapper"] // style的class
            },
            [ //這個標籤下的子標籤
              _c(
                'image',
                {
                  staticClass: ["logo"],
                  attrs: {
                    "src": _vm.logo //其他屬性
                  }
                }
              ),
              _c(
                'text',
                {
                  staticClass: ["greeting"]
                },
                [
                  _vm._v("The environment is ready!") //子標籤裡只有String字串。
                ]
              ),
              _c(
                'text',
                {
                  staticClass: ["message"]
                },
                [
                  _vm._v("Now, let's use Vue.js to build your Weex app.")
                ]
              )
            ]
          )
        },
        staticRenderFns: []
      }
      module.exports.render._withStripped = true

      /***/
    })
  ]);
複製程式碼

相關文章