最近把一個比較舊的業餘項目從新升級了下,將主文件進行了剝離,增長了些惰性加載的配置,將過程當中一些零散的知識點作個總結,同時儘可能深刻原理實現層面。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查看
先搞這些,依賴包升級乃至換個環境重寫等下次再有閒情哈!!