02 Code-Splitting

打包

大多数React应用都会使用Webpack/Rollup/Browserify这类构建工具来打包文件
打包指的是将引入文件合并到一个单独文件的过程,最终形成一个bundle,接着在页面内引入该bundle,就可以一次性载入!
如果你在使用 Create React App, Next.js, Gatsby等类似工具,你会拥有一个可以直接使用的Webpack配置来进行打包工作。
如果没有使用上述工具,就需要自己进行配置


代码分隔

尽管打包是个很棒的技术,但随着应用的增长和第三方库的增加,难免会出现页面加载缓慢现象
为避免搞出大体积代码包,前期考虑到代码分隔是明智的
常见的代码构建工具/打包器都支持这一技术,能够创建多个包并在运行时动态加载。
代码分隔可以让你“懒加载”用户所需内容,提升响应速度

动态import语法

动态import()语法是引入代码分隔的最佳方式

import('./math').then(math => {
  console.log(math.add(19, 21))
})

Webpack在解析到该语法时,会自动进行代码分隔
当你使用Babel时,要确保Babel能解析动态import语法,而非进行转换,你需要babel-plugin-syntax-dynamic-import插件


React.lazy

React.lazy函数能让你像渲染常规组件一样处理动态引入的组件

// not using React.lazy
import OtherCompo from './OtherCompo'

// using React.lazy
const OtherCompo = React.lazy(() => import('./OtherCompo'))

React.lazy接收一个函数,该函数要动态调用import(),且必须返回一个Promise,该Promise需要resolve一个default export的React组件

接下来,应该在Suspense组件中渲染lazy组件,如此使得我们可以做组件加载中的优雅降级,即loading指示器

import React, { Suspense } from 'react'

const OtherCompo = React.lazy(() => import('./OtherCompo))

function MyCompo() {
  return (
    <div>
      <Suspense fallback={<div>Loading....</div>}>
        <OtherCompo />
      </Suspense>
    </div>
  )
}

fallback属性接收任何React元素
Suspense组件可以置于懒加载组件之上的任意位置(任意父级别)
Suspense组件可以包裹多个懒加载组件


异常捕获边界(Error boundaries)

如果模块加载失败(如网路问题),它会触发一个错误
你可以通过异常捕获边界(Error boundaries)来处理,以显示良好的用户体验并管理恢复事宜

import React, { Suspense } from 'react'
import MyErrorBoundary from './MyErrorBoundary'

const OtherCompo = React.lazy(() => import('./OtherCompo'))
const AnotherCompo = React.lazy(() => import('./AnotherCompo'))

const MyCompo = () => {
  <div>
    <MyErrorBoundary>
      <Suspense fallback={<div>Loading...</div>}>
        <section>
          <OtherCompo />
          <AnotherCompo />
        </section>
      </Suspense>
    </MyErrorBoundary>
  </div>
}
// 具体实现见 04 Error Boundarires 

基于路由的代码分隔

决定在哪儿使用“引入代码分隔”是需要一些技巧的
引入代码分隔要以均匀分隔、不影响用户体验为前提条件

大多数用户习惯网页切换过程,所以常见的选择是从路由开始

import React, { Suspense, lazy } from 'react'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'

const Home = lazy(() => import('./routes/Home'))
const About = lazy(() => import('./routes/About'))

const App = () => (
  <Router>
    <Suspense fallback={<div>Loading...</div>}>
      <Switch>
        <Route exact path="/" component={Home} />
        <Route path="/about" component={About} />
      </Switch>
    </Suspense>
  </Router>
)

命名导出(Named Exports)

React.lazy目前只支持默认导出(default exports)
如果想要被引入的模块使用命名导出(named exports)
你可以创建一个中间模块,用以导出为默认模块,来保证tree shaking不出错

// Messages.js
export const AllMessages = /*...*/
export const UnreadMessages = /*...*/

// UnreadMessages.js
export { UnreadMessages as default } from './Messages.js'

// App.js
import React, { lazy } from 'react'
const UnreadMessages = lazy(() => import('./UnreadMessages'))

代码分割示例见:myapp>LazyCompo.jsx

Webpack 实现 Code Splitting 的方式主要有以下几种: 1. 基于入口点(Entry Points)的 Code Splitting:通过将应用程序拆分为多个入口点,每个入口点都可以生成一个独立的代码块,从而实现 Code Splitting。可以使用 Webpack 的 `entry` 配置选项来指定多个入口点,例如: ```js module.exports = { entry: { app: './src/app.js', vendor: './src/vendor.js' }, // ... } ``` 在上面的例子中,`app` 和 `vendor` 分别是两个入口点,它们可以生成独立的代码块。 2. 基于模块(Module)的 Code Splitting:通过将应用程序中的模块拆分为多个代码块,从而实现 Code Splitting。可以使用 Webpack 的 `import()` 函数来实现基于模块的 Code Splitting,例如: ```js function loadComponent() { // 动态加载异步模块 return import('./components/MyComponent.vue') } // 使用异步组件 Vue.component('my-component', () => ({ // 异步加载组件 component: loadComponent(), // 加载组件时显示的占位符 loading: LoadingComponent, // 加载组件失败时显示的占位符 error: ErrorComponent, // 组件加载成功后的延迟时间 delay: 200, // 最长等待时间 timeout: 10000 })) ``` 在上面的例子中,`loadComponent()` 函数返回一个异步加载的模块,可以通过 `import()` 函数来加载模块。然后,在组件中使用异步组件来加载动态组件。 3. 基于运行时(Runtime)的 Code Splitting:通过将应用程序的代码分成多个块,并在运行时动态加载这些代码块,从而实现 Code Splitting。可以使用 Webpack 的 `require.ensure()` 函数来实现基于运行时的 Code Splitting,例如: ```js function loadComponent() { // 动态加载异步模块 require.ensure(['./components/MyComponent.vue'], function() { // 加载成功后的回调函数 const MyComponent = require('./components/MyComponent.vue') // 渲染组件 new Vue({ el: '#app', render: h => h(MyComponent) }) }, function() { // 加载失败后的回调函数 }, 'my-component') } ``` 在上面的例子中,`require.ensure()` 函数用于异步加载模块,并在加载成功后执行回调函数。第三个参数 `'my-component'` 表示这个代码块的名称,用于指定 Webpack 生成的代码块文件名。 需要注意的是,虽然这些方式都可以实现 Code Splitting,但它们的实现方式和使用场景有所不同。因此,在实际开发中,应该根据具体的需求来选择合适的方式来实现 Code Splitting
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值