Vite打包从12.17M -> 7.95M,速度提升≈51.85% (面试亮点,持续编写)

2,364 阅读4分钟

面试问1:请问你平时都是如何 优化项目 or 打包 的?

优化策略:安装visualizer看图,针对大区块进行着重优化,配置vite.config,引入CDN。

亮点:针对性分析优化 + 什么手段 + 解决了什么。

最终结果

CACCD7D3-FED3-4c64-B358-2B9093D085F8.png

安装相关Npm依赖

image.png image.png

分析优化前占比图(预览图)

image.png

单条拆分优化

1、排除打包 *.json 文件 + 动态加载
image.png
2、echarts、element-plus、jsoneditor 不做外联确保稳定。(可自主选择优化)
3、通过 CDN 方式挂载:markdonwit、xlsx

推荐使用国内镜像:

  1. BootCDN: BootCDN
  2. 字节跳动: 字节跳动静态资源公共库
  3. 引用 +esm 适配 Esm模式

image.png

运行 depcheck 查看无用安装依赖

对未使用的依赖进行删除,需要确保不会对项目造成破坏,如 tailwindcss 被检测无使用,实际在使用中,故不能删除。删除后本地确保没问题,再提交!!!

  1. Unused:未使用依赖
  2. Missing:丢失依赖

image.png

打包输出配置,采用 esbuild

  1. 生产模式移除 输出/断点
  2. sourcemap:定位错误(自行选择)
  3. treeShake、cache:清理无用代码|缓存(默认true)
  4. output:命名代码分割时创建共享块
  5. external:排除不需要的打包文件/文件夹

image.png

全局引入改为局部/按需

Element-plus引入及图标
image.png image.png
路由懒加载及搭配单个Chunk
  1. 通过 import 方式载入页面地址
  2. 根据打包配置中的 output 输出为 单个Chunk,实现按需载入
image.png

面试问2:下拉列数据量 很大很卡 怎么办?有什么优化策略吗?

优化策略:节流 + 自定义插件

亮点:自定义组件封装 + 自定义插件

1、实现防抖节流

特性防抖(Debounce)节流(Throttle)
触发频率最后一次操作后延迟执行固定时间间隔内只执行一次
适用场景搜索输入、窗口大小调整、表单验证等滚动加载、按钮点击、鼠标移动等
image.png image.png

2、创建自定义指令

关键点: binding.arg 是用于区别 同页面中存在多个下拉。

image.png

3、全局挂载(如没有多复用,则页面单独使用)

import permissionDirective from './utils/permission.directive' //  引用
app.directive('el-select-loadmore', loadMores)                 // (指令名,指令)

4、El-Plus组件使用自定义指令

image.png

面试问3:平时都用什么组件? 有封装过什么吗?

1、Echarts 图表进行封装,增加自适应窗口并统一管理调用

封装策略:复用性高 传值

亮点:二次封装、减少代码冗余、统一管理、ResizeObserver、自适应窗口大小

<template>
  <div ref="chartRef" :style="{ width: width, height: height }"></div>
</template>

<script setup>
import echarts from 'echarts'
const props = defineProps(['options','width','height']

const chartRef = ref(null)
let myChart = null

// 1、初始化图表
const initChart = () => {
  if (chartRef.value) {
    if (myChart) { myChart.dispose() }
    myChart.setOption(options)
  }
}

// 2、ResizeObserver 监听容器大小变化
const resizeObserver = new ResizeObserver((entries) => {
  for (let entry of entries) {
    if (myChart && !myChart.isDisposed()) { myChart.resize() }
  }
})

// 3、装载
onMounted(() => {
  nextTick(() => {
    initChart()
    if (chartRef.value) { resizeObserver.observe(chartRef.value) }
  })
})

// 4、卸载
onUnmounted(() => {
  if (chartRef.value) { resizeObserver.unobserve(chartRef.value) }
  if (myChart && !myChart.isDisposed()) { myChart.dispose() }
})

// 5、监听 options 的变化
watch(
  () => props.options,
  (newOptions) => {
    nextTick(() => {
      if (myChart && !myChart.isDisposed()) {  myChart.setOption(newOptions) } 
      else { initChart()}
    })
  }, { deep: true }
)
</script>

2、对 ElementPlus 组件进行封装,通过传入组件方式统一管理

封装策略:复用性高 进阶Api 传值

亮点:二次封装、父子传递、统一管理、shallowRef

<template>
  <el-drawer v-model="drawer" :with-header="false" :destroy-on-close="true">
    <component :is="currentComponent" v-bind="dynamicAttrs" />
  </el-drawer>
</template>

<script lang="ts" setup>
const props = defineProps({ toToData: Object, currentComponent: Object })
const drawer = ref(false)

// 动态组件引用
const currentComponent = shallowRef(props.currentComponent)
watch(
  () => props.currentComponent,
  (newValue) => { currentComponent.value = newValue },
  { immediate: true }
)

// 动态绑定的属性
const dynamicAttrs = computed(() => { 
    return props.toToData ? { toToData: props.toToData } : {}
})

// 展开/关闭
const exchangeStatus = () => { drawer.value = !drawer.value }

defineExpose({ exchangeStatus })
provide('exchangeStatus', { exchangeStatus })
</script>


// 使用方式
  <DrawerComp
    size="35%"
    ref="draw"
    :current-component="activityManageOpContent"
    :toToData="parentData"
  ></DrawerComp>

面试问4:了解 vue3的生态吗?是如何选择的?

  1. 构建采用: v3 + vite (速度快,Tree机制)
  2. 路由状态: vue-router@4 + Pinia(轻量、TS 友好,替代 Vuex)
  3. 编码类型:强类型 TypeScript(方便定位错误类型)
  4. Ui 组件库: Element Plus
  5. CSS: Tailwind (统一全局样式 响应式布局) CSS scss(嵌套好管理)
  6. 图表/可视化: Echart

针对以上的生态提出问题:

  1. vue3 为什么比 vue2 快?

  2. vue3 可以用 vuex吗? vue2 可以用 pinia 吗?

  3. 平时都是怎么做响应式布局的?

  4. 平时都是怎么管理项目/代码的?

  5. 封装过echart吗?

后续编写记录。后续会开单独面试题。

  1. 多页面引用则单独抽离,传值配置
  2. 减少多层嵌套,提早return
  3. 命名规范,驼峰命名 + 常量大写
  4. 组件抽离及语法糖
  5. 这里不一一介绍了,看官方文件,背背理解理解,如果记不住就抄吧。组合式 API:setup() | Vue.js