vite入门笔记

87 阅读6分钟

Vite

是一种新型前端构建工具,能够显著提升前端开发体验。它主要由两部分组成:

构建工具

什么是构建工具

构建工具是一个把源代码生成可执行应用程序的过程自动化的程序,构建包括编译、连接跟把代码打包成可用的或可执行的形式

构建工具能做什么

  • 代码转化(ts ==> js, Vue/React代码 ==》 js)
  • 代码降级(babel实现es6 ==> es5转换)
  • Less/Sass等语言转换
  • 代码压缩
  • 模块化语法编译
  • 代码分割
  • 热更新
  • 开发服务器

Vite相比webpack的优势

当我们开始构建越来越大型的应用时,需要处理的 JavaScript 代码量也呈指数级增长。包含数千个模块的大型项目相当普遍。我们开始遇到性能瓶颈 —— 使用 JavaScript 开发的工具通常需要很长时间(甚至是几分钟!)才能启动开发服务器,即使使用 HMR,文件修改后的效果也需要几秒钟才能在浏览器中反映出来。如此循环往复,迟钝的反馈会极大地影响开发者的开发效率和幸福感。

Vite 旨在利用生态系统中的新进展解决上述问题:浏览器开始原生支持 ES 模块,且越来越多 JavaScript 工具使用编译型语言编写。

  • 服务启动

webpack

因为需要兼容不同的模块化规范,需要从打包入口文件开始分析,然后将文件中的不同模块化规范转换成自己的语法规范,并收集各个模块之间的依赖,当模块越来越多时,处理的时间就会越久

需要将所有的模块分析完成并生成对应的js文件之后,才去启动server,如下图所示:

image.png vite

Vite 以 原生 ESM 方式提供源码。这实际上是让浏览器接管了打包程序的部分工作:Vite 只需要在浏览器请求源码时进行转换并按需提供源码。根据情景动态导入代码,即只在当前屏幕上实际使用时才会被处理。

image.png

  • 模块热更新

webpack

webpack在监听文件变化之后,都需要经过重新编译和转换之后,再触发热更新逻辑

vite

vite在监听文件变化之后,则触发热更新逻辑,浏览器重新请求此文件

vite脚手架和vite

当我们执行yarn create vite时,实际是调用的create-vite这个脚手架,而create-vite中内置了vite,可以类比vue-cli和webpack的关系

  • vite脚手架提供了一些预设(比如vue,vue-ts, react, react-ts等模板)
  • vite 是构建工具

vite使用

安装vite

npm init -y // 生成package.json文件

yarn add vite -D
// or
npm i vite -D

创建文件

  • 文件目录
//
 |- index.html
 |- main.js
 |- count.js
 |- package.json
  • index.html

在一个 Vite 项目中,index.html 在项目最外层而不是在 public 文件夹内。这是有意而为之的:在开发期间 Vite 是一个服务器,而 index.html 是该 Vite 项目的入口文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    // type = "module" 告诉浏览器是使用的es6 module
    <script src="../main.js" type="module"></script>
</body>
</html>
  • main.js
import {num} from './count.js'
console.log(num)
  • count.js
export const num = 0
  • package.json 配置脚本
{
  "name": "vite",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "dev": "vite"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "vite": "^3.0.9"
  }
}

处理第三方模块

比如在项目中引入lodash

  • 安装依赖
npm i lodash -S
  • 在count.js中引用
import _ from 'lodash'
console.log(_)
export const num = 0
  • network中请求结果

vite对引入的第三方做了转换,转换后的代码存放在node_modules/.vite/deps下

image.png 为什么要做转换:

项目中使用的第三方库不一定是使用ESM标准,而vite只支持ESM标准

两个目的:

  • 将不同的第三方库的代码进行转换,并存放在node_modules/.vite/deps,方便使用相对路径使用
  • 提升性能,Vite 将有许多内部模块的 ESM 依赖关系转换为单个模块,以提高后续页面加载性能(减少http请求次数)

针对提升性能可以看下面的列子:

  • 引入lodash-es模块
npm i lodash-es -S
  • main.js使用
import lodashEs from 'lodash-es'
console.log(lodashEs)
  • 默认情况下 vite会将第三方模块中的依赖转换为对应的方法块,如下图所示

image.png

  • 修改配置查看做处理的结果
// vite.config.js
import { defineConfig } from "vite";
export default defineConfig({
    optimizeDeps: { // 告知vite这个模块不进行依赖预构建
      exclude: ['lodash-es']
    },
  });

再次刷新页面结果如下(依赖的模块会被一次请求,很大的影响了性能):

image.png

vite中使用环境变量

Vite 使用 dotenv 从你的 环境目录 中的下列文件加载额外的环境变量:

image.png 加载的环境变量也会通过 import.meta.env 暴露给客户端源码。

为了防止意外地将一些环境变量泄漏到客户端,只有以 VITE_ 为前缀的变量才会暴露给经过 vite 处理的代码

  • 创建.env文件
// .env
VITE_BASE_URL = 'http://test/api' 
  • 使用
// request.js
const BASE_URL = import.meta.env.VITE_BASE_URL
const service = {
    baseUrl: BASE_URL
}

针对css资源的支持

vite中默认是能解析css的, 如果使用了预编译语言如less, sass等, 需要安装对应语言的编译器

  • 安装依赖(以sass为例)
npm i sass -D
  • 样式编写与引入
// index.scss 
$bgColor: blue;

.box1 {
    width: 400px;
    height: 200px;
    background: $bgColor;
}
// main.js
import './index.scss'
  • index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>hello Vite</h1>
    <div class="box1"></div>
    <script src="main.js" type="module"></script>
</body>
</html>

问题

  • 样式冲突和覆盖问题

vite 在处理css资源时,将css文件的内容放置style标签内,并拼接到头部head中,如果存在同名的样式,则后面的会影响到前面的样式,如下图所示

image.png

  • 通过cssModule来解决样式冲突问题 规定以*.module.css命名的css文件就表示开启了css 模块化
// index.module.scss
.bg {
    width: 300px;
    height: 300px;
    background: url('../assets/bg.png');
    background-size: cover;
}

经过vite处理之后,会将原有的类名转换带hash值的唯一值, 如下所示

image.png 遗留问题

目前cssModule虽然实现了类名唯一值, 但是页面中的类名还是未转换前的,需要通过import cssModule from 'index.module.css'; 然后在vue页面中使用

设置样式,感觉有点繁琐,暂时没找到合适的转换方式

图片,字体资源

vite在处理图片资源时,默认将资源引入为URL

服务时引入一个静态资源会返回解析后的公共路径(js文件或者css中的背景图片):

// main.js
import imgUrl from './img.png'
document.getElementById('hero-img').src = imgUrl

// index.css
.bg {
    width: 500px;
    height: 300px;
    background: url('../assets/bg.png');
    background-size: cover;
}
// iconfont.css
@font-face {
  font-family: "iconfont"; /* Project id 3590825 */
  src: url('../fonts/iconfont.woff2?t=1660614433445') format('woff2'),
       url('../fonts/iconfont.woff?t=1660614433445') format('woff'),
       url('../fonts/iconfont.ttf?t=1660614433445') format('truetype');
}
  • 较小的资源体积小于 assetsInlineLimit 选项值(默认4kb) 则会被内联为 base64 data URL

  • 未被包含在内部列表或 assetsInclude 中的资源,可以使用 ?url 后缀显式导入为一个 URL,如下所示

import workletURL from 'extra-scalloped-border/worklet.js?url'
CSS.paintWorklet.addModule(workletURL)

vite常用配置

server配置

import { defineConfig } from "vite";
export default defineConfig({
    server: {
      port: '9530', // 设置服务器端口
      open: true, // 是否启动时, 自动打开浏览器
      cors: true, // 是否开启跨域
      proxy: {
        '/rms': {
          target: 'http://rms.com/api',
          changeOrigin: true,
          rewrite: path =>  path.replace(/^\/api/, '')
        }
      }
    },
})

alias别名

import { defineConfig } from "vite";
import path from 'path'
export default defineConfig({
    resolve: {
      alias: {
        '@': path.resolve(__dirname, './src'),
        '@comp': path.resolve(__dirname, './src/components')
      }
    }
})

构建相关

import { defineConfig } from "vite";
export default defineConfig({
    build: {
      terserOptions: { // js处理配置
        compress: { // 压缩配置
          drop_console: true,  // 删除log语句
        }
      }
    }
})