前端之家收集整理的这篇文章主要介绍了
代码分离知多少,
前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
一、为什么要进行代码拆分
@H_
404_2@在以往的
性能优化清单中,减少HTTP请求一直是其中的一项。事实上,也做到了。在目前的大多数应用开发中都会用到 webpack 进行应用的构建打包,从而将我们应用以及应用所需的模块打包成一个大 bundle。这样也确实是减少了HTTP的请求。但是这样做有几个明显的劣势:
- 首屏加载时间过长,导致白屏,移动端网络不稳定尤甚
- 当你修改了业务代码以后,整个大的 bundle 要重新下载。
二、怎样对代码进行拆分
@H_
404_2@先看一下
webpack
进行
代码分离的几种
方法:
- 在入口处配置
entry
进行分离
- 防止重复,使用
CommonsChunkPlugin
去重和分离chunk
- 动态导入:使用模块的内联函数
1、在入口处配置进行分离
entry: {
app: './src/entry.js',vendor: ['react','react-dom']
},
@H_
404_2@对于一些不常变动的库,比如框架,第三方依赖等等,可以直接在入口就进行
代码的分离,就好比这里的
react
、
react-dom
2、防止重复,使用CommonsChunkPlugin
@H_
404_2@这个
插件可以将公共模块依赖
提取到已有的chunk中,比如下面这样
new webpack.optimize.CommonsChunkPlugin({
name: 'common',}),
@H_
404_2@当然,这个
插件在
webpack
4.0以上的版本被废弃掉了,具体的可以查看
SplitChunksPlugin
3、使用import()
来进行动态导入
@H_
404_2@
import()
的相关文档可以查看
import()相关文档
@H_
404_2@当然,使用
import()
需要用到
babel-plugin-Syntax-dynamic-import
插件
@H_
404_2@
import()
的使用如下:
import('lodash').then(_ => {
// do something
})
@H_
404_2@但这样写的话,每次都很麻烦,这里有一个高阶组件来处理这个事情
import React from 'react';
export default function asyncComponent(importComponent) {
class AsyncComponent extends React.Component {
constructor(props){
super(props);
this.state = {
Component: null,}
}
componentDidMount() {
importComponent().then(module => {
// const { default: component } = res;
this.setState({ Component: module.default });
});
}
render(){
const { Component } = this.state;
return Component ? <Component { ...this.props } /> : null;
}
}
return AsyncComponent;
}
@H_
404_2@有了这个高阶组件,使用就方便了:
const Result = asyncComponent(() => import('./container/result/result'))
@H_
404_2@
import
规范不允许控制模块的
名称或其他的
属性,因为
chunks
是
webpack
的概念。如果像上面那样直接使用的话,
输出的就像下面这样
@H_
404_2@
@H_
404_2@好在
webpack
可以注释接受一些特殊的参数,但还要在
配置文件的
output
加上chunkFilename
// 第一处修改
const Result = asyncComponent(() => import(/* webpackChunkName: "result" */ './container/result/result'))
// 第二处修改
output: {
path: '/',publicPath: '/',chunkFilename: '[name].bundle.js',filename: '[name].[hash].js',},
@H_
404_2@这样,上面的模块就会被命名为
result.bundle.js
,而不是
[id].bundle.js
。
@H_
404_2@其实做到这一步,就已经做到了
代码拆分。但是有一个比较好的库更适合做这个事情,这个库就是
react-loadable
,使用如下:
const Home = Loadable({
loader: () => import(/* webpackChunkName: "Home" */ './container/Home/home'),loading: () => {
return <div>loading</div>
},})
@H_
404_2@有的组件加载实在过快(<200ms),那么这个我们可以给一
Loading
组件来设置延迟时间
function Loading(props) {
if (props.error) {
return <div>Error! <button onClick={ props.retry }>Retry</button></div>;
} else if (props.pastDelay) {
return <div>Loading...</div>;
} else {
return null;
}
}
@H_
404_2@接着使用
react-loadable
const Home = Loadable({
loader: () => import(/* webpackChunkName: "Home" */ './container/Home/home'),loading: Loading,delay: 200,// 200ms内加载出来的话,不显示加载状态
})
@H_
404_2@想了解更多
react-loadable
,可以点击
react-loadable
import React from 'react';
import { Route,Router,BrowserRouter,HashRouter,Switch,Redirect } from 'react-router-dom';
import { ConnectedRouter } from 'react-router-redux';
import createHistory from 'history/createHashHistory';
import App from './container/app';
import Loadable from 'react-loadable';
const Home = Loadable({
loader: () => import(/* webpackChunkName: "Home" */ './container/Home/home'),loading: () => {
return <div>loading</div>
}
})
const Result = Loadable({
loader: () => import(/* webpackChunkName: "result" */ './container/result/result'),loading: () => {
return <div>loading...</div>
}
})
const history = createHistory();
class Routers extends React.Component {
render() {
return (
<HashRouter>
<App>
<Switch>
<Route exact path="/" render={() => (<Redirect to="/home" />)} />
<Route path="/home" component={Home} />
<Route path="/second" component={Result} />
</Switch>
</App>
</HashRouter>
)
}
}
export default Routers;
最后
@H_
404_2@
代码拆分有两种思路,一种是基于路由拆分,一种是基于组件拆分
@H_
404_2@
@H_
404_2@左边这幅图是基于路由拆分的示意图,右边的是基于组件拆分的示意图,可以看到基于组件进行拆分的粒度更细一点。
@H_
404_2@考虑这样一个场景,你有多个tab,可能有一些tab你从进入应用到离开应用都不会去点击它,那么每个tab
页面下的组件就很适合进行
代码拆分。这完全根据你的应用场景来决定的。
@H_
404_2@如果你想对你的一些组件进行拆分,也是同样的使用
react-loadable