由一个模块混用报错引出的模块化再思考
某日,工位上,小程序前端开发同学小明
收到需求:
需要开发一个函数,函数里面使用的是另外团队开发的一个功能,最后需要把这个函数对外暴露出去。
“这还不简单么,分分钟搞定!”小明心理想,但是还是评了1个小时的开发时间。
说搞就搞,撸起袖子,刷刷刷,小明的代码就写好了:
想一想这么简单的业务功能,也没啥循环引用存在的,
然后require还是得依赖第三方commonjs库,就用JS原生支持的模块规则吧
ES6的导入导出的多种形式,想到后续可能会有更多能力函数,那就挑一种非default的吧。
于是,代码就这样了:
// 具体的业务文件do.js中
function do(){
getApp().xxx // 此处引用了其他团队的一个函数
console.log('done')
}
export { do }
// 小明负责的模板对外的入口文件 index.js 中
import { do } from './do.js'
const A = require('./A')
const B = require('./B')
const C = require('./C')
class XiaoMing {
constructor(){
this.do = do
this.A = A
this.B = B
this.C = C
// xxx
}
// xxx
}
module.exports = XiaoMing
// A B C 模块是长这样的
class A {}
module.exports = new A()
class B {}
module.exports = new B()
class C {}
module.exports = new C()
为了验证自己写的代码,小明还专门写了一份测试代码。
新建了一个测试小程序项目,把自己的代码加了进去,一行测试代码,进行测试
cosnt sdk = new XiaoMing()
sdk.do() // 成功执行了业务方代码,并最终输出了done
看到代码成功的输出了字符串do,小明不禁露出了欣慰的笑容。
搞定!
开发、测试、代码提交,合并,推送,交付~
通知相关同学可以用了~
殊不知,一个小坑,就这么埋下了。。。
其他同学用了一阵子,华丽丽的报错就找到小明了…
反馈的报错是:
“Uncaught TypeError: Cannot assign to read only property 'exports' of object '#<Object>'”
原来是小明开发的代码,在某个使用场景中,还会被webpack打包后使用。。
而webpack其实是有一个规矩的:在js文件中混用 require 和 export是可以的,但是不能混用 import 以及 module.exports,混用了,就是上面那个报错~
而小程序本身如果开启了ES6 转 ES5的话,是可以混用的,想必是小程序本身内部的转换起到了作用。
这也是小明直接使用小程序原生项目测试自己的代码所没有覆盖到的点
自己挖的坑,含泪也要填好的。
解决方案:
统一整体的导入导出方式,既然一直用require,那就require。require对node也是友好的
小明又花了10分钟,把之前新增的模块的导入导出方式,改成了require
流程再来一遍,又是一通操作
开发、测试、代码提交,合并,推送,交付~ 对已经在坑中的同学的脱坑处理~
提出问题:
其他那么多第三方库,怎么可能统一规范,似乎各种导入导出是可以混用的啊
跟项目打包之后的生成js的规范有关,如果是使用 babel 转换 es6 模块,混合使用 es6 的模块和 commonjs 的规范是没有问题的,因为最终都会转换成 commonjs。主要看统一规范的这一步是在哪个环节做的。
es6 + webpack + babel 的解决方案 transform-es2015-modules-commonjs 了解一下
时间紧迫,待研究…
导入导出技术总结:
导入:require 、 import
导出:exports 、module.exports 、export
NodeJs: 不支持 import 、export
webpack不能在一个js文件中混用 import 以及 module.exports
如果不想被webpack困扰,那就整个项目手动处理成全部是导入用require, 导出用module.exports
整体总结:
站在前人的肩膀上,大胆创新是要的,需要全盘考虑代码生存环境,评估风险
对技术的总结要定期回顾以加深记忆