最近的项目需要兼容到IE9,所以在打完包之后,在虚拟机里使用IE9调试,发现个别页面会有报错:“Promise”未定义
。
很奇怪,因为这几个页面比较简单,代码就几十行,也根本没有用到promise。当时考虑到时间紧迫,就没有仔细想,匆匆忙忙地打了个babel-polyfill
上去,补上了promise,把这个问题盖过去了。
同时,有一个比较在意的问题,就是打包的时候,出现一些0/1/2/3.js
的文件。
从log来看,包含的内容是那几个页面用到的插件。
由于只有那么几个文件,并且不是所有公共模块都打包,所以并不是webpack提取出来的公共模块。所以……搜一下文档看看吧。
1、非入口(non-entry chunk)文件
在查找CommonsChunkPlugin
这个插件的用法的时候,偶然看到output
里有个字段是chunkfilename
,试着改一下看看:chunkFilename: "js/[id].chunk.js"
,运行,之前的0.js
变成了0.chunk.js
。
官方文档里面说,这个选项决定非入口(non-entry chunk)文件的名字,那么这些0/1/2/3.js就是这里所说的“非入口文件”了。
什么时候会产生非入口文件?
简单说,当使用了动态载入(dynamic importing)方式引用模块,使这些部分被分割(代码分割)出来,供按需加载使用。
同时,如果不指定名字,分割出来的代码会按0.js/1.js/2.js...
这样命名。这些名字的指定位置,在output.chunkfilename
这里配置,所以,如果你配置了chunkFilename:"js/[id].chunk.js"
,即会按0.chunk.js/1.chunk.js...
这样的格式命名。至于何时引用,由webpack负责,不用显式调用。
2、动态引入(Dynamic Imports)
这里 有动态引入的介绍。
一般,import * as someModule from './dir/someModule.js'
形式引入的模块都是静态(static)的,只能放在文件顶部,也就是说,不能被if条件或事件处理函数包裹来达到按需引入的目的。但是可以用import(moduleName)来达到动态引入的目的
import('./dialogBox.js') .then(someModule => someModule.foo());
所以,用import()
的语法,可以解决按需引入、分状态引入、加入符号计算等情况。webpack有对这部分的支持说明。
3、require(String)
和require([])
的区别
意外的,发现了IE一直报错的原因
查找js文件,确实发现几处这样的写法
require(["./plugins/jqueryColor", "./plugins/jqueryValidata/message_CN", "./plugins/jqueryValidata/jquery.validate.min"]);
虽然没有使用require.ensure
,但是使用了require(['./dir/module1','./dir/module2'])
的语法,同require(String)
虽然写法一样,但是意思却是不一样的。
require(String)
require是CommonJS支持的格式,也是Node支持的引入语法,该方法是同步的,格式如下
var $ = require("jquery"); var myModule = require("my-module");
require([])
有点疑问,这个应该是RequireJS的语法,因为写的并不是require.ensure
。但在本地使用的webpack里是支持的,能找到的一点资料在这里。
require([])
是AMD语法,webpack相关的介绍在 这里。语法在需要的时候才下载依赖的模块,值得注意的是,该语法异步的。
require(dependencies: String[], [callback: function(...)])
require.ensure
是commonJS的语法,和require([])
语法基本类似,不同点在于,require.ensure
可以通过option
来指定chunk名字,但是require([])
只能遵循webpack配置文件默认的命名规则。
require.ensure(dependencies: String[], callback: function([require]), [chunkName: String])
将代码里require的数组分别用require
(或者import
)分开,再次编译,发现0/1/2/3.js
文件都消失了。并且在IE9调试,不再出现“Promise”未定义
的错误。
4、该使用require还是import?
require
是CommonJS的规范,是Node支持的语法。在ES6之前,所有的模块化使用的都是require
语法,不管是node(CommonJS)、requireJsJ还是seajs。
而import
是ES6的语法,但是ES6目前还没有普及。关于二者的关系,可以看这里。
引用上文中的结论:在目前阶段,二者没有本质区别,我们会使用babel来支持ES6,但是babel也是将ES6转码为ES5再执行,import
语法会被转码为require
。这也是为什么在模块导出时使用module.exports,在引入模块时使用import仍然起效,因为本质上,import
会被转码为require
去执行。