package.json中的main字段指向的是Library的入口,通常有3个选择:

1.指向源代码入口文件,如src/index.js;
2.指向打包后的开发版本,如dist/library.js;
3.指向打包后的发布版本,如dist/library.min.js

引用Library的方式也分为两种:

1.通过script标签直接引用,适用于简单页面;
2.通过require或import方式引用,需要借助打包工具打包,适用于复杂页面。

本文探讨一下main字段如何指定,才能兼顾各种引用方式。

指向源代码入口文件

第一种方式指向源码入口,这种情况仅适用于require方式引用。由于指向的是源代码,需要库使用者借助打包工具如webpack,自行对库进行打包。此方式存在以下问题:

1.webpack配置babel-loader一般会排除node_modules,意味着不会对library进行转译,可能会导致打包后的代码中包含ES6代码,造成低版本浏览器兼容问题;
2.如果library的编译需要一些特别的loader或loader配置,使用者需要在自己的配置中加上这些配置,否则会造成编译失败;
3.使用者的打包工具需要收集library的依赖,造成打包编译速度慢,影响开发体验。

总的来说,第一种方式需要使用者自行对library进行编译打包,对使用者造成额外的负担,因此源代码入口文件不适宜作为库的入口。但是,如果library的目标运行环境只是node端,由于node端不需要对源代码进行编译打包,所以这种情况下可以使用src/index.js作为库入口。

指向打包后的开发版本

开发版本的主要作用是便于调试,文件体积并不是开发版本所关心的问题,这是因为开发版本通常是托管在localhost上,文件大小基本没影响。

开发版本主要通过以下手段来方便调试,提升开发体验:

1.预先进行依赖收集和babel转译,即使用者不再需要对library进行这两步工作了,提高编译打包的效率;
2.尽量保留源代码的格式,保证开发版本里面的源代码基本可读;
3.保留警告信息,对开发者对库的错误或不合理调用进行提示。

其中第3点是通过库代码中添加如下类似代码实现的:

1
2
3
if (process.env.NODE_ENV === 'development') {
console.warn('Some useful warnings.')
}

生成开发版本的似乎,webpack的DefinePlugin会将process.env.NODE_ENV替换为development,所以以上代码变为:

1
2
3
if ('development' === 'development') {
console.warn('Some useful warnings.')
}

这就表示上述条件一直成立,warning信息会显示出来。

最近和iview的开发者争论一件事,即在生成library的开发版本的时候,NODE_ENV应该设置为development还是production。他们认为应该设置为production,理由是可以减小开发版本的体积。假设DefinePlugin将process.env.NODE_ENV替换为production,之前的示例代码会变为:

1
2
3
if ('production' === 'development') {
console.warn('Some useful warnings.')
}

这就意味着你使用库开发应用时,不会看到任何警告信息,这不利于提前发现错误。可能有的人会说,我的源代码中没有if (process.env.NODE_ENV === 'development') {}这类代码,所以设置为production也不会有任何问题呀。殊不知,虽然你的源代码中这种没有这类提示代码,但是你的devependencies里面可能会有啊,这样做就会关闭依赖中的warning信息。

可能又有疑问:“引用开发版本的包体积很大,岂不是让我的应用打包上线版本很大?”其实完全不用担心,因为应用打包为上线版本时,会经过两个额外的工作:

1.使用DefinePlugin将process.env.NODE_ENV替换为production,关闭所有警告信息;
2.使用UglifyJsPlugin对应用代码进行minify,减小应用体积。同时会删除if ('production' === 'development') {}这类永远不会执行的代码,进一步减小应用体积。

所以,在开发时应用开发版本,不必担心最后的应用体积。但是如果开发时是以script标签的方式引用库的开发版本,上线时应该替换为响应的发布版本。

指向打包后的发布版本

发布版本追求的是尽量减小体积,因为相比于JS引擎解析的时间,网络传输是最慢的,所以要通过减小库的体积,减少网络传输的时间。

减小发布版本的文件体积,主要是通过将process.env.NODE_ENV设置为production,然后再使用UglifyJsPlugin对应用代码进行minify以及删除永不执行的代码。

那么将库的发布版本作为入口文件合不合适呢?显然不合适,因为发布版本的是经过高度压缩精简的,代码完全不可读,应用开发阶段难以调试。

发布版本是适用于在应用上线时,通过script标签形式引用。

结论

通过上面的分析,可以发现将库的开发版本作为库的入口才是正确合理的做法,即设置"main": "dist/library.js"。而作为库的开发者,也要遵循约定,生成库的开发版本的时候,使用development环境变量,保留警告信息。