rpi*_*var 1 javascript dynamic-import reactjs webpack
我有一个使用 Webpack 作为捆绑器的 React 项目,我将我的捆绑包分成两个块 - 主代码库main.js和供应商捆绑包vendor.js。
构建这些捆绑包后,main.js最终大小为 45kb 和vendor.js651kb。
一个特定的供应商库大小为 225kb,似乎是供应商导入中最严重的违规者。
我正在文件顶部的页面组件中导入该库:
import React from 'react';
import { ModuleA, ModuleB } from 'heavyPackage'; // 225kb import
...
const Page = ({ setThing }) => {
...
};
Run Code Online (Sandbox Code Playgroud)
为了尝试将这个繁重的导入加载到单独的包中,我尝试使用动态导入来导入这些模块。
在组件内部Page,直到调用特定函数才真正使用模块,因此我尝试在该范围内而不是在文件顶部导入模块:
import React from 'react';
...
const Page = ({ setThing }) => {
...
const handleSignIn = async () => {
const scopedPackage = await import('heavyPackage');
const { moduleA, moduleB } = scopedPackage;
// use moduleA & moduleB normally here
};
};
Run Code Online (Sandbox Code Playgroud)
出于某种原因,我认为 Webpack 会智能地接受我在这里尝试做的事情,并将这个沉重的包分离成自己的块,仅在需要时下载,但生成的包是相同的 - 一个是main.js45kb,一个是 45kb。vendor.js那是 651kb。我的思路是否正确,可能是我的 Webpack 配置已关闭,还是我以错误的方式考虑动态导入?
编辑我已将 Webpack 配置为使用splitChunks. 以下是我的配置方法:
optimization: {
chunkIds: "named",
splitChunks: {
cacheGroups: {
commons: {
chunks: "initial",
maxInitialRequests: 5,
minChunks: 2,
minSize: 0,
},
vendor: {
chunks: "initial",
enforce: true,
name: "vendor",
priority: 10,
test: /node_modules/,
},
},
},
},
Run Code Online (Sandbox Code Playgroud)
React 18 更新:不再需要下面的代码来分割块/动态加载组件。相反,您可以将React.lazy 与 Suspense 结合使用,这会获得类似的结果(这只适用于React Components,因此任何node_module导入都需要在此动态加载的组件中导入):
Run Code Online (Sandbox Code Playgroud)const ProfilePage = React.lazy(() => import('./ProfilePage')); // Lazy-loaded <Suspense fallback={<Spinner />}> <ProfilePage /> </Suspense>
@Ernesto 的答案提供了一种使用插件进行代码分割的方法react-loadable,babel-dynamic-import但是,如果您的 Webpack 版本是 v4+(并且将自定义 Webpack 配置设置为所有人的 SplitChunks),那么您只需要使用魔术注释和自定义反应组件。
来自文档:
通过在导入中添加 [magic] 注释,我们可以执行诸如命名块或选择不同模式等操作。有关这些神奇注释的完整列表,请参阅下面的代码,然后解释这些注释的作用。
// 单个目标
Run Code Online (Sandbox Code Playgroud)const ProfilePage = React.lazy(() => import('./ProfilePage')); // Lazy-loaded <Suspense fallback={<Spinner />}> <ProfilePage /> </Suspense>
// 多个可能的目标
Run Code Online (Sandbox Code Playgroud)import( /* webpackChunkName: "my-chunk-name" */ /* webpackMode: "lazy" */ 'module' );
因此,您可以创建一个可重用的LazyLoad组件,如下所示:
import(
/* webpackInclude: /\.json$/ */
/* webpackExclude: /\.noimport\.json$/ */
/* webpackChunkName: "my-chunk-name" */
/* webpackMode: "lazy" */
/* webpackPrefetch: true */
/* webpackPreload: true */
`./locale/${language}`
);
Run Code Online (Sandbox Code Playgroud)
然后在您的路由中,使用目录LazyLoad中的文件名并将其传递给它pages(例如pages/"Home"/index.js):
import React, { Component } from "react";
import PropTypes from "prop-types";
class LazyLoad extends Component {
state = {
Component: null,
err: "",
};
componentDidMount = () => this.importFile();
componentWillUnmount = () => (this.cancelImport = true);
cancelImport = false;
importFile = async () => {
try {
const { default: file } = await import(
/* webpackChunkName: "[request]" */
/* webpackMode: "lazy" */
`pages/${this.props.file}/index.js`
);
if (!this.cancelImport) this.setState({ Component: file });
} catch (err) {
if (!this.cancelImport) this.setState({ err: err.toString() });
console.error(err.toString());
}
};
render = () => {
const { Component, err } = this.state;
return Component ? (
<Component {...this.props} />
) : err ? (
<p style={{ color: "red" }}>{err}</p>
) : null;
};
}
LazyLoad.propTypes = {
file: PropTypes.string.isRequired,
};
export default file => props => <LazyLoad {...props} file={file} />;
Run Code Online (Sandbox Code Playgroud)
在这一点上,React.Lazy和React-Loadable是自定义 Webpack 配置或不支持动态导入的 Webpack 版本的替代方案。
可以在此处找到工作演示。按照安装说明进行操作,然后您可以运行以查看按名称yarn build拆分的路由。
| 归档时间: |
|
| 查看次数: |
14956 次 |
| 最近记录: |