本文介绍基于 React Router 2.8.1 与 Webpack 的按需加载方案。通过配置 output.chunkFilename 生成独立 Chunk,利用 getComponent 异步加载组件,并结合 require.ensure 实现代码拆分。文章详细演示了根路由、子路由及重定向路由的拆分配置方法,帮助优化大型应用的首屏加载性能。
React Router 按需加载概述
本文基于 React Router 2.8.1 版本进行讲解。
React Router 内置了按需加载机制,通过将代码拆分为多个独立小包,在用户浏览过程中动态加载所需资源。
Webpack 配置 chunkFilename
若项目使用 Webpack 进行打包,需在 webpack.config.js 的 output 配置中添加 chunkFilename 字段。
output: {
path: path.join(__dirname, '/../dist/assets'),
filename: 'app.js',
publicPath: defaultSettings.publicPath,
// 添加 chunkFilename
chunkFilename: '[name].[chunkhash:5].chunk.js',
},
name 参数用于指定生成 Chunk 的名称;若代码中未显式指定,Webpack 将默认使用 ID 作为名称。
chunkhash 代表文件的哈希值,由于哈希值较长,此处仅截取前五位。
根路由与 getComponent 配置
为实现路由组件的动态加载,需将 component 属性替换为 getComponent。首先拆分路由结构,创建根路由 rootRoute:
const rootRoute = {
path: '/',
indexRoute: {
getComponent(nextState, cb) {
require.ensure([], (require) => {
cb(null, require('components/layer/HomePage'))
}, 'HomePage')
},
},
getComponent(nextState, cb) {
require.ensure([], (require) => {
cb(null, require('components/Main'))
}, 'Main')
},
childRoutes: [
require('./routes/baidu'),
require('./routes/404'),
require('./routes/redirect')
]
}
ReactDOM.render(
(
<Router
history={browserHistory}
routes={rootRoute}
/>
), document.getElementById('root')
);
该配置包含以下四个主要属性:
path
用于匹配路由路径,此处不再赘述。
getComponent
对应旧版中的 component 属性,但该方法为异步执行。仅当路由匹配成功时,才会调用此方法加载组件。
该方法内部使用了 require.ensure 方法。
require.ensure(dependencies, callback, chunkName)
这是 Webpack 提供的核心按需加载方法。其第一个参数为依赖列表,第二个参数为回调函数,第三个参数为前述的 chunkName,用于指定生成的 Chunk 文件名。
indexRoute
用于定义主页路由(此处将主页单独抽离)。
注意 indexRoute 的写法,它是一个对象,在对象内部使用 getComponent 进行配置。
childRoutes
子路由配置。
此处放置子路由的配置信息,对应旧版中的子路由集合。我们将原有的 /baidu、/404 以及通配符 * 路由均进行了拆分,接下来将分别为它们创建对应的路由配置。
子路由拆分与文件结构
路由控制
在上面的 childRoutes 中,我们 require 了三个子路由文件。请在目录下创建 routes 目录,并将这三个路由文件放入其中。
routes/
├── 404
│ └── index.js
├── baidu
│ ├── index.js
│ └── routes
│ ├── frequency
│ │ └── index.js
│ └── result
│ └── index.js
└── redirect
└── index.js
与 rootRoute 类似,每个 index.js 文件均定义了一个路由对象:
/404/index.js
module.exports = {
path: '404',
getComponent(nextState, cb) {
require.ensure([], (require) => {
cb(null, require('components/layer/NotFoundPage'))
}, 'NotFoundPage')
}
}
/baidu/index.js
module.exports = {
path: 'baidu',
getChildRoutes(partialNextState, cb) {
require.ensure([], (require) => {
cb(null, [
require('./routes/result'),
require('./routes/frequency')
])
})
},
getComponent(nextState, cb) {
require.ensure([], (require) => {
cb(null, require('components/layer/BaiduPage'))
}, 'BaiduPage')
}
}
/baidu/routes/frequency/index.js
module.exports = {
path: 'frequency',
getComponent(nextState, cb) {
require.ensure([], (require) => {
cb(null, require('components/layer/BaiduFrequencyPage'))
}, 'BaiduFrequencyPage')
}
}
以及其他类似的路由文件。
重定向路由实现
接下来介绍重定向(Redirect)的设置方法。
我们需要将重定向路由单独拆分,即通配符 * 对应的路由,上文已为其创建了 redirect 目录。此处使用 onEnter 方法,在方法内部改变路由状态并跳转至目标路由,从而实现重定向:
/redirect/index.js 官方示例
module.exports = {
path: '*',
onEnter: (_, replaceState) => replaceState(null, "/404")
}
以上为本文全部内容,希望对您的学习有所帮助,欢迎继续支持本站。