为什么我们要亲手“捏”一个 Vue 项目?

你在一家做 B 端 SaaS 的公司,产品迭代节奏极快。某天,老板突然甩来一句:"客户要私有化部署,包体必须 < 500 KB,脚手架里那些没用到的依赖全给我砍掉!"

那一刻,你深刻体会到:脚手架是"通用解",而私有化场景需要"定制解"。于是,你决定从零手搓一个 Vue 应用,既能极致瘦身,又能随时插拔功能。


解决方案:30 分钟搭出可交付的"裸奔" Vue3 项目

1. 环境准备(2 分钟)

bash 复制代码
# 🔍 用 volta 锁 Node 版本,避免"在我电脑能跑"
volta install node@20
mkdir vue-lite && cd vue-lite
npm init -y

2. 最小依赖安装(3 分钟)

bash 复制代码
# 只装运行时 + 编译时刚需
npm i vue@next
npm i -D vite @vitejs/plugin-vue

为什么选 Vite?

对比 Webpack5(webpage 3 的做法),Vite 在 dev 阶段用 esbuild 做预构建,冷启动 < 300 ms,正适合我们"边改边看"的私有化调试场景。

3. 目录结构(5 分钟)

csharp 复制代码
vue-lite
├─ public
│  └─ favicon.ico
├─ src
│  ├─ main.ts          # 应用入口
│  ├─ App.vue
│  └─ components
│     └─ Hello.vue
├─ index.html          # Vite 的"钩子"
└─ vite.config.ts

4. 核心文件代码(10 分钟)

index.html

html 复制代码
<!doctype html>
<html>
  <head>
    <title>Vue-Lite</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

vite.config.ts

ts 复制代码
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  build: {
    lib: {
      entry: 'src/main.ts',
      name: 'VueLite',
      fileName: 'vue-lite',
    },
    rollupOptions: {
      external: ['vue'], // 🔍 把 vue 打成 external,私有化时再外链 CDN
    },
  },
})

src/main.ts

ts 复制代码
import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')

src/App.vue

vue 复制代码
<template>
  <Hello />
</template>

<script setup lang="ts">
import Hello from './components/Hello.vue'
</script>

src/components/Hello.vue

vue 复制代码
<template>
  <h1>{{ msg }}</h1>
</template>

<script setup lang="ts">
const msg = 'Hello, 私有化客户!'
</script>

原理剖析:从"裸文件"到"可交付产物"的三层视角

层级 表面用法 底层机制 设计哲学
Dev 阶段 npm run dev 秒开浏览器 Vite 把 .vue 文件实时编译成 ESModule,浏览器直接 import 浏览器原生能力优先,工具链只做"翻译"
Build 阶段 npm run build 生成 dist/vue-lite.umd.js Rollup 做 tree-shaking + 代码分割,external vue 减少 80 KB 私有化场景下,业务代码与框架解耦
Runtime 阶段 客户页面 <script src="vue-lite.umd.js"></script> UMD 格式自动判断宿主环境(CommonJS / AMD / 全局) 不侵入客户构建体系,即插即用

应用扩展:把"裸奔"项目武装到牙齿

1. 插拔式路由(不打包路由库)

ts 复制代码
// src/router/index.ts
import { ref, computed } from 'vue'

const routes = {
  '/': () => import('../pages/Home.vue'),
  '/about': () => import('../pages/About.vue'),
}

export const path = ref(location.pathname)
window.addEventListener('popstate', () => (path.value = location.pathname))

export const currentView = computed(() => routes[path.value] || routes['/'])

原理:利用浏览器原生 popstate + Vue3 的响应式,实现 0 依赖路由。

场景:后台管理系统只有 3-4 个页面,无需整包 vue-router。

2. 按需引入 UI 组件(以 ElementPlus 为例)

ts 复制代码
// vite.config.ts 新增
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import Components from 'unplugin-vue-components/vite'

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

结果:按钮、表格用到多少就打包多少,未使用的组件 0 成本。

3. 私有化环境变量注入

ts 复制代码
// src/env.ts
export const API_BASE = import.meta.env.VITE_API_BASE || 'https://saas.example.com'

客户部署时只需在 Nginx 加一行:

bash 复制代码
location / {
  sub_filter 'https://saas.example.com' 'https://customer.internal';
}

举一反三:3 个变体场景实现思路

场景 关键差异 实现思路
微前端子应用 需要生命周期钩子 main.ts 导出 bootstrap / mount / unmount,用 Vite 的 library 模式打包成 systemjs 格式
低代码平台渲染器 动态组件量巨大 defineAsyncComponent + import.meta.glob 做运行时加载,配合 CDN 缓存
Chrome 插件 popup 包体 < 100 KB 关闭 Vite 的代码分割,用 build.minify='terser' + pure_funcs=['console.log'] 删除所有日志

可复用配置片段

ts 复制代码
// vite.config.ts(私有化专用)
export default defineConfig(({ command }) => ({
  base: command === 'build' ? '/static/vue-lite/' : '/', // 🔍 适配客户子路径
  plugins: [vue()],
  build: {
    rollupOptions: {
      external: ['vue'],
      output: {
        globals: { vue: 'Vue' }, // 告诉 UMD 外部依赖叫 Vue
      },
    },
  },
}))

小结

不用脚手架,不是"为了酷",而是"为了活"。当你面对包体、合规、私有化这些真实约束时,手搓项目就像给自己开了一条逃生通道:

  • 想砍依赖?直接删 package.json 一行。
  • 想换构建?Vite 换 Rollup 换 esbuild,5 分钟搞定。

下次老板再提"极限瘦身",你就可以淡定地打开这篇文章,30 分钟交差。

相关推荐
Point4 分钟前
[LeetCode] 最长连续序列
前端·javascript·算法
rookiesx8 分钟前
安装本地python文件到site-packages
开发语言·前端·python
支撑前端荣耀9 分钟前
九、把异常当回事,代码才靠谱
前端
LotteChar17 分钟前
HTML:从 “小白” 到 “标签侠” 的修炼手册
前端·html
未来之窗软件服务18 分钟前
网站访问信息追踪系统在安全与性能优化中的关键作用——网络安全—仙盟创梦IDE
安全·web安全·性能优化·仙盟创梦ide·东方仙盟
趣多多代言人19 分钟前
20分钟学会TypeScript
前端·javascript·typescript
90后的晨仔19 分钟前
⚙️ 《响应式原理》— Vue 是怎么做到自动更新的?
前端·vue.js
结城19 分钟前
深入掌握CSS Grid布局:每个属性详解与实战示例
前端·css
寒..25 分钟前
网络安全第三次作业
前端·css·html
90后的晨仔34 分钟前
🧮《计算属性》— 自动根据其它响应式数据得出结果
前端·vue.js