當(dāng)網(wǎng)站規(guī)模越來越大,通過webpack 打包后的 react 項目也會越來越大,這會導(dǎo)致首頁渲染時間變長,影響用戶體驗,webpack 提供了一種按需加載的方式,需要結(jié)合 react-router 使用,他會將代碼拆分成多個小包,需要哪個部分就加載響應(yīng)的包。
首先需要對 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 按需加載,關(guān)鍵是讓路由動態(tài)加載組件,react-router 提供了一個屬性 getComponent
,它與 component
屬性一樣,但是是異步的,當(dāng)路由匹配時才會調(diào)用這個方法,常用于代碼分割; 相關(guān)內(nèi)容查看 API文檔
webpack 為我們提供了一個按需加載函數(shù) require.ensure(dependencies, callback, chunkName)
,
更多了解,查看官方文檔
注意:cb(null, require('./containers/Login.js').default)
因為我用 es6 的 export default
導(dǎo)出的組件,所以 require 之后要加上 default
,如果使用 module.export
導(dǎo)出組件 則不需要加 default
以上寫法在 路由層級或者數(shù)量較多的時候會比較臃腫,所以還需要對路由進(jìn)行拆分
路由拆分,需要對目錄結(jié)構(gòu)做一下改變,在js 文件夾下添加 routes 路由配置文件夾
|---js | |---actions | | | |---components | | | |---containers | | | |---reducers | | | |---store | | | |---routes | | |---login.js // 主路由的下一級路由 | | |---login // login 路由的下一級路由目錄 | |---constants.js // 靜態(tài)常量 | |---index.js // 項目入口文件 | |---routes.js // 路由配置主文件 |routes.js 路由配置的主文件
const routes = { path : '/', // 將匹配的路由,對應(yīng)標(biāo)簽中的 path 屬性 indexRoute: { // 設(shè)置默認(rèn)顯示頁面,對應(yīng)標(biāo)簽中的 IndexRoute 組件 getComponent(nextState, cb) { require.ensure([], (require) => { cb(null, require('./containers/Login').default); }, 'Login'); } }, // childRoutes:[] // 子 route 的一個數(shù)組,與在 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) { // 定義對應(yīng)的組件,對應(yīng)標(biāo)簽中的 component 屬性,但是是異步的,路由匹配時才會調(diào)用這個方法 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') } }基本思路 : 每當(dāng)指定路由要發(fā)生改變,就使用一個中間服務(wù),介于上一級路由和將要到達(dá)路由之間啟動,來判斷我們是否有進(jìn)入這個路由的權(quán)限,React 中的 <Route />
提供了一個 onEnter
方法,表示正要進(jìn)入這個路由,在這里判斷進(jìn)入權(quán)限,可以修改要進(jìn)入的頁面
注:nextState : 表示跳轉(zhuǎn)后的location 信息;replace 用于 更改下一個進(jìn)入的頁面地址,但是不會跳轉(zhuǎn);next : 用于跳轉(zhuǎn)頁面,沒有其他操作則顯示當(dāng)前路由對應(yīng)頁面
如果使用路由拆分,如下
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(); } } }新聞熱點(diǎn)
疑難解答