《猛戳-查看个人博客地图-总有你意想不到的惊喜》
本文内容:代码分离、资源按需加载javascript
当项目太大时,单页面应用打包成单个bundle包,若是不进行代码分离,首屏会加载没有用到的资源,严重影响首屏加载时间。html
webpack提供的有三种经常使用的代码分离方法:click here前端
多入口打包输出多模块,以下:在entry配置了三个入口,分别是app、vendor、jqueryjava
4个入口,会生成7个js文件,包括4个入口的独立压缩文件和3个关联文件(关联文件:app~ vendor、app~ jquery、app~ common),从此在常规开发中,3个类库文件(vendor、jquery、common)和3个关联文件不会常常改变,生成的chunkhash值不变,项目升级只更新app包,这个业务代码的app包很是小。react
module.exports = { entry: { app:'./src/index.js', // 将 第三方依赖 单独打包 vendor: [ 'react', 'react-dom', //'react-router', 'react-router-dom', 'react-router-redux', 'redux', 'react-redux', ], jquery:["jquery"], common:['./public/common-module'] }, output: { path: path.join(__dirname, '../dist'), filename: '[name].[chunkhash:8].bundle.js',//当文件没有发生改变chunkhash不变 chunkFilename: '[name].[chunkhash].js',//非入口(non-entry) chunk 文件(关联文件)的名称 } };
注意:此处 react-router 和 react-router-dom 库,二选一,react-router-dom 库包含 react-router 全部内容jquery
遗留问题和陷阱:4个对应入口文件app vendor jquery common中,若是 chunks 之间包含重复的模块,那些重复模块都会被引入到各个 bundle 中,形成重复引用
webpack
使用 SplitChunksPlugin 插件来移除重复的模块web
module.exports = { optimization: { splitChunks: { chunks: 'all' } } };
import React, { Component } from "react"; export default function asyncComponent(importComponent) { class AsyncComponent extends Component { constructor(props) { super(props); this.state = { component: null }; } async componentDidMount() { const { default: component } = await importComponent(); this.setState({ component: component }); } render() { const C = this.state.component; return C ? <C {...this.props} /> : null; } } return AsyncComponent; } const AsyncHome = asyncComponent(() => import("./containers/Home")); <Route path="/" exact component={AsyncHome} />
import React, { Component } from 'react'; class DynamicImports extends Component { constructor(props) { super(props); this.state = { } } async getComponent(){ //使用import()语法,动态导入必须是npm包模块 //本地本身封装的模块没法使用这种模式,属于非法操做 let $ = await import(/* webpackMode: "jquery" */'jquery') let dom = document.createElement('div') $('dom').text('some text') return dom } insert(){ this.getComponent().then(component => { document.getElementById('box').appendChild(component); }); } render() { return ( <div id='box'> <div>点击下面这个按钮,动态插入较大的DOM</div> <span className='btn' onClick={()=>{this.insert()}}>click</span> </div> ); } } export default DynamicImports;
require.ensure() 是 webpack 特有的,已经被 import() 取代。
//路由中的组件经过getComponent方法引入 //组件引入经过require.ensure,并在webpack中配置chunkFilename const chooseProducts = (location, cb) => { require.ensure([], require => { cb(null, require('../Component/chooseProducts').default) },'chooseProducts') } const helpCenter = (location, cb) => { require.ensure([], require => { cb(null, require('../Component/helpCenter').default) },'helpCenter') } const saleRecord = (location, cb) => { require.ensure([], require => { cb(null, require('../Component/saleRecord').default) },'saleRecord') } const RouteConfig = ( <Router history={history}> <Route path="/" component={Roots}> <IndexRoute component={index} />//首页 <Route path="index" component={index} /> <Route path="helpCenter" getComponent={helpCenter} />//帮助中心 <Route path="saleRecord" getComponent={saleRecord} />//销售记录 <Redirect from='*' to='/' /> </Route> </Router> );
click herenpm
{ "presets": ["@babel/react"], "plugins": ["@babel/plugin-syntax-dynamic-import"] } import Loadable from "react-loadable"; import Loading from "./Loading"; const LoadableComponent = Loadable({ loader: () => import("./Dashboard"), loading: Loading }); export default class LoadableDashboard extends React.Component { render() { return <LoadableComponent />; } }
感谢阅读,欢迎评论^-^redux
打赏我吧^-^