libraryTarget的几种选择我们来好好分析
好久没写库了,发现时代变了
这一切的起因都是因为那只pm,整个一个奇奇怪怪的需求,然后发现需要写库了,就在我流利的初始化项目时,突然脑抽风的发现,library配置貌似不太对,libraryTarget配置貌似也不太对,所以还是停下来吧,好好分析回顾一下,阿西吧。
先来回顾一下,library是指定义一个全局使用的名称变量,libraryTarget是指设置library的暴露方式,是commonjs、commonjs2、umd还是this、var等。
变量定义:
- libraryTarget:“assign”,暴露一个未定义的library设置的变量。在node环境不支持。
- libraryTarget:“var”,暴露一个用var 定义的library设置的变量。在node环境下不支持。
这两个属性,都是在全局创建一个变量,只有定义与未定义的区别,并且并不能在nodejs中得的支持,并且存在变量冲突的可能性。

观察一下libraryTarget:“assign” or “var”产出的代码,只是创建了一个library里设置的变量,然后通过webpack的方法做一个导出。
对象定义:
- libraryTarget:“window”,在window对象上定一个library设置的变量。在node环境下不支持。
- libraryTarget:“global”,在global对象上定义一个library设置的变量。受target属性影响,当target为默认值web时,会在window上注册,如果你想在global上注册,必须修改target为node。
- libraryTarget:“this”,在当前this对象上定义一个library设置的变量,如果this是window,就在window。在node的环境中,如果没指定require赋值的变量,并不会在指向global。
这三个属性的特征都是在公共对象上export出你的方法函数。特点无非是减少了变量冲突的可能性,但是依旧没有解决问题,只有global模式支持在node环境中,还必须设置target为node不然也是不支持的。

观察一下libraryTarget:“window” or “global” or “this”产出的代码,在相应的libraryTarget设置的对象上,创建一个library设置的变量,然后根据webpack的方法做一个导出。global有一个注意点,那就是target配置。如果没有写那默认是在window对象上注册。

模块定义
- libraryTarget:“commonjs”,在export对象上定义library设置的变量。在node中支持,浏览器中不支持。
- libraryTarget:“commonjs2”,直接用module.export导出export,会忽略library设置的变量。在node中支持,在浏览器中不支持。
- libraryTarget:“amd”,在define方法上定义library设置的变量,不能用script直接引用,必须通过第三方模块RequireJS来时用
这两个属性,是符合模块化规范的产物,commonjs是在export上定义library设置的变量,commonjs2是用module.export直接export的。amd的依赖前置方案在浏览器、node中都必须额外引入RequireJS来使用。

commonjs/commonjs2,查看源码的话,commonjs是在exports中创建一个library设置的变量,而commonjs2是直接把方法export到module.exports中,这就是为什么commonjs2会忽略library的原因。

amd那就是在define的方法中设置了library,这样就能符合RequireJS的使用规范。
兼容的模块化定义
- libraryTarget:“umd”,该方案支持commonjs、commonjs2、amd,可以在浏览器、node中通用。
但是如果你想做到这一点,必须要额外设置,umdNamedDefine: true,globalObject: ‘this’,umdNamedDefine为设置amd前置名称使用library设置的变量,globalObject为改变全局指向。这样就能保证你的库在node和浏览器中通用了。当然便捷的引入一定会带来一定的冗余,这就看你如何取舍了。

umd的核心无法是webpackUniversalModuleDefinition中的判断,这里会做环境判断,去使其能够使用,这里有必要注意两个关注点,那就是window对象,这个对象在node中是无法使用的,并且会报错。而且define([var])的var为空值这也会在RequireJS中报错。如果你需要在node、RequireJS中使用,那么就需要额外配置umdNamedDefine、globalObject了。


这样,你的define和window就符合要求了。
最后建议,如果目标明确,我只是兼容nodejs,那么选择commonjs/commonjs2,如果只兼容浏览器,那就选择暴露变量的方式,如果想通用,那就选择umd的方式,对于不同的情况做多种处理方式,是非常明智的选择。
最后附上表格一张,仅供参考。
