weex学习之路(一)--项目快速创建
weex是阿里开源的一款类似react-native的使用js开发客户端的框架,不过使用的前端框架是vue而不是react。不过阿里有另外一个rax框架是类似react的的框架 语法和api基本相同,也支持jsx。weex官网:https://weex.apache.org/cn/vue官网:https://cn.vuejs.org/rax:https://aliba
weex是阿里开源的一款类似react-native的使用js开发客户端的框架,不过使用的前端框架是vue而不是react。不过阿里有另外一个rax框架是类似react的的框架 语法和api基本相同,也支持jsx。
weex官网:https://weex.apache.org/cn/
vue官网:https://cn.vuejs.org/
rax:https://alibaba.github.io/rax/
用了weex大概小半年,开发了2款客户端产品(基本使用js开发,原生提供能力), 基本可以满足大部分日常的需求,踩过一些坑,以及还有一些Bug这边就不一一赘述了(后面会考虑专门写一个关于坑和遇到的bug的文章)。
另外多说一句,因为阿里推荐使用weexpack(好像是叫这个名字),不这么用的来,所以没有用这个工具,打包我是使用webpack。
1:创建一个npm工程 npm init(这个我就不多说了)
2:使用https://github.com/fengwuxp/weex_componets 这个我自己整理的weex的一个通用模块,
因为有部分功能不是很通用,所以就没有发布npm的包。
这个项目大体分以下几部分:
一:通用api请求的统一封装(数据交换乃是重中之重,所以第一个讲)
weex有内置一个stream模块(https://weex.apache.org/cn/references/modules/stream.html)用于数据请求或者提交 android是用oakhttp,ios(抱歉,真心不懂),web端使用XHLHttpRequest对象实现。有写过jquery的人应该被$.ajax的写法郁闷过,接口一多代码简直不能看,而且不好维护,所以这边推荐typeScript(https://tslang.cn/samples/index.html),面向对象的js,语法和java相近。
不多废话了,api的封装可以看我之前写的文章基于typeScript请求服务端的js-api-sdk统一封装思路 这个例子是就是基于 weex的stream对象写的,不过后面发现weex不支持es6( 阮一峰es6教程)的proxy对象,所以写了一个es5的降级版本,部分代码如下(完整代码在上面贴的git项目中都有):
服务方法实现示例:
调用示例:
import ApiReqFactory from "wxp_weex_componets/src/utils/ApiReqFactory";
import memberService from 'xxx/member/memberService ';
let req=ApiReqFactory.newInstancesReq({
userName:""
});
memberService login(req).then(()=>{
}).catch(()=>{
}).finally(()=>{
});
这里主要使用了es6的 Promise ,有疑问的可以参考之前贴的阮一峰大神写的教程。
提示:typescript的服务成可以使用自动生成(让开发服务端的同靴配合一一下,可以少些很多代码,而且如果api模块有多个项目有改动,可以抽象成一个单独的项目,发布到自己的npm私服)
备注:
api模块要求使用这个模块的项目需要提供一个配置以及一个用户登陆状态(或者是token)获取的ts文件
这个目前没有找到更好的方式先使用约定的方式。具体要做什么请参见代码。
另外在ApiClientWeex.ts的实现中有一些关键服务端数据请求签名的实现,大家可以根据自己的情况自行修改
3:将项目打包成js文件
打包使用webpack,(webpack版没有什么托儿所要求 ) 。因为路由的问题web端和原生端的打包结果不同,web端使用常规的打包方式(打包成一个js文件),原生端每个页面都打包成一个js文件。
打包配置在
使用方式:
在项目目录和src目录同级目录下创建一个webpack-config目录,里面分别有 webpack.native.config.js 打包原生测试包
const config = require("wxp_weex_componets/webpack- native/webpack.native.config");
const webpack = require('webpack');
const {DEV_API_ADDRESS} = require("./WebpackConfig");
config.plugins.push(
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"dev"',
API_ROOT: JSON.stringify(DEV_API_ADDRESS)
}
})
);
module.exports = config;
webpack.native.config.prod.js 打正式包
const config=require("wxp_weex_componets/webpacknative/webpack.native.config.prod");
module.exports = config;
WebpackConfig.js 打包配置(这个文件的文件必须是这个,因为在wxp_weexx_compents里面有依赖它)
/**
* webpack 打包配置
* @type {[string,string]}
*/
const INCLUDE_PATH=["xxx_api_sdk"]; //需要从node_modules引入的自己的源码模块
//开发环境请求域名
const DEV_API_ADDRESS="test.xxx";
//正式环境请求域名
const PROD_API_ADDRESS="xxx";
module.exports= {
INCLUDE_PATH,
DEV_API_ADDRESS,
PROD_API_ADDRESS
};
常规开发一般是web上开发和调试,最后到原生上测试,所有需要有web端的打包配置:
具体代码如下:
webpack.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require('path');
const webpack = require('webpack');
const {getBaseConfig} = require('wxp_weex_componets/webpack- web/WebpackWebUtils');
const {DEV_API_ADDRESS} = require('./webpack-config/WebpackConfig');
const webConfig = getBaseConfig({
entry: {
app: path.resolve('src', 'Main'),
},
output: {
path: path.resolve(__dirname, 'dist_web'),
filename: '[name].web.js'
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: "index.html",
title: "xxxxx",
chunks: ["app"],
inject: false,
}),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"dev"',
API_ROOT:JSON.stringify(DEV_API_ADDRESS)
}
})
]
});
webConfig.module.rules[1].loaders.push('vue-loader');
console.log(webConfig);
module.exports = webConfig;
webpack.dev.js:
const configs = require('./webpack.config.js');
const webpack = require('webpack');
const ip = require('quick-local-ip').getLocalIP4();
const pathTo = require('path');
const chalk = require('chalk');
let config = Array.isArray(configs) ? configs[0] : configs;
config.devServer = {
contentBase: pathTo.join(__dirname, ''),
compress: true,
host: '0.0.0.0',
public: ip + ':8089',
};
console.log('server is running! Please open ' + chalk.green('http://' + ip + ':8089/index.html'));
module.exports = config;
webpack.prod.config.js:
const webpack = require('webpack');
const UglifyJsPlugin = webpack.optimize.UglifyJsPlugin;
const HtmlWebpackPlugin = require("html-webpack-plugin");
const {getBaseConfig} = require('wxp_weex_componets/webpack- web/WebpackWebUtils');
const {PROD_API_ADDRESS} = require('./webpack-config/WebpackConfig');
const webConfig = getBaseConfig({
entry: {
app: path.resolve('src', 'Main'),
},
output: {
path: path.resolve(__dirname, 'dist_web'),
filename: '[name].web.js'
},
plugins:[
new HtmlWebpackPlugin({
template: './src/index.html',
filename: "index.html",
title: "xxxxx",
chunks: ["app"],
inject: false,
}),
new UglifyJsPlugin({
// 最紧凑的输出
beautify: false,
// 删除所有的注释
comments: false,
compress: {
// 在UglifyJs删除没有用到的代码时不输出警告
warnings: false,
// 删除所有的 `console` 语句
// 还可以兼容ie浏览器
drop_console: true,
// 内嵌定义了但是只用到一次的变量
collapse_vars: true,
// 提取出出现多次但是没有定义成变量去引用的静态值
reduce_vars: true,
}
}),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"prod"',
API_ROOT:JSON.stringify(PROD_API_ADDRESS)
}
})
]
});
webConfig.module.rules[1].loaders.push('vue-loader');
module.exports = webConfig;
最后附上package.json等配置
{
“name”: “jn_operation_center”,
“version”: “1.0.0”,
“description”: “”,
“main”: “index.js”,
“keywords”: [
“weex”,
“vue”,
“javascript”,
“android”,
“ios”
],
“scripts”: {
“serve-dev”: “webpack-dev-server –config webpack.dev.js –devtool eval –progress –colors –watch –port 8089 –open”,
“build:native”: “webpack –config webpack-config/webpack.native.config.js –progress –colors”,
“build:web-prod”: “webpack –config webpack.prod.config.js –progress –colors”,
“build:native-prod”: “webpack –config webpack-config/webpack.native.config.prod.js –progress –colors”,
“build:two-prod”: “npm run build:web-prod & npm run build:native-prod –progress –colors”
},
“engines”: {
“node”: “>=4.0”
},
“license”: “Apache-2.0”,
“dependencies”: {
“md5”: “^2.2.1”,
“natjs”: “0.0.4”,
“vue-router”: “^2.1.1”,
“weex-vue-framework”: “^2.4.2-weex.3”,
“weex-vue-render”: “^0.12.1”
},
“devDependencies”: {
“@types/lodash”: “^4.14.66”,
“@types/node”: “^7.0.16”,
“awesome-typescript-loader”: “^3.2.2”,
“babel-core”: “^6.24.1”,
“babel-istanbul”: “^0.11.0”,
“babel-loader”: “^7.0.0”,
“babel-plugin-coverage”: “^1.0.0”,
“babel-plugin-import”: “^1.1.1”,
“babel-polyfill”: “^6.23.0”,
“babel-preset-es2015”: “^6.24.1”,
“babel-preset-stage-2”: “^6.24.1”,
“babel-register”: “^6.24.1”,
“babel-runtime”: “^6.11.6”,
“css-loader”: “^0.28.1”,
“html-webpack-plugin”: “^2.6.5”,
“isomorphic-fetch”: “^2.2.1”,
“node-sass”: “^4.5.3”,
“quick-local-ip”: “^1.0.7”,
“reflect-metadata”: “^0.1.10”,
“sass-loader”: “^6.0.6”,
“serve”: “^5.1.5”,
“style-loader”: “^0.13.2”,
“typescript”: “^2.4.2”,
“typings”: “^2.1.1”,
“vue”: “^2.3.0-beta.1”,
“vue-loader”: “^13.0.2”,
“vue-template-compiler”: “^2.4.2”,
“webpack”: “^3.4.1”,
“webpack-dev-middleware”: “^1”,
“webpack-dev-server”: “^2.6.1”,
“weex-loader”: “^0.5.3”
}
}
tsconfig配置:
{
“compilerOptions”: {
“moduleResolution”: “node”,
“allowSyntheticDefaultImports”: true,
“emitDecoratorMetadata”: true,
“experimentalDecorators”: true,
“module”: “commonjs”,
“target”: “es6”,
“sourceMap”: true,
“allowJs”:true,
“lib”: [
“dom”,
“es5”,
“es2015”,
“es2015.promise”
]
},
“compileOnSave”: false,
“include”: [
“src/*/”
],
“exclude”: [
“config/dist”,
“node_modules”,
“*/.spec.ts”
]
}
.babelrc:
{ “presets”: [“es2015”] }
基本流程大体如下,有疑问的可以在下面留言。另外附一篇写的很好的博文:最全的weex踩坑攻略-出自大量实践与沉淀,大家可以参考一下。
更多推荐
所有评论(0)