前端性能优化之按需加载(React-router+webpack)
一、什么是按需加载
和异步加载script的目的一样(异步加载script的方法),按需加载/代码切割也可以解决首屏加载的速度。
- 什么时候需要按需加载
如果是大文件,使用按需加载就十分合适。比如一个近1M的全国城市省市县的json文件,在我首屏加载的时候并不需要引入,而是当用户点击选项的时候才加载。如果不点击,则不会加载。就可以缩短首屏http请求的数量以及时间。
如果是小文件,可以不必太在意按需加载。过多的http请求会导致性能问题。
二、实现按需加载的方法
- Webpack打包模块工具实现
- RequireJs实现
这里介绍React-router+Webpack
实现按需加载的功能,效果如下:
三、实现过程(React-router4.0)
注意!我这里使用的是最新版本的React-router-dom^4.3.1.如果是4.0以下的react-route可直接看四
4.0相比以前实现方式要复杂。需要引入bundle-loader模块。并且自己创建bundle模型实现。
1.创建包装组件模型bundle.js
import React from 'react';
class Bundle extends React.Component {
constructor(arg){
super(arg)
this.state = {
mod: null,
}
}
componentWillMount() {
this.load(this.props);
}
componentWillReceiveProps(nextProps) {
if (nextProps.load !== this.props.load) {
this.load(nextProps);
}
}
// load 方法,用于更新 mod 状态
load(props) {
// 初始化
this.setState({
mod: null
});
/*
调用传入的 load 方法,并传入一个回调函数
这个回调函数接收 在 load 方法内部异步获取到的组件,并将其更新为 mod
*/
props.load(mod => {
this.setState({
mod: mod.default ? mod.default : mod
});
});
}
render() {
/*
将存在状态中的 mod 组件作为参数传递给当前包装组件的'子'
*/
return this.state.mod ? this.props.children(this.state.mod) : null;
}
}
export default Bundle ;
2.创建包装组件的方法(函数)
// 懒加载方法
import React from 'react';
import Bundle from './Bundle';
console.log(Bundle);
// 默认加载组件,可以直接返回 null
const Loading = () => <div>Loading...</div>;
/*
包装方法,第一次调用后会返回一个组件(函数式组件)
由于要将其作为路由下的组件,所以需要将 props 传入
*/
const lazyLoad = loadComponent => props => (
<Bundle load={loadComponent}>
{Comp => (Comp ? <Comp {...props} /> : <Loading />)}
</Bundle>
);
console.log(lazyLoad);
export default lazyLoad; //实际上lazyLoad就是一个函数,组件调用即可
上面两个文件的关系:
lazyLoad.js从名字上看,叫懒加载.实际上是一个中间件的作用。最后lazyLoad会暴露一个函数出来供组件调用。lazyLoad导出的内容:
function lazyLoad(loadComponent) {
return function(props) {
return (
<Bundle load={loadComponent}>
{Comp => (Comp ? <Comp {...props} /> : <Loading />)}
</Bundle>
)
}
}
显而易见,loadComponent就是要加载的组件,在路由中调用,例如:异步调用page1组件
<Route path="/page1" component={lazyLoad(Page1)}/>
Bundle.js作为按需加载的核心,在lazyLoad中间件就已经引入,并传入一个自定义的方法load,值为组件内容。以及动态的子内容children:
{Comp => (Comp ? <Comp {...props} /> : <Loading />)}
最终返回组件信息,并附带相应的props.如果不存在相关组件,则Loading
3. Route搭配使用
import React from 'react';
import { NavLink,Route,Switch,BrowserRouter as Router } from 'react-router-dom'
import './style/style.css'
import 'bundle-loader'
// bundle模型用来异步加载组件
import Bundle from '../routes/Bundle.js';
import lazyLoad from '../routes/lazyLoad';
import Page1 from 'bundle-loader?lazy&name=page1!../components/page1/index';
import Page2 from 'bundle-loader?lazy&name=page2!../components/page2/index';
import Page3 from 'bundle-loader?lazy&name=page3!../components/page3/index';
class AppPage extends React.Component{
constructor(arg){
super(arg)
this.state={}
}
render(){
return(
<Router basename="/" >
<div className="appWried">
<div className="appBtn">
<NavLink to="/page1" className="button" activeClassName="active">
PAGE1
</NavLink>
<NavLink to="/page2" className="button" activeClassName="active">
PAGE2
</NavLink>
<NavLink to="/page3" className="button" activeClassName="active">
PAGE3
</NavLink>
</div>
<Route
path="/"
render={props => (
<Switch>
<Route path="/page1" component={lazyLoad(Page1)}/>
<Route path="/page2" component={lazyLoad(Page2)}/>
<Route path="/page3" component={lazyLoad(Page3)}/>
</Switch>
)}
/>
</div>
</Router>
)
}
}
export default AppPage;
几个注意的点:
- import异步加载组件的时候,名字变更为'bundle-loader?lazy&name=page1!../components/page1/index'
其中bundle-loader表示loader:'bunle-loader'(需加载bundle-loader模块)
lazy表示lazy:true;懒加载
name:表示异步生成的文件名字- 去掉外层route,不用render渲染也是可行的
<Switch>
<Route path="/page1" component={lazyLoad(Page1)}/>
<Route path="/page2" component={lazyLoad(Page2)}/>
<Route path="/page3" component={lazyLoad(Page3)}/>
</Switch>
//webpack.config.js
...
module.exports = {
...
output:{
path:path.join(__dirname + '/dist'), //打包地方
filename:'bundle.js', //打包名字
publicPath: '/', //自动生成html引入js的路径
//按需加载
chunkFilename:'[name]_[chunkhash:8].js'
},
...
}
...
这里要注意一下publicPath这个参数.
如果未设置publicPath参数,则默认打包生成的html引入bundle的时候为:
<script type="text/javascript" src="bundle.js"></script>
如果设置publicPath为publicPath: '/dist',则打包后html文件引入js格式为:
<script type="text/javascript" src="/dist/bundle.js"></script>
参考文章:React-router-v4 - Webpack 实现按需加载(code-splitting)
前端性能优化之按需加载(React-router+webpack)的更多相关文章
- 阿里无线前端性能优化指南 (Pt.1 加载优化)
前言 阿里无线前端团队在过去一年对所负责业务进行了全面的性能优化.以下是我们根据实际经验总结的优化指南,希望对大家有所帮助. 第一部分仅包括数据加载期优化. 图片控制 对于网页特别是电商类页面来说,图 ...
- Web前端性能优化——如何提高页面加载速度
前言: 在同样的网络环境下,两个同样能满足你的需求的网站,一个"Duang"的一下就加载出来了,一个纠结了半天才出来,你会选择哪个?研究表明:用户最满意的打开网页时间是2-5秒, ...
- 【转】Web前端性能优化——如何提高页面加载速度
前言: 在同样的网络环境下,两个同样能满足你的需求的网站,一个“Duang”的一下就加载出来了,一个纠结了半天才出来,你会选择哪个?研究表明:用户最满意的打开网页时间是2-5秒,如果等待超过10秒, ...
- vue项目优化之按需加载组件-使用webpack require.ensure
require-ensure和require-amd的区别: require-amd 说明: 同AMD规范的require函数,使用时传递一个模块数组和回调函数,模块都被下载下来且都被执行后才执行回调 ...
- vue项目性能优化(路由懒加载、gzip加速、cdn加速)
前端工程性能优化一说意义深远悠长,本章主要介绍除了一些基础优化外如何实行路由懒加载.Gzip加速.CDN加速,让网页飞的快一些. 基础优化 老生常谈的一些: 不要在模板中写复杂的表达式 慎用watch ...
- VUE项目性能优化实践——通过懒加载提升页面响应速度
本文由葡萄城技术团队原创并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 最近我司因业务需求,需要在一个内部数据分析平台集成在线Excel功能,既然我 ...
- 页面性能优化:preload预加载静态资源
本文主要介绍preload的使用,以及与prefetch的区别.然后会聊聊浏览器的加载优先级. preload 提供了一种声明式的命令,让浏览器提前加载指定资源(加载后并不执行),在需要执行的时候再执 ...
- React 性能优化之组件动态加载(react-loadable)
React 项目打包时,如果不进行异步组件的处理,那么所有页面所需要的 js 都在同一文件中(bundle.js),整个js文件很大,从而导致首屏加载时间过长. 所有,可以对组件进行异步加载处理,通常 ...
- Web前端性能优化进阶——完结篇
前言 在之前的文章 如何优化网站性能,提高页面加载速度 中,我们简单介绍了网站性能优化的重要性以及几种网站性能优化的方法(没有看过的可以狂戳 链接 移步过去看一下),那么今天我们深入讨论如何进一步优化 ...
随机推荐
- 蓝牙Profile的概念和常见种类(转)
蓝牙Profile Bluetooth的一个很重要特性,就是所有的Bluetooth产品都无须实现全部 的Bluetooth规范.为了更容易的保持Bluetooth设备之间的兼容,Bluetooth规 ...
- Git HEAD detached from XXX (git HEAD 游离) 解决办法
本文 Git 图片主要来自:图解 Git,非常感谢! 读完本文你将了解: 什么是 HEAD HEAD 游离状态的利与弊 具体解决操作 Thanks 什么是 HEAD Git 中的 HEAD 可以理解为 ...
- How to install john deere service advisor 4.2.005 on win 10 64bit
How to install john deere service advisor 4.2.005 with the February 2016 data base disks on a machin ...
- 数据库中的undo日志、redo日志
MySQL中有六种日志文件,分别是:重做日志(redo log).回滚日志(undo log).二进制日志(binlog).错误日志(errorlog).慢查询日志(slow query log).一 ...
- EDK II之USB总线驱动的实现框架
本文简单介绍一下UEFI中USB驱动的实现框架: 下图是USBD向上层驱动提供的接口: 1.从图中我们可以看出,USBDI的实现主要通过调用HCDI实现 和 访问USB_INTERFACE结构体(该结 ...
- P4890 Never·island(dp)
P4890 Never·island 求门开的最小时间,其实也就是求门关的最大时间. 坐标这么大....显然坐标要离散化 离散化排序后,我们发现x轴被这些点划分成若干条线段$(l,r)$,并且有4种情 ...
- jQuery操作下拉框的text值和val值
jQuery操作下拉框的text值和val值 1,JS源码 <select name="select1" id="select1" style=" ...
- java热加载之springloaded
https://github.com/spring-projects/spring-loaded/wiki
- FileZilla连接腾讯云Centos7
现在需要使用ftp快速上传资料去云机备份, 于是想到FileZilla. 生成密匙文件 登录腾讯云--ssh密匙 FileZilla Client 导入密匙文件 填写登录信息 连接 另外记得开放22端 ...
- 快速阅读《QT5.9 c++开发指南》2
1.sample2_2 信号和槽 MFC中最让人印象深刻的就是"消息映射",这里有理由相信,"信号和槽"是这种功能的发扬和扩展.通过简单的 connect(ui ...