如何实现 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 函数让你可以可以像导入将常规组件一样的渲染一个动态导入。

import OtherComponent from './OtherComponent';

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

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

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

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

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

import React, { Suspense } from 'react';

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

function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
</div>
);
}

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

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

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


import React, { Suspense } from 'react'; const OtherComponent = React.lazy(() => import('./OtherComponent')); const AnotherComponent = React.lazy(() => import('./AnotherComponent')); function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<section>
<OtherComponent />
<AnotherComponent />
</section>
</Suspense>
</div>
);
}

Error boundaries

错误边界

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

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

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

import React, { Suspense } from 'react';

import MyErrorBoundary from './MyErrorBoundary';

const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent')); const MyComponent = () => (
<div>
<MyErrorBoundary>
<Suspense fallback={<div>Loading...</div>}>
<section>
<OtherComponent />
<AnotherComponent />
</section>
</Suspense>
</MyErrorBoundary>
</div>
);

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



Route-based code splitting

基于路由的代码拆分

React Router & React.lazy

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

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

路线是一个不错的起点

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

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

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

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>
);

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

react-router

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

Named Exports

命名的导出

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

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

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


// 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"));

webpack

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


module.exports = {
entry: {
main: './src/app.js',
},
output: {
// `filename` provides a template for naming your bundles (remember to use `[name]`)
filename: '[name].bundle.js',
// `chunkFilename` provides a template for naming code-split bundles (optional)
chunkFilename: '[name].bundle.js',
// `path` is the folder where Webpack will place your bundles
path: './dist',
// `publicPath` is where Webpack will load your bundles from (optional)
publicPath: 'dist/'
}
};

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


// Single target
import(
/* webpackChunkName: "my-chunk-name" */
/* webpackMode: "lazy" */
/* webpackExports: ["default", "named"] */
'module'
); // Multiple possible targets
import(
/* webpackInclude: /\.json$/ */
/* webpackExclude: /\.noimport\.json$/ */
/* webpackChunkName: "my-chunk-name" */
/* webpackMode: "lazy" */
/* webpackPrefetch: true */
/* webpackPreload: true */
`./locale/${language}`
);
import(/* webpackIgnore: true */ 'ignored-module.js');

babel

https://babeljs.io/

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

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

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

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

{
"plugins": ["@babel/plugin-syntax-dynamic-import"]
}

// webpack config
const config = {
entry: [
"core-js/modules/es.promise",
"core-js/modules/es.array.iterator",
path.resolve(__dirname, "src/main.js"),
],
// ...
};
// or

// src/main.js
import "core-js/modules/es.promise";
import "core-js/modules/es.array.iterator"; // ...

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

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

.babelrc


{
"plugins": ["dynamic-import-node"]
}

dynamic import

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

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

切换路由

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/

const moduleA = `ESM (code splitting & dynamic import)`;

export { moduleA };

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

import React, { Component } from 'react';

class App extends Component {
handleClick = () => {
import('./moduleA')
.then(({ moduleA }) => {
// Use moduleA
})
.catch(err => {
// Handle failure
});
};
render() {
return (
<div>
<button onClick={this.handleClick}>Load</button>
</div>
);
}
}
export default App;

async / await & promise

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

// async / await 

 async handleClick = () => {
const moduleA = await import('./moduleA'); moduleA.then(({ moduleA }) => {
// Use moduleA
})
.catch(err => {
// Handle failure
});
};

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. windows ping bat脚本

    参考百度链接:https://zhidao.baidu.com/question/577024998.html 要求:1.从同级目录下读取iplist.txt文件内的ip/域名列表(每行一个):2.对 ...

  2. Beating JSON performance with Protobuf https://auth0.com/blog/beating-json-performance-with-protobuf/

    Beating JSON performance with Protobuf https://auth0.com/blog/beating-json-performance-with-protobuf ...

  3. 【SVN】windows 下的SVN常见问题及其解决方法

    1.能提交和更新,但SVN查看log时提示:找不到路径 'svn/XXXX' 双击以清除错误信息 勾选这个选项就好了.因为该路径是通过重命名或者拷贝过来的,倘若不选中,SVN便会尝试同时从当前文件的拷 ...

  4. 系列trick - bitmask

    目录 系列trick - bitmask 拆位 位运算优化(点少的)图操作 位筛 系列trick - bitmask 拆位 主体思想:位之间不影响,把每一位拆开来考虑贡献,转化成非常容易考虑的 0/1 ...

  5. wmi_exporter+Prometheus+Grafana

    wmi_exporter+Prometheus+Grafana 原文地址: CSDN:NRlovestudy:Windows 下搭建 wmi_exporter+Prometheus+Grafana 服 ...

  6. SparkMLlib—协同过滤推荐算法,电影推荐系统,物品喜好推荐

    SparkMLlib-协同过滤推荐算法,电影推荐系统,物品喜好推荐 一.协同过滤 1.1 显示vs隐式反馈 1.2 实例介绍 1.2.1 数据说明 评分数据说明(ratings.data) 用户信息( ...

  7. Weblogic漏洞利用

    Weblogic漏洞 Weblogic任意文件上传(CVE-2018-2894) 受影响版本 weblogic 10.3.6.0.weblogic 12.1.3.0.weblogic 12.2.1.2 ...

  8. java架构《并发线程高级篇三》

    本章主要介绍和讲解concurrent.util里面的常用的工具类. 一.CountDownLatch使用:(用于阻塞主线程) 应用场景 :通知线程休眠和运行的工具类,是wait和notify的升级版 ...

  9. 基于efcore的分表组件开源

    ShardingCore ShardingCore 是一个支持efcore 2.x 3.x 5.x的一个对于数据库分表的一个简易扩展, 目前该库暂未支持分库(未来会支持),仅支持分表,该项目的理念是让 ...

  10. Spring MVC 处理一个请求的流程分析

    Spring MVC是Spring系列框架中使用频率最高的部分.不管是Spring Boot还是传统的Spring项目,只要是Web项目都会使用到Spring MVC部分.因此程序员一定要熟练掌握MV ...