Weex是使用Vue和WebPack进行项目配置的。Weex创建的项目默认是只有一个入口的,也就是说,是单页面应用。对于移动开发来说,使用单页面(使用vue-router)是没有原生的页面跳转效果。在Weex的官方文档中,Weex提供了navigator内置模块来实现Web端前进、后退页面,以及iOS/Android的navigator导航效果。
我使用的是最近的weex创建的项目,下面是weex的项目结构。
我们打开weebpack.config.js。
// You can see all the config in `./configs`.
const buildPlugins = require('./configs/plugin');
let webpackConfig;
module.exports = env => {
switch (env.NODE_ENV) {
case 'prod':
case 'production':
webpackConfig = require('./configs/webpack.prod.conf');
break;
case 'test':
case 'testing':
webpackConfig = require('./configs/webpack.test.conf');
break;
case 'plugin':
buildPlugins();
case 'common':
webpackConfig = require('./configs/webpack.common.conf');
break;
case 'release':
webpackConfig = require('./configs/webpack.release.conf');
break;
case 'dev':
case 'development':
default:
webpackConfig = require('./configs/webpack.dev.conf');
}
return webpackConfig;
}
可以看到webpackConfig的配置根据特定环境放在不同的文件。
我们打开configs文件夹下的webpack.common.conf.js,这个文件是配置weex和web的入口。weex把移动端和web端的webpack入口和出口配置分为weex和web。
我们在configs/webpack.common.conf.js下找到weexEntry。
const weexEntry = {
'index': helper.root('entry.js'),
'login': helper.root('login.js'),
}
这里我已经创建了src/login.js文件,这个文件和src/entry.js的内容是一样的,只是对应的vue不同。和entry.js一样都会在使用web/index.html作为页面渲染。下面是src/login.js。
/*global Vue*/
/* weex initialized here, please do not move this line */
const router = require('./router');
const App = require('@/login.vue');
/* eslint-disable no-new */
new Vue(Vue.util.extend({el: '#root', router}, App));
router.push('/');
以上就是weexConfig的入口配置(iOS/Android的webpack入口配置)。weex已经帮我们配置好weexConfig的出口配置。
const weexConfig = {
entry: weexEntry,
output: {
path: path.join(__dirname, '../dist'),
filename: '[name].js'
},
/**
* Options affecting the resolving of modules.
* See http://webpack.github.io/docs/configuration.html#resolve
*/
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'@': helper.resolve('src')
}
},
/*
* Options affecting the resolving of modules.
*
* See: http://webpack.github.io/docs/configuration.html#module
*/
module: {
rules: [
{
test: /\.js$/,
use: [{
loader: 'babel-loader'
}],
exclude: config.excludeModuleReg
},
{
test: /\.vue(\?[^?]+)?$/,
use: [{
loader: 'weex-loader',
options: vueLoaderConfig({useVue: false})
}],
exclude: config.excludeModuleReg
}
]
},
我们在configs/webpack.common.conf.js下找到webEntry。
// The entry file for web needs to add some library. such as vue, weex-vue-render
// 1. src/entry.js
// import Vue from 'vue';
// import weex from 'weex-vue-render';
// weex.init(Vue);
// 2. src/router/index.js
// import Vue from 'vue'
const webEntry = getEntryFile();
上面有一些注释,说明webConfig的入口文件需要导入Vue和weex-vue-render模块。我们找到getEntryFile()函数。
const getEntryFile = () => {
const entryFile = path.join(vueWebTemp, config.entryFilePath)
const routerFile = path.join(vueWebTemp, config.routerFilePath)
fs.outputFileSync(entryFile, getEntryFileContent(helper.root(config.entryFilePath), routerFile));
fs.outputFileSync(routerFile, getRouterFileContent(helper.root(config.routerFilePath)));
const loginFilePath = 'login.js'
const loginFile = path.join(vueWebTemp, loginFilePath)
fs.outputFileSync(loginFile, getEntryFileContent(helper.root(loginFilePath), routerFile));
return {
index: entryFile,
login: loginFile,
}
}
这个函数的entryFile使用的是path/vueWebTemp/config.entryFilePath的文件,routerFile使用的是path/vueWebTemp/config.routerFilePath的文件。
我们找到vueWebTemp和config.entryFilePath。
const path = require('path');
const fs = require('fs-extra');
const webpack = require('webpack');
const config = require('./config');
const helper = require('./helper');
const glob = require('glob');
const vueLoaderConfig = require('./vue-loader.conf');
const vueWebTemp = helper.rootNode(config.templateDir);
config是当前目录下的config.js文件。下面是config.js的部分代码。
const path = require('path');
const ROOT = path.resolve(__dirname, '..');
const ip = require('ip').address();
const config = {
root: ROOT,
// webpack-dev-server
pluginConfigPath: 'plugins/plugins.json',
pluginFilePath: 'plugins/plugins.js',
// router
routerFilePath: 'router.js',
// common
templateDir: '.temp',
entryFilePath: 'entry.js',
// Module exclude from compile process
excludeModuleReg: /node_modules(?!(\/|\\).*(weex).*)/,
我们看到templateDir是项目中的.temp文件,entryFilePath是entry.js,routerFilePath是router.js。
在getEntryFile()的entryFile就是项目下的.temp/entry.js。routerFile就是项目下的.temp/router.js。
我们按照上面的例子,创建login.js的webConfig入口文件。下面是login.js代码,它和entry.js的代码是一样的,只是对于的vue不同。
import Vue from 'vue'
import weex from 'weex-vue-render'
/*global Vue*/
weex.init(Vue)
/* weex initialized here, please do not move this line */
const router = require('./router');
const App = require('@/login.vue');
/* eslint-disable no-new */
new Vue(Vue.util.extend({el: '#root', router}, App));
router.push('/');
我们看到之前注释说明需要导入的vue和weex-vue-render模块。
按照getEntryFile()函数的指示,我们需要把入口文件和router文件同步到src目录的入口文件和router文件内容。(helper的root是src文件夹)。以下是helper.js的代码内容。
// Helper functions
const path = require('path');
const ROOT = path.resolve(__dirname, '..');
const root = (args) => {
return path.join(ROOT, 'src', args);
}
const rootNode = (args) => {
return path.join(ROOT, args);
}
const resolve = (dir) => {
return path.join(__dirname, '..', dir)
}
module.exports = {
root,
rootNode,
resolve
}
由于weex之前已经帮我们在src创建了entry.js和router.js,我们之前在配置weexConfig时已经创建了login.js。所以这段代码是把.temp文件和src的文件内容同步。最后我们在getEntryFile()返回我们的loginFile入口文件。
以上就是webConfig的入口配置,weex已经帮我们配置好webConfig的出口配置。
// Config for compile jsbundle for web.
const webConfig = {
entry: Object.assign(webEntry, {
'vendor': [path.resolve('node_modules/phantom-limb/index.js')]
}),
output: {
path: helper.rootNode('./dist'),
filename: '[name].web.js'
},
我们需要编译src文件到dist文件才能生效。在命令行输入weex compile src dist编译src文件夹到dist文件夹。
由于web和iOS/Android是分开配置的,所以它们的URL分别对应web的http跳转和iOS/Android生成的本地文件的js跳转。
methods: {
login () {
navigator.push({url:this.getJumpBaseUrl('login')})
},
getJumpBaseUrl(toUrl) {
var bundleUrl = weex.config.bundleUrl;
bundleUrl = new String(bundleUrl);
var nativeBase;
var native;
if (WXEnvironment.platform === 'Android') {
nativeBase = 'file://assets/dist/';
native = nativeBase + toUrl + ".js";
} else if (WXEnvironment.platform === 'iOS') {
nativeBase = bundleUrl.substring(0, bundleUrl.lastIndexOf('/') + 1);
native = nativeBase + toUrl + ".js";
} else {
var host = 'localhost:8081';
var matches = /\/\/([^\/]+?)\//.exec(bundleUrl);
if (matches && matches.length >= 2) {
host = matches[1];
}
//此处需注意一下,tabbar 用的直接是jsbundle 的路径,但是navigator是直接跳转到新页面上的.
if (typeof window === 'object') {
nativeBase = 'http://' + host + '/';
} else {
nativeBase = 'http://' + host + '/';
}
native = nativeBase + toUrl + ".html";
}
return native;
}
}