Open qinyuanf opened 4 years ago
当前解读的脚手架是基于 weex 官方脚手架的升级版。
目录:
flex-wrap
启动开发平台
npm run ui
开发平台部分功能说明
开发阶段针对 css 端的日志输出主要分为以下几种形式:
以上控制台提示都是针对 native 端的兼容问题,也许 H5 端显示正常,但是都需要进行 css 样式调整,避免出现不必要的兼容问题。经过多方确认后某个 css 样式已经被 weex 支持,该样式将被记录同步到 npm 私服(weex-styler 已使用自定义 loader)。
|-- weex-code-weiyi |-- .temp 用于 webpack 打包的入口文件 | |-- insurance | | |-- demo | | |-- index.js web 端入口 | |-- index.web.js native 端入口 |-- build webpack 配置文件 | |-- webpack.common.conf.js 通用配置 | |-- webpack.dev.conf.js 开发环境配置 | |-- webpack.prod.conf.js 生产环境配置 |-- config 环境变量配置 | |-- weex.config.dev.js 开发 | |-- weex.config.prod.js 生产 | |-- weex.config.test.js 测试 | |-- index.js |-- dist 打包文件目录 | |-- insurance | |-- demo | |-- index.js 用于 native 端解析 | |-- index.web.js 用于 web 端解析 | |-- weex-zip 压缩包目录,用于上传到 kano | |-- insurance-demo-index.zip 压缩了 index.js 和 index.web.js |-- plugins 插件目录,暂未使用 | |-- plugins.json |-- server weex 工作台服务器 |-- src 业务文件目录 | |-- api api 接口相关 | | |-- modules api 模块 | | |-- insurance | | | |-- demo.js | | |-- gateway-api.js 请求方法封装 | | |-- index.js | |-- lib 工具方法 | |-- modules weex 模块 H5 实现 | | |-- log | | |-- monitor | | |-- nav | | |-- share | | |-- user | | |-- index.js | |-- pages weex 页面 | |-- components | |-- insurance | | |-- demo | | |-- components | | |-- index.vue | |-- entry.js 入口模板,用于生成 .temp 文件下 web 端和 native 端入口 |-- test 测试用例 |-- web weex 工作台前端页面 |-- .babelrc babel 配置文件 |-- .eslintignore eslint 忽略的文件目录 |-- .eslintrc.js eslint 配置规则 |-- .gitignore git 忽略的文件目录 |-- .gitlab-ci.yml git-ci 运行文件 |-- .postcssrc.js postcss配置文件 |-- android.config.json android 配置,暂未使用 |-- ios.config.json ios 端配置,暂未使用 |-- config.json 项目配置文件,重要!!!用于修改全局配置项 |-- webpack.config.js 根据当前环境判定,最终输出的 webpack 配置项 |-- package.json |-- README.md
解读一个项目结构最好的入口就是 package.json,代码如下:
{ "scripts": { // 建立缓存并启动 weex 开发平台 "ui": "npm run cache && node ./server/app.js", // 开发模式使用全量打包 "dev": "cross-env NODE_ENV=development webpack-dev-server --progress", // 生产环境使用全量打包 "build:prod": "cross-env NODE_ENV=production webpack", // 测试环境使用全量打包 "build:test": "cross-env NODE_ENV=test webpack", // 开发环境使用单页打包 "dev:single": "cross-env NODE_ENV=development PACKAGE_PATH=insurance/demo/index webpack-dev-server --progress", // 生产环境使用单页打包 "build:prod:single": "cross-env NODE_ENV=production PACKAGE_PATH=insurance/demo/index webpack", // 测试环境使用单页打包 "build:test:single": "cross-env NODE_ENV=test PACKAGE_PATH=insurance/demo/index webpack", // 创建数据缓存,用于某些全局配置 "cache": "node ./server/utils/create-cache.js" } }
用于抹平不同平台(如 windows等)设置环境变量方式的差异,cross-env 之后 webpack/webpack-dev-server 之前即在设置环境变量。
环境变量完全可以自定义,当前使用以下变量:
NODE_ENV:设置开发/测试/生产环境
PACKAGE_PATH:需要打包的文件路径,不传则表示全量打包
webpack/webpack-dev-server:使用 webpack/webpack-dev-server 进行打包。
--config:指定配置文件进行构建,不指定则默认为 webpack.config.js,本项目为默认。
--progress:打印出编译进度的百分比值。
参考:https://webpack.docschina.org/api/cli/#%E5%B8%B8%E7%94%A8%E9%85%8D%E7%BD%AE
通过 package.json 设置的环境变量 NODE_ENV 来区分当前环境应该加载哪个打包配置文件,代码如下:
NODE_ENV
let webpackConfig module.exports = () => { switch (process.env.NODE_ENV) { case 'prod': case 'production': webpackConfig = require('./build/webpack.prod.conf') break case 'test': case 'testing': webpackConfig = require('./build/webpack.test.conf') break case 'dev': case 'development': default: webpackConfig = require('./build/webpack.dev.conf') } return webpackConfig }
分别查看三个文件的导出,如下:
// webpack.dev.conf module.exports = new Promise((resolve, reject) => { // ...省略了很多代码 resolve(webConfig) }) // webpack.test.conf module.exports = [weexConfig, webConfig] // webpack.prod.conf module.exports = [weexConfig, webConfig]
疑问:命令行 webpack 能加载几种类型的配置文件?
三种。
// 导出为一个函数,如下代码 module.exports = function(env, argv) { return { mode: env.production ? 'production' : 'development', devtool: env.production ? 'source-maps' : 'eval' } } // 导出一个 Promise module.exports = () => { return new Promise((resolve, reject) => { setTimeout(() => { resolve({ entry: './app.js', /* ... */ }) }, 5000) }) } // 导出多个配置对象 // 作为导出一个配置对象/配置函数的替代,你可能需要导出多个配置对象(从 webpack 3.1.0 开始支持导出多个函数)。当运行 webpack 时,所有的配置对象都会构建。 module.exports = [{ output: { filename: './dist-amd.js', libraryTarget: 'amd' }, name: 'amd', entry: './app.js' }, { output: { filename: './dist-commonjs.js', libraryTarget: 'commonjs' }, name: 'commonjs', entry: './app.js' }]
参考:https://webpack.docschina.org/configuration/configuration-types/
按照思路,解析完 webpack.config.js 之后应该分别解读各个环境下 webpack 的配置文件,但这里先看一下 weex 的整体架构思路。
Weex 主要用于编写多页的应用程序,每个页面都对应了原生开发中的 View 或者 Activity,并且保持自己的上下文。
从 weex 官方文档来看,weex 是一个多页应用,区别于普通的 spa 及 ssr 应用,也正是这个特性,webpack 的打包方式也有所不同,优化方式也与之前完全不同。接下去的分析也会逐渐印证 weex 是个多页应用。
我们从入口开始分析,src/entry.js 作为入口模板,用于生成 .temp 文件下 web 端入口,代码如下:
entry.js
import Vue from 'vue' import weex from 'weex-vue-render' import initModules from '@/modules/index' import initRouteQuery from '@/lib/query' // 挂载 Vue weex.init(Vue) // 初始化自定义模块,如 log、nav 等 initModules(weex) // 初始化路由参数模块 // 将路由参数挂载到 weex.config initRouteQuery(weex)
.temp/**/index.web.js
import Vue from 'vue' import weex from 'weex-vue-render' import initModules from '@/modules/index' import initRouteQuery from '@/lib/query' // 挂载 Vue weex.init(Vue) // 初始化自定义模块 initModules(weex) // 初始化路由参数模块 initRouteQuery(weex) // 以下代码是与 entry.js 的差异之处 // .vue 的路径从文件夹目录读取 // 由此可见,weex 项目是多页的,每个入口文件对应一个路径 const App = require('../../../src/pages/insurance/demo/index.vue') new Vue(Vue.util.extend({el: '#root'}, App))
.temp/**/index.js
// h5 端所需要的自定义模块及参数模块,在 app 端都有同步实现 // 因此 native 的入口文件相较于 h5 端少很多东西 import App from '../../../src/pages/insurance/demo/index.vue' App.el = '#root' new Vue(App)
该文件夹主要放置与 webpack 构建相关的配置文件及工具方法。
webpack.dev.conf/webpack.test.conf/webpack.prod.conf 从这三个文件中可以发现都引用了 webpack.common.conf.js,所以从该文件开始看起。查看详情
@
config
pages
// { "framework": "Vue"}
经过 vue-loader的 postTransformNode image 标签被渲染为 AST。
postTransformNode
{ type: 1, tag: 'image', attrsList: [ { name: 'src', value: 'https://vuejs.org/images/logo.png' } ], attrsMap: { style: 'width:500px;height:500px', src: 'https://vuejs.org/images/logo.png' }, rawAttrsMap: {}, parent: { type: 1, tag: 'div', attrsList: [ [Object] ], attrsMap: { class: 'insurance-demo' }, rawAttrsMap: {}, parent: undefined, children: [ [Object], [Object], [Circular] ] }, children: [], ns: 'svg', plain: false, staticStyle: '{"width":"500px","height":"500px"}', attrs: [ { name: 'src', value: '"https://vuejs.org/images/logo.png"', dynamic: undefined } }
然后再通过 weex-vue-precompiler,在原来 AST 的基础上将 weex 特有的组件,如 text、image 等进一步转化为对应的 AST。
weex-vue-precompiler
{ type: 1, tag: 'figure', attrsList: [Array], attrsMap: [Object], rawAttrsMap: {}, parent: [Circular], children: [], plain: false, staticStyle: '{"width":"6.66667rem","height":"6.66667rem"}', attrs: [Array], _origTag: 'image', _weexBuiltIn: true, staticClass: '" weex-el weex-image"' } ], plain: false, staticClass: '"insurance-demo"' }
开发阶段的 webpack 配置文件,主要作用:
web 端
phantom-limb
native 端
生产阶段和测试阶段的配置文件,主要区别只有环境变量,主要作用:
h5 端实现自定义模块,这些模块在 app 端会由原生提供支持;推荐进行判空处理,万一 h5 端未实现,调试阶段会报错。
项目配置文件,变量说明
先看一张图:
从图中我们可以大致总结一下 weex 的工作流程:
前端编写 vue 单文件,通过 webpack 打包一份 js-bundle(上文已经比较透彻得讲述该文件在前端是如何被打包的),然后该 js-bundle 会通过上传工具(如 weex-manager)被上传到文件服务器(如 kano),文件信息被服务器(如 weex-renderer) 处理后保存到数据库;
打开 app 时,客户端会定时去请求服务器(如 weex-renderer),服务器会告诉 app 是否有新的 js-bundle 需要下载,如果需要则返回下载链接,客户端下载新的文件到本地并替换对应文件;
当打开一个页面时,客户端提供了 js 执行引擎(V8/js core,作用相当于浏览器),用于执行缓存在本地的 js-bundle;
在执行 js-bundle 之前,weex 执行引擎(v8/js core)还将加载 weex-vue-framework 框架,相当于在 weex 环境执行的 vue.js,区别在于 vue.js 最终生成了 dom,而该框架最终生成了 native dom;
前端为什么要分开打包,分为 index.js 和 index.web.js?
为什么在 app 内 weex 相较于 ssr 架构拥有更快的内容到达时间?
分析下当前所使用 Hybrid 方案:
app 内利用 webview 在线加载 h5 页面,h5 使用了 ssr 服务;
app 内置离线包(如首页)
weex
原生(不属于 hybrid 体系)
众所周知 app 内部 weex 页面的体验明显好于 h5,而在微信端或浏览器端 ssr 的效果要好于 spa。从用户角度出发,每次需求评审时要明确该需求在哪一端更有用户量。如果产品强调 seo,需要更快地首屏加载速度,会有大量合作方需求,那 ssr 是必要的;相反,产品更看重 app 内部的用户体验,需求都以 app 为主,h5 端的页面只要在某个活动时出现,此时 weex 的三端统一方案或许更合适。
作为一个项目,我们追求 h5 的迭代效率和原生的用户体验。作为一个脚手架,我们希望能够与时俱进,拥有更好的开发体验,更快的打包效率,在某个项目中使用了我们脚手架,如何保持脚手架的持续迭代可能会是接下去主要的尝试方向。。。
你好 非常感谢的文章 写的非常好 请问怎么联系你呢
weex 脚手架全面解读
当前解读的脚手架是基于 weex 官方脚手架的升级版。
目录:
问题分析
flex-wrap
,官网已支持,却仍旧抛出警告。项目特征
weex 开发平台
启动开发平台
npm run ui
开发平台部分功能说明
控制台日志输出
开发阶段针对 css 端的日志输出主要分为以下几种形式:
以上控制台提示都是针对 native 端的兼容问题,也许 H5 端显示正常,但是都需要进行 css 样式调整,避免出现不必要的兼容问题。经过多方确认后某个 css 样式已经被 weex 支持,该样式将被记录同步到 npm 私服(weex-styler 已使用自定义 loader)。
目录详解
文件目录
package.json
解读一个项目结构最好的入口就是 package.json,代码如下:
cross-env
用于抹平不同平台(如 windows等)设置环境变量方式的差异,cross-env 之后 webpack/webpack-dev-server 之前即在设置环境变量。
环境变量
环境变量完全可以自定义,当前使用以下变量:
NODE_ENV:设置开发/测试/生产环境
PACKAGE_PATH:需要打包的文件路径,不传则表示全量打包
命令参数
webpack/webpack-dev-server:使用 webpack/webpack-dev-server 进行打包。
--config:指定配置文件进行构建,不指定则默认为 webpack.config.js,本项目为默认。
--progress:打印出编译进度的百分比值。
参考:https://webpack.docschina.org/api/cli/#%E5%B8%B8%E7%94%A8%E9%85%8D%E7%BD%AE
webpack.config.js
通过 package.json 设置的环境变量
NODE_ENV
来区分当前环境应该加载哪个打包配置文件,代码如下:分别查看三个文件的导出,如下:
疑问:命令行 webpack 能加载几种类型的配置文件?
三种。
参考:https://webpack.docschina.org/configuration/configuration-types/
.temp 文件夹与 src/entry.js
按照思路,解析完 webpack.config.js 之后应该分别解读各个环境下 webpack 的配置文件,但这里先看一下 weex 的整体架构思路。
从 weex 官方文档来看,weex 是一个多页应用,区别于普通的 spa 及 ssr 应用,也正是这个特性,webpack 的打包方式也有所不同,优化方式也与之前完全不同。接下去的分析也会逐渐印证 weex 是个多页应用。
我们从入口开始分析,src/entry.js 作为入口模板,用于生成 .temp 文件下 web 端入口,代码如下:
entry.js
.temp/**/index.web.js
.temp/**/index.js
build 文件夹
该文件夹主要放置与 webpack 构建相关的配置文件及工具方法。
webpack.dev.conf/webpack.test.conf/webpack.prod.conf 从这三个文件中可以发现都引用了 webpack.common.conf.js,所以从该文件开始看起。查看详情
webpack.common.conf.js
@
、config
、pages
// { "framework": "Vue"}
注释经过 vue-loader的
postTransformNode
image 标签被渲染为 AST。然后再通过
weex-vue-precompiler
,在原来 AST 的基础上将 weex 特有的组件,如 text、image 等进一步转化为对应的 AST。webpack.dev.conf.js
开发阶段的 webpack 配置文件,主要作用:
web 端
phantom-limb
native 端
webpack.prod.conf.js/webpack.test.conf.js
生产阶段和测试阶段的配置文件,主要区别只有环境变量,主要作用:
native 端
web 端
src/modules 文件夹
h5 端实现自定义模块,这些模块在 app 端会由原生提供支持;推荐进行判空处理,万一 h5 端未实现,调试阶段会报错。
config.json 文件
项目配置文件,变量说明
简述 weex 工作机制
先看一张图:
从图中我们可以大致总结一下 weex 的工作流程:
前端编写 vue 单文件,通过 webpack 打包一份 js-bundle(上文已经比较透彻得讲述该文件在前端是如何被打包的),然后该 js-bundle 会通过上传工具(如 weex-manager)被上传到文件服务器(如 kano),文件信息被服务器(如 weex-renderer) 处理后保存到数据库;
打开 app 时,客户端会定时去请求服务器(如 weex-renderer),服务器会告诉 app 是否有新的 js-bundle 需要下载,如果需要则返回下载链接,客户端下载新的文件到本地并替换对应文件;
当打开一个页面时,客户端提供了 js 执行引擎(V8/js core,作用相当于浏览器),用于执行缓存在本地的 js-bundle;
在执行 js-bundle 之前,weex 执行引擎(v8/js core)还将加载 weex-vue-framework 框架,相当于在 weex 环境执行的 vue.js,区别在于 vue.js 最终生成了 dom,而该框架最终生成了 native dom;
问题解答
前端为什么要分开打包,分为 index.js 和 index.web.js?
为什么在 app 内 weex 相较于 ssr 架构拥有更快的内容到达时间?
分析下当前所使用 Hybrid 方案:
app 内利用 webview 在线加载 h5 页面,h5 使用了 ssr 服务;
app 内置离线包(如首页)
weex
原生(不属于 hybrid 体系)
众所周知 app 内部 weex 页面的体验明显好于 h5,而在微信端或浏览器端 ssr 的效果要好于 spa。从用户角度出发,每次需求评审时要明确该需求在哪一端更有用户量。如果产品强调 seo,需要更快地首屏加载速度,会有大量合作方需求,那 ssr 是必要的;相反,产品更看重 app 内部的用户体验,需求都以 app 为主,h5 端的页面只要在某个活动时出现,此时 weex 的三端统一方案或许更合适。
展望
作为一个项目,我们追求 h5 的迭代效率和原生的用户体验。作为一个脚手架,我们希望能够与时俱进,拥有更好的开发体验,更快的打包效率,在某个项目中使用了我们脚手架,如何保持脚手架的持续迭代可能会是接下去主要的尝试方向。。。