webpack之代码分割和动态import

1、安装babel插件

npm install @babel/plugin-syntax-dynamic-import --save-dev

2、添加配置.babelrc(ES6: 动态import目前还没有原生支持,需要babel转换)

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

    ...
}

结果如下所示,数字开头的js是懒加载的id:

<think>我们已经在之前的回答中讨论了Webpack代码分割的基本方法,现在用户特别询问Webpack 5中的具体实现方法。根据引用[2]引用[3],我们知道Webpack 5继续使用`optimization.splitChunks`配置以及动态导入来实现代码分割。此外,引用[4]提到了使用魔法注释(如`webpackChunkName`)来设置动态导入的块名称。 在Webpack 5中,代码分割的主要方法包括: 1. **配置`optimization.splitChunks`**:用于提取公共模块(包括来自node_modules的第三方库业务代码中的公共模块)到单独的chunk。 2. **使用动态导入Dynamic Imports)**:通过`import()`语法实现按需加载,Webpack会自动将动态导入的模块分割成单独的chunk。 3. **使用魔法注释(Magic Comments)**:在动态导入时,通过注释来指定chunk的名称、模式等。 下面将详细说明这些方法在Webpack 5中的使用。 ### 1. 使用`optimization.splitChunks`配置 在Webpack 5中,`splitChunks`的配置与Webpack 4类似,但有一些默认配置的调整。以下是一个典型的配置示例: ```javascript module.exports = { // ... 其他配置 optimization: { splitChunks: { chunks: 'all', // 对所有类型的chunk进行分割(包括异步非异步) minSize: 20000, // 生成chunk的最小体积(单位:字节),默认20000(20KB) minRemainingSize: 0, // 确保拆分后剩余的最小chunk大小,默认为0(在Webpack 5中引入) minChunks: 1, // 模块被引用次数 maxAsyncRequests: 30, // 按需加载时的最大并行请求数 maxInitialRequests: 30, // 入口点的最大并行请求数 enforceSizeThreshold: 50000, // 强制执行拆分的体积阈值(单位:字节) cacheGroups: { defaultVendors: { test: /[\\/]node_modules[\\/]/, // 匹配node_modules中的模块 priority: -10, // 优先级,数值越大优先级越高 reuseExistingChunk: true, // 如果当前chunk包含已从主bundle中拆分出的模块,则重用该chunk }, default: { minChunks: 2, // 被两个及以上chunk引用的模块 priority: -20, reuseExistingChunk: true, }, }, }, }, }; ``` **说明**: - `cacheGroups`是配置的核心,用于定义如何拆分代码块。`defaultVendors`通常用于拆分`node_modules`中的第三方库,而`default`则用于拆分应用中的公共模块。 - `priority`属性用于解决模块同时满足多个缓存组条件时的冲突,优先级高的缓存组会优先处理。 ### 2. 动态导入Dynamic Imports) 动态导入Webpack实现按需加载的关键。在Webpack 5中,我们可以使用ES2020的`import()`语法来实现动态导入。 **示例**: ```javascript // 在需要的时候加载模块 button.addEventListener('click', () => { import('./moduleA') .then(({ default: moduleA }) => { moduleA.doSomething(); }) .catch(err => { console.error('模块加载失败', err); }); }); ``` Webpack会将`moduleA`及其依赖打包到一个单独的chunk中,并在用户点击按钮时按需加载。 ### 3. 魔法注释(Magic Comments) 在动态导入时,我们可以使用魔法注释来指定chunk的名称、加载模式等。 **示例**: ```javascript import( /* webpackChunkName: "my-chunk-name" */ /* webpackPrefetch: true */ // 预获取(在浏览器空闲时加载) /* webpackPreload: true */ // 预加载(与父chunk并行加载) './moduleB' ).then(moduleB => { // ... }); ``` - `webpackChunkName`:为生成的chunk指定一个名称,这样在输出时文件名会更清晰(例如:`my-chunk-name.[contenthash].js`)。 - `webpackPrefetch`:告诉浏览器在空闲时间预取该资源,通常用于未来可能用到的资源。 - `webpackPreload`:告诉浏览器该资源需要与父chunk并行加载,适用于当前导航中可能需要的资源。 ### 示例项目配置 以下是一个Webpack 5配置文件的完整示例,包括代码分割的设置: ```javascript const path = require('path'); module.exports = { mode: 'production', entry: './src/index.js', output: { filename: '[name].[contenthash].js', path: path.resolve(__dirname, 'dist'), clean: true, // 在每次构建前清理输出目录 }, optimization: { splitChunks: { chunks: 'all', minSize: 20000, minRemainingSize: 0, minChunks: 1, maxAsyncRequests: 30, maxInitialRequests: 30, enforceSizeThreshold: 50000, cacheGroups: { vendors: { test: /[\\/]node_modules[\\/]/, priority: -10, reuseExistingChunk: true, filename: 'vendors.[contenthash].js' // 可以指定输出文件名 }, common: { minChunks: 2, priority: -20, reuseExistingChunk: true, filename: 'common.[contenthash].js' } } }, runtimeChunk: 'single', // 将运行时代码拆分为单独的chunk,避免因模块标识符变化导致哈希值变化 }, }; ``` ### 总结 在Webpack 5中实现代码分割主要依靠: 1. **`optimization.splitChunks`配置**:自动拆分公共模块。 2. **动态导入**:使用`import()`语法实现按需加载。 3. **魔法注释**:增强对动态导入chunk的控制。 这些方法协同工作,可以有效减少初始加载时间,提升应用性能[^1][^2][^3][^4]。 §§相关问题§§ 1. Webpack 5中如何配置Tree Shaking? 2. 在Webpack 5中如何使用持久化缓存? 3. Webpack 5与Webpack 4在代码分割上有哪些区别?</think>在 Webpack 5 中实现代码分割主要通过以下三种核心方法实现,这些方法协同工作可显著提升应用性能: ### 1. 动态导入 (Dynamic Imports) 使用 ES2020 的 `import()` 语法实现按需加载,Webpack 会自动分割代码块: ```javascript // 基础用法(自动生成chunk名) button.addEventListener('click', () => { import('./module.js') .then(module => module.doSomething()) .catch(error => console.error('加载失败', error)) }); // 使用魔法注释定制 import(/* webpackChunkName: "chart" */ './charting-library') .then(({ drawChart }) => drawChart()) ``` **魔法注释选项**: - `webpackChunkName`:自定义 chunk 名称(输出文件名) - `webpackPrefetch`:空闲时预加载(`<link rel="prefetch">`) - `webpackPreload`:与父模块并行加载(`<link rel="preload">`) ### 2. 配置 optimization.splitChunks(核心方法) 在 `webpack.config.js` 中配置代码分割策略: ```javascript module.exports = { optimization: { splitChunks: { chunks: 'all', // 分割所有类型chunk(async/initial/all) minSize: 20000, // 最小分割体积(20KB) maxSize: 0, // 无最大限制 minChunks: 1, // 被引用次数阈值 cacheGroups: { // 提取node_modules模块 vendors: { test: /[\\/]node_modules[\\/]/, name: 'vendors', priority: 10 // 优先级高于default }, // 提取公共业务模块 commons: { name: 'commons', minChunks: 2, // 至少被2个入口引用 reuseExistingChunk: true } } }, runtimeChunk: { // 分离webpack运行时文件 name: entrypoint => `runtime-${entrypoint.name}` } } } ``` ### 3. 多入口分割 通过多个入口点显式分割代码: ```javascript module.exports = { entry: { app: './src/app.js', admin: './src/admin.js' }, output: { filename: '[name].bundle.js', path: __dirname + '/dist' } } ``` ### 最佳实践配置(Webpack 5 推荐) ```javascript // webpack.config.js module.exports = { optimization: { splitChunks: { chunks: 'all', minSize: 30000, // 30KB以上模块才分割 maxAsyncRequests: 5, // 异步请求最大并行数 maxInitialRequests: 3, // 入口最大并行数 automaticNameDelimiter: '-', cacheGroups: { reactVendor: { test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/, name: 'react-vendor', chunks: 'all' }, utilityVendor: { test: /[\\/]src[\\/]utils[\\/]/, name: 'utility', minChunks: 2 } } } } } ``` ### 效果说明 - **初始加载优化**:主包体积减少 40-60% - **缓存利用率提升**:第三方库单独打包,哈希不变可长期缓存 - **按需加载**:非关键功能延迟加载,如: ```javascript // 用户交互时才加载图表库 reportButton.addEventListener('click', () => { import(/* webpackPrefetch: true */ './charting').then(...) }); ``` > **性能提示**:结合 `webpack-bundle-analyzer` 分析包组成,调整分割策略[^1][^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值