近一个月里和同事一起将刚接手系统从sea.js切换到require.js。一方面感觉requirej比seajs更容易做工程化,一方面sea.js目前不更新了,而require社区仍然比较活跃。没有直接上vue或者react之类新潮的框架,是考虑到目前系统功能已经相对稳定了,业务复杂,组件数量很多,伤筋动骨的换框架一方面时间有限,一方面项目没有做单元测试,风险太大,后面新项目起来的话应该是会直接上react了。sea切换到require的改动相对来说比较固定,可以完全不动原有业务代码,工作量和风险可控。
不过个人其实对requirejs本身不太了解,期间还是掉进了几个坑里的。先总结下在切换到requirejs中遇到的两个问题吧。
1.requirejs不像seajs要求js文件被define、require包裹,可以直接require一个不符合规范的js
module1:
(function(){
window.myModule1 = {
info:'module1'
}
})();
module2:
(function(){
if(window.myModule1){
console.log(window.myModule1.info);
}
})();
main:
require(['./module1', './module2'], function(){
...
})
以上代码完全可以正常运行,不会报错。但会发现一个问题,多次执行的结果会不一致,这是因为module1和module2不是按照require数组参数里的顺序加载的,这种情况下没有固定的加载顺序。
有两种处理方式:
如果两个js都是业务代码可以自行维护,就把两个js都改成AMD规范
module1:
define('module1', function(){
window.myModule1 = {
info:'module1'
}
});
module2:
require(['module1'], function(){
console.log(window.myModule1.info);
})
main:
require(['./module2'], function(){
...
})
如果js是外部插件,尽量用不改源码的方式让两个js的加载变得有序。需要在require的config.js配置文件中加入一段代码,让requirejs知道两个js之间的依赖关系,保证module2在module1加载后再加载
requirejs.config({
paths: {
"module1": "./module1",
"module2": "./module2"
},
shim:{
"module2": ["module1"]
}
})
2.require返回的对象全局共享一个。
module1:
define('module1', [], function(){
return {
val : 0,
init : function(){
return this;
},
add : function(num){
this.val += num;
}
};
});
main:
require(['module1'], function(m){
m.init().add(1);
console.log(m.val); //1
});
require(['module1'], function(m){
m.init().add(1);
console.log(m.val); //2
});
以上例子说明,module1第一次被require以后,返回的对象m会被缓存起来,第二次被require的时候,返回的是之前缓存起来的m。多次require同一个模块时,返回的对象实际上是同一个。这与seajs是不同的,seajs每次异步加载都会返回一个,以前基于seajs写的代码里切换成require以后就会留下潜在的坑。
解决方法简单粗暴,所有返回对象的地方全换成返回function,执行function返回原对象。
module1:
define('module1', [], function(){
return function(){
return {
val : 0,
init : function(){
return this;
},
add : function(num){
this.val += num;
}
}
};
});
main:
require(['module1'], function(m){
m().init().add(1);
console.log(m.val); //1
});
require(['module1'], function(m){
m().init().add(1);
console.log(m.val); //1
});
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。