前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于webpack4+react 的js懒加载

基于webpack4+react 的js懒加载

原创
作者头像
shirley
修改2019-04-01 12:31:59
4.3K0
修改2019-04-01 12:31:59
举报
文章被收录于专栏:进击的全栈
以下介绍js懒加载的两种方式:
  • webpack4方式
  • React.lazy方式
webpack4方式

严格意义来说,这种方式是按需加载,只加载用到的js文件。

此处主要介绍使用动态导入(通过模块中的内联函数调用来分离代码)的懒加载。这种动态代码拆分的方式是webpack提供并推荐选择的方式。其原理是使用符合 ECMAScript 提案import() 语法 来实现动态导入。

代码语言:javascript
复制
import() 调用会在内部用到 promises。如果在旧版本浏览器中使用 import(),记得使用一个 polyfill 库(例如 es6-promise 或 promise-polyfill),来 shim Promise。

例如:通过 dynamic import(动态导入) lodash 来分离出一个 chunk:

代码语言:javascript
复制
function getComponent() {
    return import(/* webpackChunkName: "lodash" */ 'lodash').then(({ default: _ }) => {
    var element = document.createElement('div');
    element.innerHTML = _.join(['Hello', 'webpack'], ' ');
    return element;
    }).catch(error => 'An error occurred while loading the component');
}
​
getComponent().then(component => {
    document.body.appendChild(component);
})

当调用 ES6 模块的 import() 方法(引入模块)时,必须指向模块的 .default 值,因为它才是 promise 被处理后返回的实际的 module 对象。原因是从 webpack v4 开始,在 import CommonJS 模块时,不会再将导入模块解析为 module.exports 的值,而是为 CommonJS 模块创建一个 artificial namespace object(人工命名空间对象),关于其背后原因的更多信息,请阅读 webpack 4: import() 和 CommonJs

在注释中使用了webpackChunkName。这样会将拆分出来的 bundle 命名为 lodash.bundle.js,而不是 [id].bundle.js

由于 import() 会返回一个 promise,因此它可以和 async 函数一起使用。但是,需要使用像 Babel 这样的预处理器和 Syntax Dynamic Import Babel Plugin。下面是通过async 函数简化的代码:

代码语言:javascript
复制
async function getComponent() {
var element = document.createElement('div');
    const { default: _ } = await import(/* webpackChunkName: "lodash" */ 'lodash');
    element.innerHTML = _.join(['Hello', 'webpack'], ' ');
    return element;
}
getComponent().then(component => {
    document.body.appendChild(component);
});
React.lazy方式

React.lazy函数将动态引入(dynamic import)当作一个常规组件来渲染。

例如:动态引入OtherComponent组件:

代码语言:javascript
复制
const OtherComponent = React.lazy(() => import('./OtherComponent'));
​
function MyComponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <OtherComponent />
      </Suspense>
    </div>
  );
}

当这个组件被渲染时,将自动加载包含OtherComponent的bundle。

使用React.lazy时,传入一个调用动态import()的函数。这个函数必须返回一个Promise,它解析一个包含React组件的一个默认导出(default export)的模块。

如果在MyComponent渲染时尚未加载包含OtherComponent的模块,我们必须在等待加载时显示一些后备内容—— 例如加载指示符。 这是使用Suspense组件完成的。

fallback 属性接受任何 React 元素。可以将Suspense组件放在懒加载组件上方的任何位置,甚至可以使用单个Suspense组件包裹多个懒加载的组件。

建议从路由开始处进行代码拆分。以下是使用React Router 和 React.lazy 从路由拆分代码的示例:

代码语言:javascript
复制
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import React, { Suspense, lazy } from 'react';
​
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>
);

React.lazy 目前仅支持默认导出。 如果想要导入的模块使用命名导出,则可以创建一个中间模块,将其重新导出为默认模块。

代码语言:javascript
复制
// ManyComponents.js
export const MyComponent = /* ... */;
export const MyUnusedComponent = /* ... */;
​
// MyComponent.js
export { MyComponent as default } from "./ManyComponents.js";
​
// MyApp.js
import React, { lazy } from 'react';
const MyComponent = lazy(() => import("./MyComponent.js"));
React.lazy 和 Suspense还不支持在服务端的渲染。
React v16.6.0以上版本才支持React.lazy 和 Suspense。
总结

关于懒加载,除了以上两种方法之外,还可以使用插件的方式或者直接使用原生的 js 方式来实现。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 以下介绍js懒加载的两种方式:
  • webpack4方式
  • React.lazy方式
    • React.lazy 和 Suspense还不支持在服务端的渲染。
      • React v16.6.0以上版本才支持React.lazy 和 Suspense。
      • 总结
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档