如何实现 React 模块动态导入

React 模块动态导入

代码分割

webpack & code splitting

https://reactjs.org/docs/code-splitting.html

https://zh-hans.reactjs.org/docs/code-splitting.html

Code-Splitting 可以创建多个可在运行时动态加载的包

https://webpack.js.org/guides/code-splitting/

https://rollupjs.org/guide/en/#code-splitting

https://github.com/browserify/factor-bundle

虽然您并未减少应用程序中的全部代码量,但避免了加载用户可能永远不需要的代码,并减少了初始加载过程中所需的代码量。

https://create-react-app.dev/docs/code-splitting/

https://nextjs.org/docs/advanced-features/dynamic-import

React.lazy and Suspense are not yet available for server-side rendering.

code-splitting & server-side rendering

https://github.com/gregberge/loadable-components

https://loadable-components.com/docs/server-side-rendering/

React.lazy

React.lazy 函数让你可以可以像导入将常规组件一样的渲染一个动态导入。

  1. import OtherComponent from './OtherComponent';
  1. // React.lazy
  2. const OtherComponent = React.lazy(() => import('./OtherComponent'));

首次呈现此组件时,它将自动加载包含OtherComponent的捆绑包。

React.lazy 采用了必须调用动态 import()的函数。

这必须返回一个 Promise,该 Promise 解析为一个带有默认导出的模块,该模块包含一个 React组件。

然后,应该将懒惰的组件呈现在Suspense组件中,这使我们可以在等待懒惰的组件加载时显示一些后备内容(例如加载指示符)。

  1. import React, { Suspense } from 'react';
  2. const OtherComponent = React.lazy(() => import('./OtherComponent'));
  3. function MyComponent() {
  4. return (
  5. <div>
  6. <Suspense fallback={<div>Loading...</div>}>
  7. <OtherComponent />
  8. </Suspense>
  9. </div>
  10. );
  11. }

fallback prop 支持在等待组件加载时接受要渲染的任何React元素

您可以将 Suspense 组件放置在 lazy 组件上方的任何位置

您甚至可以用一个 Suspense 组件包装多个惰性组件。


  1. import React, { Suspense } from 'react';
  2. const OtherComponent = React.lazy(() => import('./OtherComponent'));
  3. const AnotherComponent = React.lazy(() => import('./AnotherComponent'));
  4. function MyComponent() {
  5. return (
  6. <div>
  7. <Suspense fallback={<div>Loading...</div>}>
  8. <section>
  9. <OtherComponent />
  10. <AnotherComponent />
  11. </section>
  12. </Suspense>
  13. </div>
  14. );
  15. }

Error boundaries

错误边界

如果另一个模块无法加载(例如,由于网络故障),它将触发错误

您可以处理这些错误,以显示良好的用户体验,并通过错误边界管理恢复

创建错误边界后,您可以在惰性组件上方的任何位置使用它来在出现网络错误时显示错误状态。

  1. import React, { Suspense } from 'react';
  2. import MyErrorBoundary from './MyErrorBoundary';
  3. const OtherComponent = React.lazy(() => import('./OtherComponent'));
  4. const AnotherComponent = React.lazy(() => import('./AnotherComponent'));
  5. const MyComponent = () => (
  6. <div>
  7. <MyErrorBoundary>
  8. <Suspense fallback={<div>Loading...</div>}>
  9. <section>
  10. <OtherComponent />
  11. <AnotherComponent />
  12. </section>
  13. </Suspense>
  14. </MyErrorBoundary>
  15. </div>
  16. );

https://reactjs.org/docs/error-boundaries.html

Route-based code splitting

基于路由的代码拆分

React Router & React.lazy

确定在应用程序中的何处引入代码拆分可能有些棘手

您要确保选择的位置能够平均拆分捆绑包,但不会破坏用户体验

路线是一个不错的起点

网络上的大多数人习惯了页面过渡,需要花费一些时间来加载

您还倾向于一次重新渲染整个页面,因此您的用户不太可能同时与页面上的其他元素进行交互

这是一个示例,说明如何使用带有 React.lazy 的 React Router 等库将基于路由的代码拆分为您的应用。

  1. import React, {
  2. Suspense,
  3. lazy,
  4. } from 'react';
  5. import {
  6. BrowserRouter as Router,
  7. Route,
  8. Switch,
  9. } from 'react-router-dom';
  10. const Home = lazy(() => import('./routes/Home'));
  11. const About = lazy(() => import('./routes/About'));
  12. const App = () => (
  13. <Router>
  14. <Suspense fallback={<div>Loading...</div>}>
  15. <Switch>
  16. <Route exact path="/" component={Home}/>
  17. <Route path="/about" component={About}/>
  18. </Switch>
  19. </Suspense>
  20. </Router>
  21. );

https://reactjs.org/docs/code-splitting.html#route-based-code-splitting

react-router

https://reacttraining.com/react-router/

Named Exports

命名的导出

React.lazy 当前仅支持默认导出

如果要导入的模块使用命名的导出,则可以创建一个中间模块,将其重新导出为默认模块

这样可以确保摇树不停,并且不会拉扯未使用的组件


  1. // ManyComponents.js
  2. export const MyComponent = /* ... */;
  3. export const MyUnusedComponent = /* ... */;
  1. // MyComponent.js
  2. // 中间模块, 导出为默认模块
  3. export { MyComponent as default } from "./ManyComponents.js";
  1. // MyApp.js
  2. import React, { lazy } from 'react';
  3. const MyComponent = lazy(() => import("./MyComponent.js"));

webpack

https://webpack.js.org/guides/code-splitting/


  1. module.exports = {
  2. entry: {
  3. main: './src/app.js',
  4. },
  5. output: {
  6. // `filename` provides a template for naming your bundles (remember to use `[name]`)
  7. filename: '[name].bundle.js',
  8. // `chunkFilename` provides a template for naming code-split bundles (optional)
  9. chunkFilename: '[name].bundle.js',
  10. // `path` is the folder where Webpack will place your bundles
  11. path: './dist',
  12. // `publicPath` is where Webpack will load your bundles from (optional)
  13. publicPath: 'dist/'
  14. }
  15. };

https://gist.github.com/gaearon/ca6e803f5c604d37468b0091d9959269

webpack & magic-comments

https://webpack.js.org/api/module-methods/#magic-comments

https://webpack.docschina.org/api/module-methods/#magic-comments


  1. // Single target
  2. import(
  3. /* webpackChunkName: "my-chunk-name" */
  4. /* webpackMode: "lazy" */
  5. /* webpackExports: ["default", "named"] */
  6. 'module'
  7. );
  8. // Multiple possible targets
  9. import(
  10. /* webpackInclude: /\.json$/ */
  11. /* webpackExclude: /\.noimport\.json$/ */
  12. /* webpackChunkName: "my-chunk-name" */
  13. /* webpackMode: "lazy" */
  14. /* webpackPrefetch: true */
  15. /* webpackPreload: true */
  16. `./locale/${language}`
  17. );
  18. import(/* webpackIgnore: true */ 'ignored-module.js');

babel

https://babeljs.io/

https://classic.yarnpkg.com/en/package/@babel/plugin-syntax-dynamic-import

  1. $ yarn add -D @babel/plugin-syntax-dynamic-import

https://babeljs.io/docs/en/babel-plugin-syntax-dynamic-import

  1. $ npm i -D @babel/plugin-syntax-dynamic-import

  1. {
  2. "plugins": ["@babel/plugin-syntax-dynamic-import"]
  3. }

  1. // webpack config
  2. const config = {
  3. entry: [
  4. "core-js/modules/es.promise",
  5. "core-js/modules/es.array.iterator",
  6. path.resolve(__dirname, "src/main.js"),
  7. ],
  8. // ...
  9. };
  1. // or
  2. // src/main.js
  3. import "core-js/modules/es.promise";
  4. import "core-js/modules/es.array.iterator";
  5. // ...

https://babeljs.io/blog/2019/07/03/7.5.0#dynamic-import-9552httpsgithubcombabelbabelpull9552-and-10109httpsgithubcombabelbabelpull10109

https://www.npmjs.com/package/babel-plugin-dynamic-import-node

https://github.com/airbnb/babel-plugin-dynamic-import-node

  1. $ yarn add -D babel-plugin-dynamic-import-node

.babelrc


  1. {
  2. "plugins": ["dynamic-import-node"]
  3. }

dynamic import

https://webpack.js.org/guides/code-splitting/#dynamic-imports

  1. import("./emoji-component").then(emoji => {
  2. // 使用 promise
  3. console.log(emoji));
  4. });

切换路由

react-router

lazy-load

延迟加载 / 懒加载

code splitting & dynamic import

import()类似函数的形式将模块名称作为参数,并返回一个Promise,该Promise始终解析为模块的名称空间对象

https://github.com/tc39/proposal-dynamic-import

http://2ality.com/2017/01/import-operator.html#loading-code-on-demand

https://create-react-app.dev/docs/code-splitting/

  1. const moduleA = `ESM (code splitting & dynamic import)`;
  2. export { moduleA };

这将使 moduleA.js 及其所有唯一依赖项成为单独的块,仅在用户单击“加载”按钮后才加载

  1. import React, { Component } from 'react';
  2. class App extends Component {
  3. handleClick = () => {
  4. import('./moduleA')
  5. .then(({ moduleA }) => {
  6. // Use moduleA
  7. })
  8. .catch(err => {
  9. // Handle failure
  10. });
  11. };
  12. render() {
  13. return (
  14. <div>
  15. <button onClick={this.handleClick}>Load</button>
  16. </div>
  17. );
  18. }
  19. }
  20. export default App;

async / await & promise

如果愿意,还可以将其与 async / await 语法一起使用

  1. // async / await
  2. async handleClick = () => {
  3. const moduleA = await import('./moduleA');
  4. moduleA.then(({ moduleA }) => {
  5. // Use moduleA
  6. })
  7. .catch(err => {
  8. // Handle failure
  9. });
  10. };

chunks

https://create-react-app.dev/docs/production-build

refs



xgqfrms 2012-2020

www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!


如何实现 React 模块动态导入的更多相关文章

  1. 反射attr以及模块动态导入

    一.实现自省的四个函数 1.hasattr判断一个对象中有没有一个name字符串对应的方法或属性 class BlackMedium: feture="Ugly" def __in ...

  2. python 反射 动态导入模块 类attr属性

    1.反射 hasattr getattr delattr setattr 优点:事先定义好接口,接口只有在被完成后才能真正执行,这实现了即插即用,这其实是一种“后期绑定”,即先定义好接口, 然后是再去 ...

  3. 封装,封装的原理,Property ,setter ,deleter,多态,内置函数 ,__str__ , __del__,反射,动态导入模块

    1,封装 ## 什么是封装 what 对外隐藏内部的属性,以及实现细节,并给外部提供使用的接口 学习封装的目的:就是为了能够限制外界对内部数据的方法 注意 :封装有隐藏的意思,但不是单纯的隐藏 pyt ...

  4. day26 封装、多态、内置函数、反射、动态导入

    今日内容 1.封装 什么是封装? 封装从字面意思上看就只将某种东西封起来装好,当我们代码中的某些方法与属性不想让外界进行访问时,就对这些属性进行特殊的处理,使这种属性或者方法不能被外界直接进行访问或者 ...

  5. python面向对象反射-框架原理-动态导入-元类-自定义类-单例模式-项目的生命周期-05

    反射 reflect 反射(reflect)其实是反省,自省的意思 反省:指的是一个对象应该具备可以检测.修改.增加自身属性的能力 反射:通过字符串获取对象或者类的属性,进行操作 设计框架时需要通过反 ...

  6. Python之路-python(面向对象进阶(模块的动态导入、断言、Socket Server))

    模块的动态导入 断言 Socket Server 一.模块的动态导入 class C(object): def __init__(self): self.name = "zhangsan&q ...

  7. Python 动态导入模块

    动态导入模块 目录结构: zhangsandeMacBook-Air:1110 zhangsan$ tree . . ├── lib │   └── aa.py ├── test1.py lib目录下 ...

  8. Python 实现接口类的两种方式+邮件提醒+动态导入模块+反射(参考Django中间件源码)

    实现接口类的两种方式 方式一 from abc import ABCMeta from abc import abstractmethod class BaseMessage(metaclass=AB ...

  9. python importlib动态导入模块

    一般而言,当我们需要某些功能的模块时(无论是内置模块或自定义功能的模块),可以通过import module 或者 from * import module的方式导入,这属于静态导入,很容易理解. 而 ...

随机推荐

  1. 使用Python的pandas模块、mplfinance模块、matplotlib模块绘制K线图

    目录 pandas模块.mplfinance模块和matplotlib模块介绍 pandas模块 mplfinance模块和matplotlib模块 安装mplfinance模块.pandas模块和m ...

  2. CSS Color Adjustment Module Level 1

    CSS Color Adjustment Module Level 1 https://drafts.csswg.org/css-color-adjust-1/ DarkMode 适配指南 | 微信开 ...

  3. 在线配置热加载配置 go-kratos.dev 监听key

    paladin https://v1.go-kratos.dev/#/config-paladin example Service(在线配置热加载配置) # service.go type Servi ...

  4. Python_ 1生成器(上)初识生成器

    引言:列表生成式 现在有个需求,给定列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],现在要求你把列表里的每个值加1,你怎么实现?你可能会想到2种方式 1 >>> a ...

  5. sentry 错误监控 报警

    错误监控 报警 Sentry | Error Tracking Software - JavaScript, Python, PHP, Ruby, more https://sentry.io/wel ...

  6. 通过动态构建Expression Select表达式并创建动态类型来控制Property可见性

    通过动态构建Expression Select表达式并创建动态类型来控制Property可见性 项目中经常遇到的一个场景,根据当前登录用户权限,仅返回权限内可见的内容.参考了很多开源框架,更多的是在V ...

  7. 玩遍博客网站,我整理了 Hexo 及其流行的风格主题

    搭建博客网站是个人进入互联网世界的最常见方式之一.伴随着网站技术的发展,如何搭建博客网站已经变得非常容易了.当然,你可以选择诸如 新浪博客.CSDN.博客园 之类的大型网站,快速创建依赖于大平台的个人 ...

  8. Java 8新特性(Lambda,Stream API)

    由于最近总监要求学习Java 8的一些知识,就去网上找了 一套教程来学习学习,将学习结果做一个小的总结记录,方便以后使用: 1.Java 8的优点 2.Lambda表达式优点 2.1Lambda实例 ...

  9. 码一次前后台post请求交互,以及接口的使用,json数据格式的传递

    近几天,公司疯狂加班,然后补做了很多功能,很多东西虽然是自己熟悉的,但是却不会上手,动手实践能力仍需加强,对此对一些代码记录,留待学习和总结. 简单描述功能 具体实现 前台JSP.JS.后台actio ...

  10. Pytest(18)pytest接口自动化完整框架思维导图

    pytest接口自动化完整框架思维导图