开源库vue-form-design首页资源体积从3.9M到1.5M, 如何做到的?

![企业微信截图_9a2f2c80-0069-48f4-8654-e1557f724fd5.png](p6-juejin.byteimg.com

背景

打开开源项目 vue-form-design 时, 白屏时间耗时很长, 一半多可能是 github 被限速的原因, 但是通过 F12 调试发现, 首页资源有 3.9M, 假设用户的下载速度 300KB,都要 13s 多(理论情况下)

所以为了提升下开源项目预览体验,获得更多 star, 得到 jym 的认可, 性能优化刻不容缓

来看下实际优化效果

优化前:

优化后:

首页资源从 3.9M 到 1.5M, 减少了 64%

说下开源项目 vue-form-designn 的相关技术栈

  • vue3 + vite4 + typescript
  • element-plus + jsoneditor + vue-codemirrir + wangEditor

分析

开始的时候, 我发现我写的没啥问题, 引用的包确实很大, 也确实必要, 不可能删除掉.

后面知道可以利用工具进行分析, 所以安装了rollup-plugin-visualizer, 能可视化地感知到产物的体积情况

  1. 安装
js 复制代码
npm install rollup-plugin-visualizer -D
  1. vite.config.js 中使用
js 复制代码
import { visualizer } from "rollup-plugin-visualizer";
export default defineConfig({
  plugins: [
    visualizer({
      open: true, //在默认用户代理中打开生成的文件
    }),
  ],
});

这样就能在 npm run build 的时候生成 stat.html 文件, 可视化感知产物体积

我们来看下优化前的产物结果

蓝色框就是首屏资源体积, 相当于首屏加载的时候会下载所有资源

优化

拆包

从上图看到, wangEditor + jsoneditor+ codemirror 这三个包占据了首屏资源的半壁江山, 如果把这些资源进行异步加载, 那体积就减少了差不多一半

首先看下在哪里引用的 wangEditor, 发现是 starfish-form 项目下的富文本表单组件

如果把该表单组件作为异步组件, 那等同于 wangEditor 异步加载

在这里我们需要了解一个知识点, vue3 如何实现异步组件的

js 复制代码
import { defineAsyncComponent } from "vue";

const AsyncComp1 = defineAsyncComponent(() => import("./components/MyComponent1.vue"));

实现如下

js 复制代码
// 富文本
const RichText = defineAsyncComponent(() => import("./components/RichText/index.vue"));
RichText.ControlType = "RichText"; // 必须与文件名匹配
RichText.nameCn = "富文本";
RichText.icon = "icon-textEdit";
RichText.formConfig = getFormConfig("RichText");

为什么后面要跟其他字段?

原来这些字段是绑定到组件内部的

如:

js 复制代码
defineComponent({
    ControlType: "RichText", // 必须与文件名匹配
    nameCn: "富文本",
    icon: "icon-textEdit",
    formConfig: getFormConfig("RichText"),
}

但是现在作为异步组件, 就访问不到组件内部的值, 只能在创建异步组件的地方进行绑定

这样参数能不要吗? 可以不要, 看个人的实现, 目的是渲染出组件列表

这样就把 wangEditor 抽离出去了

如何抽离 jsoneditor? 也是一样的步骤吗?

jsoneditor 是全局进行导入的, 然后组件内部直接使用

js 复制代码
import JSONEditor from "jsoneditor";

window.JSONEditor = JSONEditor;

这样就必须在组件内部单个导入, 这样又有一个问题? 单个导入的地方首屏确实会加载, 那怎么办?

html 复制代码
<el-tab-pane label="JSON配置" name="json">
  <div class="json">
    <div ref="jsonCenter"></div>
  </div>
</el-tab-pane>

和首页耦合到一起的

那我们把该模块抽离出去作为一个单独的组件, 同时该组件异步引入, 到这一步还不算完, 就算异步引入了, 但是首屏还是会渲染到该异步组件, 那我们就不让首屏渲染到, 就需要使用到 v-if 了, 惰性加载, 如果为 false, 就不渲染

改造后的代码如下

html 复制代码
<el-tab-pane label="JSON配置" name="json">
  <div class="json" v-if="activeName == 'json'">
    <jsonEnter ref="jsonCenter" />
  </div>
</el-tab-pane>
js 复制代码
defineComponent({
  components: {
    jsonEnter: defineAsyncComponent(() => import("./jsonEditor.vue")),
  }}

同理, vue-codemirrir 组件我们也可以使用上方相同的方法, 异步组件和惰性加载, 这样 vite 打包的时候会单独打包到一个文件中

这其中遇到了一个问题, 优化前是直接全局注册所以 starfish-form 项目没有安装 vue-codemirror,因为 vue-form-design 是 monorepo 项目, 如果要拆包所以两个项目 starfish-editor 和 starfish-form 都要安装 vue-codemirrir, 所以有个时间差,导致安装的版本不同

导致拆包后出现了两个 vue-codemirrir 文件

所以我们需要保证两个项目的相同包的版本一致性

组件按需加载

在项目中很多公共组件都是全局直接注册的, 会导致在首屏中加载不需要的公共组件

表单编辑器中

js 复制代码
app.component("CustomDialog", CustomDialog);
app.component("ConditionSelect", ConditionSelect);
app.component("HighConditionSelect", HighConditionSelect);
app.component("draggable", draggable);
app.component("Shape", Shape);
app.component("FormStyle", FormStyle);
app.component("StarfishEditor", Editor);

这些组件中有些是通过点击某个按钮后进行弹窗展示, 首屏是不会展示出来, 所以分析下哪些需要作为异步组件

动态表单渲染中, 所有表单也是直接注册的, 我们是不是可以都作为异步组件, 因为首屏肯定是不会渲染的

如:

js 复制代码
// 规则
const Rule = defineAsyncComponent(() => import("./components/Rule/index.vue"));
Rule.ControlType = "Rule"; // 必须与文件名匹配
Rule.rule = _.getJsonValidate();
utilFuns[Rule.ControlType] = Rule;

但是因为工作量大, 同时有些组件体积很小, 不是很有必要作为异步组件, 只抽离了其中比较大的组件

公共组件库按需导入

vue-form-design 使用的组件库是 element-plus, 是直接全局注册的

js 复制代码
app.use(ElementPlus, {
  locale: zhCn,
});

导致其中没有使用到的组件也一起导入了

我们使用如下方法就能按需且自动导入

js 复制代码
import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";

{
plugins: [
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [ElementPlusResolver()],
    }),
  ],
}

实现了体积从1.3M 到 650Kb

还有如路由懒加载, 在开发初期就是这样做的, 如cdn加速, 没钱, 也懒得用网上现有的

总结

以上差不多都是把首屏不需要的资源进行拆包, 减少js体积, 不过效果也挺大的. 同时也认识到可视化分析代码体积的重要性和必要性, 希望对大家有些思考.

github 地址

预览

相关推荐
新缸中之脑6 分钟前
Llama 3.2 安卓手机安装教程
前端·人工智能·算法
hmz8569 分钟前
最新网课搜题答案查询小程序源码/题库多接口微信小程序源码+自带流量主
前端·微信小程序·小程序
看到请催我学习16 分钟前
内存缓存和硬盘缓存
开发语言·前端·javascript·vue.js·缓存·ecmascript
blaizeer1 小时前
深入理解 CSS 浮动(Float):详尽指南
前端·css
速盾cdn1 小时前
速盾:网页游戏部署高防服务器有什么优势?
服务器·前端·web安全
小白求学11 小时前
CSS浮动
前端·css·css3
什么鬼昵称1 小时前
Pikachu-csrf-CSRF(POST)
前端·csrf
XiaoYu20022 小时前
22.JS高级-ES6之Symbol类型与Set、Map数据结构
前端·javascript·代码规范
golitter.2 小时前
Vue组件库Element-ui
前端·vue.js·ui
道爷我悟了2 小时前
Vue入门-指令学习-v-on
javascript·vue.js·学习