通過上一篇 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
/***/
})
]);
複製程式碼