目录
前面说到采用多线程来实现。在浏览器中,我们可以通过网页(master),逻辑线程(一个独立的ifame),UI线程(每个页面一个iframe)来解决多线程问题。
整个业务的目录结构参考微信小程序,由常见的 pages(页面),components(自定义组件),app.js,app.json等组成。
一个页面或者组件被分成4个文件。其中 html 使用是 vue模板;css 为标准 css 文件,后续可以扩展支持 scss,less等;js中涉及到logic层的直接引用,所有暂定的,export default
而不是 page()
。
业务需要同时运行在UI层和业务层下,所以对应的脚本需要被打包成相应的两份。以下设计 webpack插件的开发,了解 抢看 Webpack4插件 这边文章。
)
UI层
UI层我们主要使用Vue来实现,主要打包模块 vue-loader
。我们知道,vue-loader
主要是打包 .vue 文件,所以需要我们根据 html,css,js 产出一份相应的 vue 文件。webpack中,在webpack的 compile
阶段读取 app.json 里面 pages 的所有路由,生成对应的 .vue 文件,代码如下:
<template>${htmlCont}</template><script>${jsCont}</script><style scoped>${cssCont}</style>
其中 jsCont
我们需要把从 js 文件中取到的内容进行修改,因为在 UI 层,是不需要执行业务代码的,比如时间方法的,这些调用都会通知到logic层中去。
jsCont = jsCont.replace(/^export default[\s]+\{/, `export default Component({route:'${compPath}'}, {`) + ')'
上面看到,主要是套了一个函数 Component
包裹起来,该函数在page.html中是全局的,主要对传入vue的options进行重写,把所有可能会被调用的methods和生命周期进行重写,改成通知logic层,我们在UI层解析会讲到。
function handleMethod(name) {
ret.methods[name] = function(e) {
postMessageToLogic(
{
cmd: COMPONENT_EVENT,
methodName: name,
handleEvent: createHandleEvent(e)
},
this._uid,
pid
)
}
}
还有把 props
和 computed
监控起来,在他们变化时也通知到logic层。
function handleWatch(name) {
// 深度监听
ret.watch[name] = {
handler(newValue, oldVal) {
postMessageToLogic(
{
cmd: COMPONENT_WATCH_DATA_CHANGE,
name,
newValue
},
this._uid,
pid
)
},
deep: true
}
}
logic层
logic层我们准备一个入口文件,使用了 require.context()
把所有页面和组件js全部引入。
const pageCtx = require.context('../src/pages', true, /\.js$/)
const compCtx = require.context('../src/components', true, /\.js$/)
...
前面说到,小程序的安全是非常重要的,而Web技术太开放了,所以logic层开发者运行的代码则需要放到一个安全的沙箱去运行。实现方式也比较简单,把代码放到一个作用域中,里面把可能会产生安全问题的 window
、location
、dom
等屏蔽掉。
在webpack编译emit
阶段,修改 logic 代码
if (name === 'logic.js') {
const newOutput = `(function(window,document,history,localStorage,location,parent,frames,frameElement){${compilation.assets[
name
].source()}})()`
compilation.assets[name] = {
source() {
return newOutput
},
size() {
return this.source().length
}
}
}
PS:由于需要支持 webpack-dev-server
来实现实时更新,目前方案废弃了 vue-loader
,自行写了一个 loader 来对 html css js 进行合并操作,如果对源码感兴趣,详见 fox2app-loader