使用webpack的require.context按需打包
2020/3/1 11:15:10
本文主要是介绍使用webpack的require.context按需打包,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
前端性能优化中有一个关键点就是:减少打包体积
目前常用的按需打包组件的方式有如下几种:
-
手工
import
所有需要打包的组件;目前大部分前端 ui 库都使用的这种方式,在入口文件处导出所有的组件。 -
使用 Lerna 将每个库单独打包,单独发布:
vue-next
等都使用此种方式,在宿主工程手动引入所需package
那么还有没有其他的方式,做到按需打包呢?答案是有的
一、 分析场景
现有如下一个工程目录:
├─App.vue ├─assets │ └─logo.png ├─components │ └─HelloWorld.vue ├─main.js ├─packages //存放所有组件 │ ├─button │ │ ├─button-prop.vue //设计态组件的vue │ │ └─button.vue //运行时组件的vue │ └─input │ ├─input-prop.vue │ └─input.vue ├─require.js //使用webpack的require.context自动读取packages目录下的组件 └─widget-render.js //运行态组件打包 复制代码
我的工程目录下所有的组件都存放在packages
目录下。每一个组件又分为:
- 设计态的组件的属性配置面板
- 运行态组件
现在我的要求是:
使用
require.context
自动读取packages
目录下的运行态组件,并打包发布。不允许打包设计态组件
二、解决方案
1. 手动使用 import 逐个引入
// widget-render.js import button from "./packages/button.vue"; import input from "./packages/input.vue"; ... 复制代码
显然这不符合我的要求:使用 require.context
自动读取
2. 使用 lerna 管理
使用 lerna 管理,此处不做详情赘述;lerna 管理会将 packages 目录下的组件单独发布成一个包。但是会让用户在用户侧手动import
多个组件(当然您也可以说 自己创建一个 index.js 做全局引入)。但是这似乎也不太符合我们的要求。
2. 使用 webpack 的 alias+externals 实现
首先我们先查看一下widget-render.js
和require.js
的内容:
其主要工作就是使用 require.context 去加载所有的 vue 组件,并同步注册发布
//require.js import endsWith from "lodash/endsWith"; /** * 加载组件和组件的属性面板 * @param {*} ignoreProps */ export default function(ignoreProps = false) { let components = [], propComponents = []; const requireAll = context => context.keys().map(context); const component = require.context("./packages", true, /\.vue$/); requireAll(component).forEach(file => { let item = file.default; if (endsWith(item.name, "prop") && !ignoreProps) { propComponents.push({ key: item.name, value: item }); } else if (!endsWith(item.name, "prop") && item.name) { components.push({ key: item.name, value: item }); } }); return { components, propComponents }; } 复制代码
import getAllWidgets from "./require"; // 如果你只需要打包组件的话,而忽略属性面板 const widgets = getAllWidgets(true).components; export { widgets }; export default { widgets }; 复制代码
(1)默认打包 lib
"scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build", "lint": "vue-cli-service lint", "lib": "vue-cli-service build --mode lib --target lib src/widget-render.js -name render.js --dest dist-lib" } 复制代码
运行
yarn lib --report 复制代码
其打包的结果为:是包含了prop.vue文件的
展示效果为:
疑问?
为什么,明明打包出来的组件没有
prop
,但是为何 report 文件中却存在prop.vue
相关文件呢?
答案
因为 webpack 的
require.context
会自动去加载packages
目录下的指定文件,由于上面写的匹配规则为.vue\。所以也会加载 prop 结尾的文件。并打包到 lib 中。
(2) 使用 alias+externals 打包
上面讲到使用默认的 require.context 会将匹配到的文件都统一打包的,那么肯定有朋友说,我把匹配规则写成匹配非 prop 结尾的文件。不就可以了吗? 欢迎尝试。
解决办法:
既然以 prop 结尾的文件被打包,那么我们是不是可以利用 webpack 自带的 externals 去排除掉呢?同时将所有以 prop 结尾的文件都设置别名。这样打包即可。
//vue.config.js module.exports = { productionSourceMap: false, configureWebpack: config => { if (process.env.BUILD_TARGET === "lib") { // 将所有匹配的文件都设置一个empty-widget的别名 config.resolve.alias[/^(\.\/).+(-prop.vue)/] = "empty-widget"; // 然后利用externals的function模式,对匹配到的文件设置external config.externals = [].concat(config.externals || [], [ function(context, request, callback) { if (/^(\.\/).+(-prop.vue)/.test(request)) { return callback(null, "empty-widget"); } callback(); } ]); } } }; 复制代码
其打包的结果为:不存在prop文件了
展示效果为:
最后只需要在宿主工程引入一个yarn add empty-widget
即可。empty-widget
的体积 19B,可以忽略不计哦。
最后: 其核心思想就是使用占位符的方式,将不需要的打包组件进行占位,从而减少打包体积
这篇关于使用webpack的require.context按需打包的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-10-04el-table 开启定时器下,表格的选中状态会消失是什么原因-icode9专业技术文章分享
- 2024-10-03如何安装和初始化飞牛私有云 fnOS?-icode9专业技术文章分享
- 2024-10-03如何安装 App 并连接到飞牛 NAS?-icode9专业技术文章分享
- 2024-10-03如何安装飞牛 TV 并连接到影视服务器?-icode9专业技术文章分享
- 2024-10-03如何在PVE和ESXI上安装飞牛私有云 fnOS?-icode9专业技术文章分享
- 2024-10-03fnOS国产最强NAS安装系统异常情况处理-icode9专业技术文章分享
- 2024-10-03飞牛NAS如何创建存储空间?-icode9专业技术文章分享
- 2024-10-03fnOS国产最强NAS硬盘会自动休眠吗?-icode9专业技术文章分享
- 2024-10-03fnOS国产最强NAS如何安装飞牛影视和创建媒体库?-icode9专业技术文章分享
- 2024-10-03fnOS国产最强NAS如何为家人朋友开通影视账号?-icode9专业技术文章分享