随着微盟业务的拓展,我们在产品形态上允许商户使用不同的业务模块动态生成一种解决方案。这时我们就需要去解决不同的业务模块开发团队所面临的协作问题。
一般情况下,我们在多个团队协作开发小程序过程中,如果某个团队的模块对全局的JS变量进行了修改,比如:wx、Page、App等,都会影响到其它模块,甚至出现一些莫名其妙的bug。所以为避免某个模块对全局的修改影响到其它模块,我们希望在使用其它团队的模块时,对该模块进行一个沙箱化(Sandbox)处理,让其对全局的修改只会在该模块下有效。
通常的一些解决方案比如在H5中使用 +、借助,在中使用 / 等方式去实现代码环境隔离,但是在小程序中这些方式都不可用。
故我们通过在编译时,在代码中插入沙箱代码实现环境隔离,以下是实现的2个思路:
比如原始代码为:
转换后代码:
说明: 是提前挂在 上的一个方法, 用于获取每个模块的的环境变量, 返回值是一个数组, 数组元素顺序与注入局部环境变量顺序一致, 伪代码如下:
优点: 实现简单, 只需对模块内的每个js文件都包装一下这个外壳就好.
缺点:
- 如果模块内某块代码对全局变量进行赋值操作, 如下:
这种用法将无效, 无法影响到同模块内其他JS文件.
- 如果某个js代码中写了如下代码:
经过一层代码包裹之后, 运行时将会报的错误
说明:
1. 判断是否需要被局部化
使用 判断是否需要被替换
2. 判断是否被引用的标识符
使用
3. 判断是否是赋值操作
使用
举例:
4. 判断是否是赋默认值操作
使用
举例:
5. 判断是否是数组结构赋值
使用
举例:
6. 没有定义过该名称
使用
举例:
在节点的阶段中判断是否进行过上面的代码替换操作,如果是则在顶部插入一句
最终转换效果如下:
原代码为:
转换后代码为:
说明: 是提前挂在 上的一个方法, 用于获取每个模块的的环境变量, 返回值是一个对象, 对象中包含所有需要进行隔离的变量, 伪代码如下:
优点:模块内的任何修改都仅作用于该模块内,并且没有的缺点,实现了我们想要的效果,并且可以自定义注入全局API,不用挂到或下
缺点:实现较为复杂,需要接入Babel。
对于每个模块的本地存储也需要进行隔离,可以在的基础上,在中对相关API进行包装,给加上模块名称,这样每个模块的本地存储也不会被相关影响了。
同时一些全局的公共需要加白名单功能(比如:存用户信息的),避免模块内读取不到公共的本地存储数据