最近把一个比较旧的业余项目从新升级了下,将主文件进行了剥离,增长了些惰性加载的配置,将过程当中一些零散的知识点作个总结,同时尽可能深刻原理实现层面。javascript
项目环境:html
前端框架:angular2.0.0-beta.21前端
构建工具:webpack4.11.0java
加载惰性模块:node
跑了下环境,再次验证了每次回头看之前本身写的东东的时候都会不能忍这一潜在的法则,发现首屏的加载事件居然超过了1s,因而果断切割主资源包,进行按需加载webpack
若是使用angular-cli命令工具,该需求基本自动化实现,只须要在对应的路由下配置须要懒加载的模块便可,其余工做如模块的异步加载等,cli会进行自动处理,以下所示git
const routes: Routes = [ { path: 'customers', loadChildren: './customers/customers.module#CustomersModule' } ];
可是一直偏向于本身构建脚手架,不喜欢拿来即用,看了下angular-cli的源码,其实也是基于webpack构建(部分配置以下),只是没看到其中异步加载模块和output输出中模块语义化的实现过程。只能本身实现模块的异步加载,解决“can not find module...”报错。es6
{ resolve: { extensions: ['.ts', '.js'], symlinks: !buildOptions.preserveSymlinks, modules: [appRoot, 'node_modules'], alias }, resolveLoader: { modules: loaderNodeModules }, context: projectRoot, entry: entryPoints, output: { path: path.resolve(buildOptions.outputPath), publicPath: buildOptions.deployUrl, filename: `[name].bundle.js`, chunkFilename: `[id]${hashFormat.chunk}.chunk.js` }, module: { rules: [ { test: /\.html$/, loader: 'raw-loader' }, { test: /\.(eot|svg|cur)$/, loader: 'file-loader', options: { name: `[name]${hashFormat.file}.[ext]`, limit: 10000 } }, { test: /\.(jpg|png|webp|gif|otf|ttf|woff|woff2|ani)$/, loader: 'url-loader', options: { name: `[name]${hashFormat.file}.[ext]`, limit: 10000 } } ].concat(extraRules) }, plugins: [ new webpack.NoEmitOnErrorsPlugin() ].concat(extraPlugins) }
查阅webpack文档,找到一个内置的ensure方法可实现模块异步,使用以下github
require.ensure(dependencies: String[], callback: function(require), errorCallback: function(error), chunkName: String)
dependencies:字符串构成的数组,声明 callback 回调函数中所需的全部模块。web
callback:只要加载好所有依赖,webpack 就会执行此函数。require 函数的实现,做为参数传入此函数。当程序运行须要依赖时,可使用 require() 来加载依赖。函数体可使用此参数,来进一步执行 require() 模块
errorCallback:当 webpack 加载依赖失败时,会执行此函数。
chunkName:由 require.ensure() 建立出的 chunk 的名字。经过将同一个 chunkName 传递给不一样的 require.ensure() 调用,咱们能够将它们的代码合并到一个单独的 chunk 中,从而只产生一个浏览器必须加载的 bundle
将方法应用到路由模块,代码以下:
export const routes: Routes = [ { path: 'course', loadChildren: () => new Promise(resolve => { (require as any).ensure( [], require => { resolve(require('../course/module').CourseModule); }, 'haha' ); }) } ];
该方法基于浏览器内置promise对象,若是须要兼容多种环境,最好增长polyfill库来填充promise环境
最后
若是不想在路由模块写异步方法,也能够引入一些封装好的插件实现,如es6-promise-loader、angular2-load-children-loader,但其实也没有本质的变化,只不过稍作封装而已,意义不大,具体usage可github查看
先搞这些,依赖包升级乃至换个环境重写等下次再有闲情哈!!