如何实现 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. linux--关于JVM CPU资源占用过高的问题排查

    一.背景: 先执行一个java程序里面开了两个线程分别都在while循环做打印操作. # java -cp ./test-threads.jar com.spiro.Main 二.现象: 通过top命 ...

  2. 解决window10 和 ubuntu 双系统安装没有启动选项问题

    win10 和Ubuntu 双系统安装在网上已经有很多例子了,这里就不在赘述了. 今天新买的笔记本,想安装双系统.正常安装完ubuntu 重启后没有选项. 解决方法一 下载和解压以后,按照以下的步骤安 ...

  3. charles配置

    https://www.cnblogs.com/ceshijiagoushi/p/6812493.html https://www.zzzmode.com/mytools/charles/

  4. 4、剑指offer——从尾到头打印链表java实现

    **题目描述** **输入一个链表,按链表从尾到头的顺序返回一个ArrayList.** 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M 思路:   1.如果链 ...

  5. 长连接开发踩坑之netty OOM问题排查实践

    https://mp.weixin.qq.com/s/jbXs7spUCbseMX-Vf43lPw 原创: 林健  51NB技术  2018-07-13

  6. LOJ10092半连通子图

    Description 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u ...

  7. 通过 JFR 与日志深入探索 JVM - TLAB 原理详解

    全系列目录:通过 JFR 与日志深入探索 JVM - 总览篇 什么是 TLAB? TLAB(Thread Local Allocation Buffer)线程本地分配缓存区,这是一个线程专用的内存分配 ...

  8. vue项目在IE下报 [vuex] vuex requires a Promise polyfill in this browser错误

    ie浏览器下报错 vue刚搭建的项目,在谷歌浏览器能够正常访问,但是在ie11等ie浏览器下无法显示页面,打开控制台查看无报错信息,打开仿真一栏,提示[vuex] vuex requires a Pr ...

  9. centos6.5升级gcc 4.4.7为最新版4.9.1

    ==================本方法切实可行===桌面版不建议用.centos============================== 1.下载源码包 我的下载  gcc-4.9.1.tar ...

  10. 飞塔创建IPSec

    5.2和5.4版本飞塔建立IPSec VPN时,必须在两端添加完策略.路由后IPSec才会起来.