这是一篇有故事的文章 --- 来自一个weex在生产环境中相爱相杀的小码农
故事一: Build
虽然weex
的口号是一次撰写,多端运行, 但其实build
环节是有差异的, native
端构建需要使用weex-loader
, 而web
端则是使用vue-loader
,除此以外还有不少差异点, 所以webpack
需要两套配置。
最佳实践
使用webpack
生成两套bundle
,一套是基于vue-router
的web spa
, 另一套是native
端的多入口的bundlejs
首先假设我们在src/views
下开发了一堆页面:
build web配置
web端的入口文件有 render.js
main.js
App.vue
webpack.prod.conf.js
入口
build native配置
native端的打包流程其实就是将src/views
下的每个.vue
文件导出为一个个单独的vue
实例, 写一个node
脚本即可以实现。
webpack.build.conf.js
中生成并打包多入口:
最终效果:
故事二: 使用预处理器
在vue
单文件中, 我们可以通过在vue-loader
中配置预处理器, 代码如下:
而weex
在native环境下其实将css
处理成json
加载到模块中, 所以...
- 使用vue-loader配置的预处理器在web环境下正常显示, 在native中是无效的。
- native环境下不存在全局样式, 在js文件中import 'index.css'也是无效的。
解决问题一
研究weex-loader
源码后发现在.vue
中是无需显示配置loader
的, 只需要指定<style lang="stylus">
并且安装stylus stylus-loader
即可,weex-loader
会根据lang
去寻找对应的loader
. 但因为scss
使用sass-loader
, 会报出scss-loader not found
, 但因为sass
默认会解析scss
语法, 所以直接设置lang="sass"
是可以写scss
语法的, 但是ide
就没有语法高亮了. 可以使用如下的写法:
语法高亮, 完美!
解决问题二
虽然没有全局样式的概念, 但是支持单独import
样式文件。
故事三: 样式差异
这方面官方文档已经有比较详细的描述, 但还是有几点值得注意的。
简写
weex
中的样式不支持简写, 所有类似margin: 0 0 10px 10px
的都是不支持的。
背景色
android
下的view是有白色的默认颜色的, 而iOS如果不设置是没有默认颜色的, 这点需要注意。
浮点数误差
weex
默认使用750px * 1334px
作为适配尺寸, 实际渲染时由于浮点数的误差可能会存在几px
的误差, 出现细线等样式问题, 可以通过加减几个px
来调试。
嵌套写法
即使使用了预处理器, css
嵌套的写法也是会导致样式失效的。
故事四: 页面跳转
weex
下的页面跳转有三种形式:
native -> weex
:weex
页面需要一个控制器作为容器, 此时就是native
间的跳转。weex -> native
: 需要通过module形式通过发送事件到native来实现跳转。weex -> weex
: 使用navigator模块, 假设两个weex
页面分别为a.js, b.js
, 可以定义mixin
方法。
- 这样就组件里使用
this.push(url), this.pop()
来跳转。
跳转配置
- iOS下页面跳转无需配置, 而
android
是需要的, 使用weexpack platform add android
生成的项目是已配置的, 但官方的文档里并没有对于已存在的应用如何接入进行说明。 - 其实
android
中是通过intent-filter
来拦截跳转的。
- 然后我们新建一个
WXPageActivity
来代理所有weex
页面的渲染, 核心的代码如下:
故事五: 页面间数据传递
native -> weex
: 可以在native
端调用render
时传入的option
中自定义字段, 例如NSDictary *option = @{@"params": @{}}
, 在weex
中使用weex.config.params
取出数据。weex -> weex
: 使用storage。weex -> native
: 使用自定义module。
故事六: 图片加载
官网有提到如何加载网络图片 但是加载本地图片的行为对于三端肯定是不一致的, 也就意味着我们得给native
重新改一遍引用图片的路径再打包...
但是当然是有解决办法的啦。
- Step 1
webpack
设置将图片资源单独打包, 这个很easy, 此时bundleJs
访问的图片路径就变成了/images/..
- Step 2 那么现在我们将同级目录下的js文件夹与images文件夹放入
native
中, iOS中一般放入mainBundle
, Android一般放入src/main/assets
, 接下来只要在imgloader
接口中扩展替换本地资源路径的代码就ok了。
iOS
代码如下:
Android
代码如下:
故事七: 生产环境的实践
增量更新
方案一
可以使用google-diff-match-patch来实现, google-diff-match-patch拥有许多语言版本的实现, 思路如下:
- 服务器端构建一套管理前端
bundlejs
的系统, 提供查询bundlejs
版本与下载的api。 - 客户端第一次访问
weex
页面时去服务端下载bundlejs
文件。 - 每次客户端初始化时静默访问服务器判断是否需要更新, 若需更新, 服务器端
diff
两个版本的差异, 并返回diff
,native
端使用patch api
生成新版本的bundlejs
方案二
还可以参考很多ReactNative的成熟方案, 本质上都是js的热更新。
降级处理
一般情况下, 我们会同时部署一套web
端界面, 若线上环境的weex
页面出现bug, 则使用webview加载web
版, 推荐依赖服务端api来控制降级的切换。
总结
weex
的优势: 依托于vue
, 上手简单. 可以满足以vue
为技术主导的公司给native
双端提供简单/少底层交互/热更新需求的页面的需求。
weex
的劣势: 在native
端调整样式是我心中永远的痛.. 以及众所周知的生态问题, 维护组没有花太多精力解答社区问题, 官方文档错误太多, 导致我在看的时候就顺手提了几个PR。
扫码下方二维码,
随时关注更多前端干货文章!
▼
微信:IMWebTech