通过上一篇 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
/***/
})
]);
复制代码