/ webpack

code splitting with webpack2 and react-router

当你用React全家桶(React, React-DOM, Webpack)做一个网站时,会发现最后打包后的文件相当大,这当然取决于你网站的规模,因为一个小网站可能应用代码都不会超过引用的库的大小。

由于最新版Webpack2已经支持了ES6的import,让开发者感觉爽了许多,无需混用requireimport ... from ...,当从gulp转换到webpack后感觉就是开发时间极大缩短,主要是修改应用代码后调试效果时间缩短,原先gulp编译一遍需要20秒,webpack只需要1~2秒,虽是这样,但最终打包结果大小都差不多。

于是有了code splitting,配合react-router就是当你访问某个location时,只下载需要的那部分代码,这显然比下载所有代码快得多,做到这,基本上优化也到头了。

配合react-router做code splitting需要在<Route>中做些修改,例如原先代码可能是这样:

现在需要修改成异步加载components:

现在webpack已经足够聪明,可以读懂System.import,最终会打包成一堆类似[id]-[chunkhash].js的文件,当你访问某个location时,会自动加载这个文件。

需要注意:

  • react-router使用Promise完成异步加载,如果你无法保证用户浏览器都支持Promise,最好使用promise polyfillhttps://github.com/stefanpenner/es6-promise
  • 当你的component写了export default时,比如export default Index,那么你应该写System.import('./Index').then(c => c.default)而不是c.Index,否则会发现这个component只有initial rendering而没有后续rendering
  • react-router文档中有个getIndexRoute,目前来看这个方法针对非JSX配置使用,如果你把它当作<Route>的属性,可能得不到期望效果。应该使用<IndexRoute getComponent={xxx}/>
  • 当你需要import多个component时,可能你会用Promise.all(['com1', 'com2'].map(x => System.import(x)).then(([c1, c2]) => ({a: c1.default, b: c2.default})),很可惜webpack支持得并不好,有一个workaround方法,新建一个component(或者应该算是js的module),在里面import好需要的components,再export出去,这样就可以改写成直接System.import形式,具体可以看这里:https://github.com/webpack/webpack.js.org/issues/275

注意配置:

webpack中vendor entry配置:Object.keys(pkg.dependencies)

CommonsChunkPlugin配置:

manifest可以使vendor不会因为build而改变,这样每次改动代码会让每个异步加载的chunk file修改,响应的,manifest也会修改,所以inline了manifest到html中,每次都会获取最新的manifest,加载最新的chunk file。