阿卡不拉阿卡不拉
Vue3
阿卡的博客
Vue3
阿卡的博客
  • Vue3

    • 快速入门

      • 搭建工程 👌
      • 模板语法
      • 响应式基础
      • 响应式常用 API
      • 计算属性
      • 类与样式绑定
      • 条件和列表渲染
      • 事件处理
      • 表单处理
      • 生命周期
      • 侦听器
      • 组件介绍
      • Props
      • 自定义事件
      • 组件v-model
      • 插槽
      • 前端路由介绍
      • KeepAlive内置组件
      • 状态管理库
      • 组件库介绍
    • 深入本质

      • 虚拟DOM本质
      • 模板的本质
      • 组件树和虚拟DOM树
      • 数据拦截的本质
      • 响应式数据的本质
      • 响应式的本质
      • 响应式和组件渲染
      • 实现响应式系统 1
      • 实现响应式系统 2
      • 图解EFFECT
      • 实现响应式系统 3
      • 手写computed
      • 手写watch
      • 指令的本质
      • 插槽的本质
      • v-model的本质
      • setup 语法标签
      • 组件生命周期
      • keepalive 生命周期
      • keepalive的本质
      • key的本质
    • 细节补充

      • 【Vue】属性透传
      • 【Vue】依赖注入
      • 【Vue】组合式函数 👌
      • 【Vue】自定义指令
      • 【Vue】插件
      • 【Vue】Transition
      • 【Vue】TransitionGroup
      • 【Vue】Teleport
      • 【Vue】异步组件
      • 【Vue】Suspense
      • 【Router】路由模式
      • 【Router】路由零碎知识
      • 【Router】路由匹配语法
      • 【Router】路由组件传参
      • 【Router】内置组件和函数
      • 【Router】导航守卫
      • 【Router】过渡特效
      • 【Router】滚动行为
      • 【Router】动态路由
      • 【State】通信方式总结
      • 【State】Pinia 自定义插件
      • 【场景】封装树形组件
      • 【场景】自定义 ref 实现防抖
      • 【场景】懒加载
      • 【场景】虚拟列表
      • 【场景】虚拟列表优化
      • 【第三方库】VueUse
      • 【第三方库】vuedragable
      • 【第三方库】vue-drag-resize
      • 【第三方库】vue-chartjs
      • 【第三方库】vuelidate
      • 【第三方库】vue3-lazyload
      • 【场景】Websocket 聊天室
      • 【Vite】✨ 认识 Vite👌
      • 【Vite】配置文件 👌
      • 【Vite】✨ 依赖预构建 👌
      • 【Vite】构建生产版本 👌
      • 【Vite】环境变量与模式
      • 【Vite】CLI
      • 【Vite】Vite 插件
  • 笔面试

    • HTML

      • HTML 面试题汇总
      • 文档声明
      • 语义化
      • W3C 标准组织
      • SEO
      • iframe
      • 微格式
      • 替换元素
      • 页面可见性
    • CSS

      • CSS 面试题汇总
      • CSS 单位总结
      • 居中方式总结
      • 隐藏元素方式总结
      • 浮动
      • 定位总结
      • BFC
      • CSS 属性计算过程
      • CSS 层叠继承规则总结
      • @import 指令
      • CSS3 calc 函数
      • CSS3 媒体查询
      • 过渡和动画事件
      • 渐进增强和优雅降级
      • CSS3 变形
      • 渐进式渲染
      • CSS 渲染性能优化
      • 层叠上下文
      • CSS3 遮罩
    • JavaScript

      • JavaScript 面试题汇总
      • ✨ let、var、const 的区别
      • JS中的数据类型
      • 包装类型
      • 数据类型的转换
      • 运算符
      • ✨ 原型链
      • ✨ this 指向
      • ✨ 垃圾回收与内存泄漏
      • ✨ 执行栈和执行上下文
      • ✨ 作用域和作用域链
      • ✨ 闭包
      • DOM 事件的注册和移除
      • DOM 事件的传播机制
      • 阻止事件默认行为
      • 递归
      • ✨ 属性描述符
      • class 和构造函数区别
      • 浮点数精度问题
      • 严格模式
      • ✨ 函数防抖和节流
      • ✨ WeakSet 和 WeakMap
      • ✨ 深浅拷贝
      • 函数柯里化
      • Node 事件循环
      • 尺寸和位置
    • 浏览器

      • 浏览器面试题汇总
      • ✨ 浏览器的渲染流程
      • ✨ 资源提示关键词
      • 浏览器的组成部分
      • IndexedDB
      • ✨ File API
      • ✨ 浏览器缓存
      • ✨ 浏览器跨标签页通信
      • Web Worker
    • 网络

      • 网络面试题汇总
      • 五层网络模型 👌
      • 常见请求方法 👌
      • ✨cookie👌
      • 面试题
      • 加密
      • ✨JWT👌
      • ✨ 同源策略及跨域问题 👌
      • 文件上传
      • ✨ 输入 url 地址之后
      • 文件下载
      • ✨ session
      • ✨ TCP
      • ✨ CSRF 攻击
      • ✨XSS 攻击 👌
      • ✨ 网络性能优化
      • 断点续传
      • 域名和 DNS
      • SSL、TLS、HTTPS 的关系
      • ✨ HTTP 各版本差异 👌
      • HTTP 缓存协议
      • ✨ WebSocket
    • 工程化

      • CMJ 和 ESM
      • npx
      • ESLint
    • Vue2

      • Vue 面试题汇总相关
      • 组件通信方式总结
      • 虚拟 DOM
      • v-model
      • 数据响应式原理
      • diff
      • 生命周期详解
      • computed
      • 过滤器
      • 作用域插槽
      • 过度和动画
      • 优化
      • keep-alive
      • 长列表优化
      • 其他 API
      • 模式和环境变量
      • 更多配置
      • 更多命令
      • 嵌套路由
      • 路由切换动画
    • Vue3

      • ✨ Vue3 整体变化 👌
      • ✨ Vue3 响应式变化 👌
      • ✨ nextTick 实现原理 👌
      • 两道代码题 👌
      • Vue 运行机制
      • 渲染器核心功能
      • 事件绑定与更新

【Vite】构建生产版本 👌

构建工具

不同于 依赖预构建 用到的 esbuild,生产构建使用的工具是 rollup. 因为 rollup 提供了一些特性和优势,特别适合用于生产环境的代码打包和优化。

1. 代码分割和动态导入

rollup 支持高级的代码分割和动态导入功能,这对于现代前端应用尤为重要。它能够处理复杂的导入场景,例如循环依赖和动态模块路径,确保最终打包的文件大小最小且模块之间的依赖正确处理。这些功能在大型应用中可以显著提高加载性能和用户体验。

2. Tree Shaking

虽然 esbuild 也支持 tree shaking,但 rollup 的 tree shaking 能力通常被认为更为强大和精准。rollup 能够更有效地识别并剔除未使用的代码,这对于减少最终生产包的体积至关重要。

3. 插件生态

rollup 拥有一个成熟且广泛的插件生态系统,这使得开发者可以轻松地扩展其构建过程,以适应各种复杂和特定的构建需求。例如,可以通过插件支持各种 CSS 预处理器、图片优化、国际化等。这种灵活性对于生产环境的构建配置是非常有价值的。

4. 输出控制和优化

rollup 提供了更细粒度的控制输出格式和结构的功能,这对于需要精确控制文件结构和模块化方式的现代应用开发非常重要。例如,rollup 可以生成更为优化的 ES 模块代码,这有助于在现代浏览器中实现更好的性能。

5. 生产优化

虽然 esbuild 的构建速度非常快,但在生产环境中,构建速度虽重要,代码质量和优化程度更为关键。rollup 在这方面提供了更多的优化策略,如更复杂的代码分割和加载策略,这有助于提高应用的性能和可维护性。

总结起来:不同环境下的打包,我们的目标是不一样

  • 开发环境:追求的是构建速度
  • 生产环境:更多考虑的是打包出来的代码的质量

自定义构建

如果仅仅是要把项目构建为生产版本,那非常简单,直接 npm run build 即可,背后运行的是 vite build

"scripts": {
  "build": "vite build",
},

不过构建生产版本时经常有一些自定义的需求,此时在配置文件里面的 build 配置项进行配置,一个基本的格式如下:

export default defineConfig({
    build: {
        // 构建相关的配置
    },
});

这里介绍一些常用的配置。

1. target

该配置项用于定义最终构建产物的 JS 版本和浏览器兼容性。这个设置非常关键,因为它直接影响到代码在不同环境中的运行能力以及可能需要的转译级别。我们来看几个例子

例子 1:默认设置

build.target 的默认值是 modules,这意味着构建出来的产物适用于现代支持 ESM 的浏览器,对应的浏览器版本:

  • Edge 88+
  • Firefox 78+
  • Chrome 87+
  • Safari 14+

例子 2:指定 ES 版本

export default defineConfig({
    build: {
        target: "es2015",
    },
});

例子 3:支持特定浏览器版本

export default defineConfig({
    build: {
        target: "chrome58",
    },
});

例子 4:多目标设置

export default defineConfig({
    build: {
        target: ["es2020", "firefox78", "chrome87"],
    },
});

注意事项

  • esbuild 虽然很快(编译过程是 esbuild 做的),但可能不支持某些复杂的或尚未广泛采用的 JS 特性。如果遇到了这一类 esbuild 不支持的特性,那么需要是 Babel 来做一个补充编译。
  • 更改 build.target 会影响构建的输出大小和性能

2. outDir

用于指定构建产物的目录,默认是项目根目录下的 dist.

3. assetsDir

指定生成静态资源的存放路径,默认是 dist/assets.

4. cssMinify

build.cssMinify 配置项允许你单独控制 CSS 文件的最小化压缩方式,独立于 JS 的压缩设置。这个选项在优化构建输出时非常有用,尤其是当你需要精确控制 CSS 和 JS 压缩策略时。下面来举一些例子:

例子 1:默认行为

默认是使用 esbuild 来做 CSS 的压缩

例子 2:使用 Lightning CSS 压缩 CSS

import { defineConfig } from "vite";

export default defineConfig({
    build: {
        cssMinify: "lightningcss",
    },
});

例子 3:禁用 CSS 压缩

import { defineConfig } from "vite";

export default defineConfig({
    build: {
        cssMinify: false,
    },
});

例子 4:独立配置 JS 和 CSS 压缩

import { defineConfig } from "vite";

export default defineConfig({
    build: {
        cssMinify: "esbuild", // CSS压缩使用esbuild
        minify: "terser", // JS压缩使用 terser
    },
});

5. minify

build.minify 用于控制构建过程中的 JS 代码压缩和混淆,这个设置对于优化生产环境的代码尺寸和性能至关重要。

默认使用 esbuild 来进行压缩,它比 terser 快 20-40 倍,压缩率只差 1%-2%

如果你需要更高级的压缩选项,或者在某些情况下 esbuild 的压缩结果不符合你的需求,你可以选择使用 terser。

terser 提供了更细致的控制和稍微更好的压缩率,尽管它的速度较慢。

npm install terser -D
import { defineConfig } from "vite";

export default defineConfig({
    build: {
        minify: "terser", // JS压缩使用 terser
    },
});

6. sourcemap

构建后是否生成 source map 文件。

  • 如果为 true,将会创建一个独立的 source map 文件
  • 如果为 inline,source map 将作为一个 data URI 附加在输出文件中。
  • hidden 的工作原理与 true 相似,只是 bundle 文件中相应的注释将不被保留。

7. rollupOptions

因为底层使用的是 rollup 进行打包,因此支持所有的 rollup 配置选项。

rollupOptions 配置项对应是一个对象,该对象和 rollup 配置文件导出的选项相同。

示例:

  1. 添加一个 rollup 插件来处理图像
  2. 指定 some-external-lib 为外部依赖
  3. 为这个外部依赖提供一个可访问的全局变量 SomeExternalLib

配置如下:

import { defineConfig } from 'vite';
import image from '@rollup/plugin-image'; // 假设这是一个用于处理图像的 Rollup 插件

export default defineConfig({
  build: {
    rollupOptions: {
      plugins:[
        images() // 通过这个rollup插件来处理图像
      ],
      external: ['some-external-lib'] // 指定some-external-lib为外部依赖,不会被打包进去
      output: {
      	globals: {
      	  'some-external-lib': 'SomeExternalLib'
    	}
      }
    }
  }
})

公共基础路径

该配置项不属于 build 里面的配置项,但也是一个非常重要的配置项,主要用于配置开发环境和生产环境的基本公共路径。

  • 类型:string
  • 默认值:/
  • 描述:用于配置开发环境和生产环境的基本公共路径,有效值包括:
    • 绝对 URL 路径名,例如 /foo/
    • 完整 URL,例如 https://bar.com/foo/(开发环境中不会使用 origin 部分,因此其值与 /foo/ 相同)
    • 空字符串或 ./(用于嵌入式部署)

举例:

my-project/
├── public/
│   └── index.html
├── src/
│   ├── main.js
│   └── App.vue
├── vite.config.js
└── package.json

配置文件:

// vite.config.js
import { defineConfig } from "vite";

export default defineConfig({
    base: "/my-app/", // 设置基本公共路径为 '/my-app/'
});

之后要访问静态资源的时候,全部会以 /my-app/作为前缀

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>My App</title>
    </head>
    <body>
        <script type="module" src="/my-app/src/main.js"></script>
    </body>
</html>

假设项目打包:

my-project/
├── dist/
│   ├── assets/
│   │   ├── main.12345.js
│   │   └── style.67890.css
│   └── index.html
└── vite.config.js

dist/index.html,要访问静态资源,也需要添加公共路径:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>My App</title>
        <link rel="stylesheet" href="/my-app/assets/style.67890.css" />
    </head>
    <body>
        <script type="module" src="/my-app/assets/main.12345.js"></script>
    </body>
</html>

思考 🤔:为什么要配置这么一个路径?

答案:因为有些时候我们的应用并非部署在根目录下面,而是部署在某一个子路径或者子目录下面,这个时候就需要通过 base 保证你的静态资源能够正确被加载。

库模式

库模式指的是将应用打包成一个依赖库,方便其他应用来使用。这里可以在 lib 配置项里面进行配置:

// vite.config.js
import { resolve } from "path";
import { defineConfig } from "vite";

export default defineConfig({
    build: {
        lib: {
            // ....
        },
    },
});

和普通模式区别:

  1. 入口文件
    • 普通应用:一般是 index.html,所有的资源从这个入口 HTML 文件开始加载。
    • 库模式:入口文件通常是一个 JS 文件,因为库通常是作为一个资源被其他项目引用
  2. 输出格式
    • 普通应用:通过只针对特定的运行环境(大多数浏览器支持即可)进行打包
    • 库模式:往往需要支持多种模块系统,包括 UMD、ESM、CommonJS 这些类型。
  3. 外部依赖
    • 普通应用:将所有的依赖打包到一个或者多个文件里面
    • 库模式:往往需要将外部依赖排除掉

总结:在库模式中,需要配置入口点、库的名称、输出文件名,以及如何处理外部依赖。这些配置确保库被打包成适用于不同消费场景的格式。

假设有如下的项目目录:

my-lib/
├── lib/
│   ├── main.js        // 库的入口文件
│   ├── Foo.vue        // Vue 组件
│   └── Bar.vue        // 另一个 Vue 组件
├── index.html         // 用于开发测试的 HTML 文件
├── package.json
└── vite.config.js     // Vite 配置文件

接下来我们要将其打包成一个库,配置文件如下:

// vite.config.js
import { resolve } from "path";
import { defineConfig } from "vite";

export default defineConfig({
    build: {
        lib: {
            entry: resolve(__dirname, "lib/main.js"),
            name: "MyLib",
            fileName: (format) => `my-lib.${format}.js`,
        },
        rollupOptions: {
            external: ["vue"],
            output: {
                globals: {
                    vue: "Vue",
                },
            },
        },
    },
});
  • entry: 指定库的入口文件
  • name:指定你的库在 UMD 或者 IIFE 环境下的全局变量的名称
  • fileName: 最终生成的文件的文件名
  • external:排除哪些外部依赖
  • globals:外部依赖在 UMD 或者 IIFE 格式下全局变量的名称

配置文件完成后,就可以通过 vite build 进行库模式的构建

my-lib/
├── dist/
│   ├── my-lib.es.js        // ES 模块格式
│   ├── my-lib.umd.js       // UMD 格式
│   └── assets/             // 包含所有静态资源,如编译后的 CSS
└── ...

构建出来的产物是多种格式,因为要应对不同的环境下使用这个库。

最后还有一个非常重要的步骤:需要在 package.json 里面去配置不同环境的入口文件

{
    "name": "my-lib",
    "type": "module",
    "files": ["dist"],
    "main": "./dist/my-lib.umd.js",
    "module": "./dist/my-lib.es.js",
    "exports": {
        ".": {
            "import": "./dist/my-lib.es.js",
            "require": "./dist/my-lib.umd.js"
        }
    }
}
最近更新:: 2025/7/16 13:47
Contributors: AK
Prev
【Vite】✨ 依赖预构建 👌
Next
【Vite】环境变量与模式