當網站規模越來越大,通過webpack 打包后的 react 項目也會越來越大,這會導致首頁渲染時間變長,影響用戶體驗,webpack 提供了一種按需加載的方式,需要結合 react-router 使用,他會將代碼拆分成多個小包,需要哪個部分就加載響應的包。
首先需要對 config 文件修改一下,如下
output: { path: path.join(__dirname, 'dev'), // 輸出路徑 filename: '/js/bundle.js', // 輸出文件名 publicPath: path.join(__dirname, 'dev'), // 必填項 chunkFilename : '/js/routes/[name].chunk.js?[chunkhash:10]', // 按需加載輸出的文件名 },app/js/routes.js
)react 按需加載,關鍵是讓路由動態加載組件,react-router 提供了一個屬性 getComponent
,它與 component
屬性一樣,但是是異步的,當路由匹配時才會調用這個方法,常用于代碼分割; 相關內容查看 API文檔
webpack 為我們提供了一個按需加載函數 require.ensure(dependencies, callback, chunkName)
,
更多了解,查看官方文檔
注意:cb(null, require('./containers/Login.js').default)
因為我用 es6 的 export default
導出的組件,所以 require 之后要加上 default
,如果使用 module.export
導出組件 則不需要加 default
以上寫法在 路由層級或者數量較多的時候會比較臃腫,所以還需要對路由進行拆分
路由拆分,需要對目錄結構做一下改變,在js 文件夾下添加 routes 路由配置文件夾
|---js | |---actions | | | |---components | | | |---containers | | | |---reducers | | | |---store | | | |---routes | | |---login.js // 主路由的下一級路由 | | |---login // login 路由的下一級路由目錄 | |---constants.js // 靜態常量 | |---index.js // 項目入口文件 | |---routes.js // 路由配置主文件 |routes.js 路由配置的主文件
const routes = { path : '/', // 將匹配的路由,對應標簽中的 path 屬性 indexRoute: { // 設置默認顯示頁面,對應標簽中的 IndexRoute 組件 getComponent(nextState, cb) { require.ensure([], (require) => { cb(null, require('./containers/Login').default); }, 'Login'); } }, // childRoutes:[] // 子 route 的一個數組,與在 JSX route 配置中的 children 一樣。 getChildRoutes(partialNextState, cb) { // 與 childRoutes 一樣,但是是異步的,并且可以接收 partialNextState(location 信息) require.ensure([], (require) => { cb(null, [ require('./routes/login'), require('./routes/home'), require('./routes/error') ]) }) }, getComponent(nextState, cb) { // 定義對應的組件,對應標簽中的 component 屬性,但是是異步的,路由匹配時才會調用這個方法 require.ensure([], (require) => { // require.ensure : webpack 提供的按需加載方法 cb(null, require('./containers/App').default); }, 'App'); } } export default routes;js/routes/home.js 路由分支
module.exports = { path: 'home', getChildRoutes(partialNextState, cb) { require.ensure([], (require) => { cb(null, [ require('./home/page'), require('./home/student'), require('./home/admin') ]) }) }, getComponent(nextState, cb) { require.ensure([], (require) => { cb(null, require('../containers/Home').default) }, 'Home') } }基本思路 : 每當指定路由要發生改變,就使用一個中間服務,介于上一級路由和將要到達路由之間啟動,來判斷我們是否有進入這個路由的權限,React 中的 <Route />
提供了一個 onEnter
方法,表示正要進入這個路由,在這里判斷進入權限,可以修改要進入的頁面
注:nextState : 表示跳轉后的location 信息;replace 用于 更改下一個進入的頁面地址,但是不會跳轉;next : 用于跳轉頁面,沒有其他操作則顯示當前路由對應頁面
如果使用路由拆分,如下
module.exports = { path: 'home', getChildRoutes(partialNextState, cb) { require.ensure([], (require) => { cb(null, [ require('./home/page'), require('./home/student'), require('./home/admin') ]) }) }, getComponent(nextState, cb) { require.ensure([], (require) => { cb(null, require('../containers/Home').default) }, 'Home') }, onEnter: (nextState, replace, next) => { console.log(nextState.location.state); let isAuth = nextState.location.state.isAuth; if (isAuth === 'student' || isAuth === 'teacher' || isAuth === 'admin') { next(); } else { replace('/error'); next(); } } }新聞熱點
疑難解答