构建工具

Viteopen in new window

  • 与 vue-cli同类型,都属于项目初始化构建工具,相当于第二代vue项目构建工具
  • vite生产环境下打包需要借助Rollup完成 node.js >= 12.0.0

支持创建项目类型

npm create vite@latest   # 使用npm创建项目(vue、react、)
yarn create vite  # 使用yarn创建项目
pnpm create vite  # 使用pnpm创建项目

# 创建react项目
yarn create vite react-router --template react


npm install #安装依赖!
npm run dev #运行项目 

特性:

  • Vite冷启动服务,在开发预览时不进行打包,使用ES6 import
    • 项目过大时,webpack需要处理的时间就会更长
  • 实时热更新,开发时代码更新保存时页面自动更新
  • 按需进行编译,不会刷新全部DOM
  • Vite的模块化规范基于 es6 module 不支持 commonjs模块化
    • webpack中,可以混用 es6和commonjs模块化,侧重于兼容性(必须一次性解析所有依赖)
    • vite侧重于浏览器开发的体验(按需解析依赖)

趋势:

  • Vite是Vue团队的官方出品,vue-cli将把vite作为预设构架工具
  • vite目前只基于浏览器项目
  • vite也支持react项目,也支持angular项目,svelte项目

基础知识

构建工具

可以让开发者不用关心代码是如何在浏览器运行的,只需要一份配置文件,他就能进行一系列的处理

  • 企业可能需要的功能

    稍微修改一点代码,就需要执行一系列麻烦的操作

    • 如果遇到TS文件,需要使用tsc将ts文件转换为js
    • React/Vue代码,需要安装react-compiler / vue-compiler 将jsx文件或vue文件 转换为js文件
    • less/sass代码,需要安装 less-loader,sass-loader等一系列编译工具
    • 语法降级 bable,将es新语法转化为低版本浏览器支持的语法
    • 体积优化 uglifyjs:将代码进行压缩变成体积更小性能更高的代码
  • 构建工具的功能

    1. 将大量模块集成在一起,我们只需要关注自己写的代码,会自动进行构建流程
    2. 模块化开发支持:支持直接从node_modules中引入代码 + 模块化支持
    3. 提高项目性能:打包过程进行 文件压缩、代码分割
    4. 优化开发体验:
      • 热更新:构建工具自动监听文件的变化,自动进行重新打包,再浏览器重新运行
      • 开发服务器:解决跨域问题,用vue-cli react-cli creat-react-app
  • 市面常见的构建工具

    • webpack (国内主流)
    • vite
    • esbuild
    • parcel(国外) rollup grunt
vite脚手架和vite
  • yarn create vite 命令都做了什么?
    1. 帮我们全局安装一个东西:create-vite(vite脚手架)
    2. 直接运行 creat-vite bi目录下的一个执行配置
  • 关系:creat-vite内置vite 例如 vue-cli内置webpack
依赖预构建

首先vite会到对应的依赖,然后调用esbuild(对js语法进行处理),将其他规范的代码转成esmodule规范,然后放到当前目录下的node_modules/.vite/deps,同时对esmodule规范的各个模块进行统一集成

  • 安装vite,开发环境,生产环境不需要vite yarn add vite -D
    • 开箱即用 out of box 安装后不需要做任何工作即可生效
    • 处理过程中如果有非绝对路径或非相对路径的引用,会自动尝试开启路径补全
  • yarn dev ---> 开发(每次依赖预构建 所重新构建的相对路径都是正确的)
    • vite会全权交给一个叫做 rollup的库去完成生产环境的打包
  • 解决的问题
    1. 不同的第三方包会有不同的导出格式,vite本身无法约束,借助预构建解决
    2. 对路径的处理上可直接用 .vite/deps 方便路径重写
    3. 网络多包传输的性能问题(也是原生esmodule不敢支持node_modules的原因之一);有了依赖预构建之后,vite最后会将他们集成为一个或多个js

语法补全

  • 使用webstorm,与生俱来的能力

  • vscode或其他编译器,需要做配置

    • // 方法1:引入对应内容
      import {defineConfig} from 'vite';
      export default defineConfig({
          xxx  //可以得到语法提示
      })
      
      //方法2:使用语法标注
      /**  @type import('vite').UserConfig  */
      const viteConfig = {
          //可以得到语法提示 
      }
      export default viteConfig
      

vite配置

默认环境变量配置
/**
- 项目更目录创建 
	.env   .env.development    .env.production   ....
- 修改package.json中的scripts配置
	"dev":"vite --mode==development",				- 当使用npm run dev时,使用development和env的变量
	"build":"vite --mode==production",				- 当使用npm run build时,使用production和env的变量
*/

注意:.env中的变量只有以VITE_开头的才会被暴露
根据执行命令配置环境
// vite.config.js 文件
export default {
    optimizeDeps:{
    	exclude:['lodash-es'],  //当遇到lodash-es这个依赖时不进行 依赖预构建
	}
}

//分类
// vite.config.js 文件
import {defineConfig} from 'vite'
import viteBaseConfig from './vite.base.config';
// 导入两种环境下的配置文件 dev开发环境的配置,prod生产环境的配置
import vitedevConfig from './vite.dev.config';
import viteProdConfig from './vite.prod.config';

// 策略模式
const evnResolver = {
    // 使用函数便于后期内容的扩展;  es6展开运算符
    "build":()=>Object.assign(viteBaseConfig,viteProdConfig),
    'serve':()=>({...viteBaseConfig,...viteProdConfig})
}
export default defineConfig( config:({command:'build'|'serve'})=>{
    // 具体使用那个配置,取决于命令行执行的命令
    return evnResolver[command]();
})
环境变量和模式open in new window

根据当前的代码环境产生值的变化的变量 == 环境变量,在不同情况下使用不同的配置

代码环境

  • 开发环境
  • 测试环境
  • 预发布环境
  • 灰度环境
  • 生产环境
在vite中的环境变量处理

vite借助内置的第三方库 dotenv,

  • 当在控制台执行命令时, dotenv就会去读取对应的 .env文件 并解析对应的环境变量,并将其注入到process对象(node环境下的进程对象?)
  • 但vite考虑到和其他配置的冲突问题,不会直接注入到process对象下
    • root
    • envDir:用来配置当前环境变量的文件地址

vite.config.ts

import AutoImport from 'unplugin-auto-import/vite'

export default defineConfig({
  server:{
    hmr: true,	// 开启热更新,默认未开启
    https: false, // 是否启动http2
    cors:true, 	// 为开发服务器配置CORS,默认启用允许任何源
    open: true, // 服务启动时自动在浏览器打开
    port:"9000",// 指定启动的端口

  },
  plugins: [
      vue(),
      AutoImport({
      	 imports: ['vue', 'vue-router', 'pinia'], // 自动导入vue和vue-router相关函数
       }),
  ],
  resolve:{
      alias:{
          '@':'/src'		// 配置别名,@表示src/ 目录
      }
  }
})


// 打包后,放置的路径配置
module.exports = {
    publicPath: '/html/front',
}

webpackopen in new window

  • 现代JavaScript应用 的静态模块打包器,在项目上线前打包

  • 文件压缩合并:html css js 图片 表格....

  • 语法转化

    • less/sass/stylus  ===>   css
      ES6+  ===>  ES5
      typescript  ===>  js
      
  • 为开发提供服务器环境:代码热更新

  • 其他特点:

    • 兼容所有模块化规范,借助webpack都可以直接在代码中使用

使用

# 初始化项目
yarn init -y
# 安装webpack 和 webpack-cli(使用webpack4+时)
yarn add --save-dev webpack webpack-cli

# 在项目的package.json文件中配置命令
"scripts": {
    "start": "webpack --config webpack.config.js",
    "build": "webpack 要打包的文件路径 -o 输出到的文件路径"
}
# 运行package.json文件中配置的命令
npm run 命令      #例:npm run build

环境变量

process.env.NODE_ENV

monorepo管理open in new window

  • 基于pnpm的Monorepo实践 - 掘金 (juejin.cn)open in new window

  • 优势:

    • 安装速度最快:非扁平的包结构、
    • 节省磁盘空间:统一安装包到磁盘的某个位置,通过软链接使用
    • monorepo可以让我们在跨团队的多个项目中 标准化一套pretty、eslint、以及git hook等配置...
  • 特点:

    • 一个monorepo项目通常包含多个app和多个packages包

    • app可以依赖pkg,pkg也可以依赖pkg,但app之间通常不建议相互依赖

    • 在apps包中可以直接安装当前monorepo/packages下的包,并使用,(用于公共代码抽离)

      // packages中定义模块 package.json
      {
          name:"@womu-good-demo/cartBtn",
          license:"MTI",
          ...
      }
              
      // 其它同仓库的项目中,使用同级仓库下的其它项目作为包
      pnpm add @womu-good-demo/cartBtn
      

初始化仓库

image-20231107161710891

// 初始化仓库 - 生成package.json
pnpm init

{
    "workspaces": {		// 启用 workspaces 功能
    	"packages": ["packages/*"]
  	},
    "engines": {		// 约束node、pnpm版本 - 在package.json中追加(根据需要添加)
        "node": ">=16",
        "pnpm": ">=7"
    },
    "private": true		// 避免根目录被当做包发布
}

// pnpm本身支持monorepo,不用额外安装包, 但每个monorepo的根目录下必须包含pnpm-workspace.yaml文件
// pnpm 会自动在更目录生成 公共的 node_modules(事先有多个项目文件)

// 安装全局项目依赖包(当前仓库的根目录)
// -w	表示在workspace的根目录下安装而不是当前的目录
// -D 表示安装为开发依赖
pnpm add -D -w xxxx
// 安装子包的依赖 - 直接进入子项目目录中安装(每个项目也都有自己的package.json)

公共配置

  • Eslint: 统一代码质量和格式检查
  • Prettier: 自动格式代码,统一代码风格
  • git 的 hook功能: 提交代码时自动执行Eslint代码检查
  • Husky:为git创建、管理代码仓库中的所有git hooks
  • lint-staged工具:提交代码时,只对当前变更的代码执行prettier 和 eslint命令,同时略过忽略文件
  • commitlint工具:对commit message进行格式检查,确保符合基本Augular规范
  • commitizen工具:辅助生成commit信息(可选)
  • vscode配置文件:extension.json settings.json
Eslint:
// 在项目更目录创建 .eslintrc 和 .eslintignore 文件夹


Prettier:
// vscode中安装插件prettier
pnpm add -w -D prettier		// 在项目根目录安装prettier
// 在根目录中创建 .prettierrc 和 .prettierignore 文件

Prettier与Eslint的冲突解决
// eslint-config-prettier 关闭所有可能干扰Prettier规则的Eslint规则,确保将其放在最后生效
// eslint-plugin-prettier 将Prettier规则转化为Eslint规则,使Eslint提供错误提示信息
pnpm add -w -D eslint-config-prettier eslint-plugin-prettier

代码规范

使用 ESLintopen in new window 配合vscode插件,实现项目代码统一规范

  • Vscode插件:ESLint

  • .eslintignore - 配置.eslintignore文件

    node_modules
    public
    build
    lib/
    dist/
    build/
    coverage/
    demo/
    es/
    .rax/
    src/miniapp
    
  • .eslintrc.js - 配置ESLint的检查规则

// 前提(前两步在现代项目创建时一般自带,不需要再执行):
// 1.项目package.json中存在 eslint 依赖项
pnpm install eslint -save-dev
// 2.项目根目录下存在eslint的config文件: .eslintrc.js
eslint --init	//如果提示eslint找不到,可以尝试运行./node_modules/.bin/eslint --init


前端工程化

配置推荐

  • VScode插件

    • Vue - Official
    • Vue VSCode Snippets - vue快捷键插件
    • ESLint
    • Prettier - Code formatter
    • UnoCSS
    # 1.VsCode 操作
    ctrl + shift + p     ## 输入重启扩展宿主,更新插件配置
    
  • 推荐使用 Vue官方脚手架创建项目

    • 自带Vitest测试、eslint、prettier等...

env.d.ts

全局声明文件;.d.ts表示声明文件

/// <reference types="vite/client" />      # /// 表示引入

ESLint open in new window

代码质量检查

# .eslintrc.cjs 配置文件
cjs 中c即表示使用 commond 规范

# 对于自定义规则 rules
0  |  "off"      # 关闭
1	# 黄色警告
2	# 红色报错

vue配置

/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')

module.exports = {
  root: true,
  extends: [
    'plugin:vue/vue3-essential',
    'eslint:recommended',
    'airbnb-base',
    '@vue/eslint-config-typescript',
    '@vue/eslint-config-prettier/skip-formatting',
    './.eslintrc-auto-import.json'
  ],
  parserOptions: {
    ecmaVersion: 'latest'
  },
  settings: {
    'import/resolver': {
      typescript: {
        // eslint-import-resolver-typescript 解决@符号别名问题
        project: './tsconfig.*.json'
      }
    }
  },
  rules: {
    'import/no-extraneous-dependencies': 'off',
    // 忽略后缀检查
    'import/extensions': [0, { js: 'never', jsx: 'never', ts: 'never', tsx: 'never' }],
    // import 导入规则
    'import/order': [
      'error',
      {
        // 对导入模块进行分组
        groups: [
          ['builtin', 'external'], // 内置模块(例:Node的内置模块)、外部模块(例:vue、react等)
          'internal', // 内部模块,相对路径的模块、前缀为@符的模块
          ['parent', 'sibling'], // 父级目录模块、同级目录模块
          'index', // 当前目录下的index
          'object', // es6 导入的模块
          'type', // 使用 import type 导入的模块
          'unknown' // 未知模块
        ],
        // 通过路径自定义分组
        pathGroups: [
          {
            // pattern:当前组中模块的最短路径匹配
            pattern: '@app/**', // 在规定的组中选其一,index、sibling、parent、internal、external、builtin、object、type、unknown
            group: 'external',
            // 定义组的位置,after、before
            position: 'after'
          }
        ],
        pathGroupsExcludedImportTypes: ['builtin'],
        // newlines-between 不同组之间是否进行换行
        'newlines-between': 'always',
        // alphabetize 根据字母顺序对每个组内的顺序进行排序
        alphabetize: {
          order: 'asc',
          caseInsensitive: true
        }
      }
    ]
  }
}

airbnb-base规范配置

// 1. 安装对应配置
pnpm i eslint-config-airbnb-base eslint-plugin-import eslint-import-resolver-typescript -D

// 2.在 .eslintrc.cjs 中导入规则
 extends: [
    'plugin:vue/vue3-essential',
    'airbnb-base',
     ...
  ],
     
// 3.解决 @ 别名报错,在 .eslintrc.cjs 中配置
  settings: {
    'import/resolver': {
      typescript: {
        // eslint-import-resolver-typescript 解决@符号别名问题
        project: './tsconfig.*.json'
      }
    }
  }
  
  
 // 4.解决其他报错,在 .eslintrc.cjs 中配置自定义规则
rules: { 
    'import/no-extraneous-dependencies': 'off', 	// require 引入报错
     // 忽略后缀检查
     'import/extensions':[
        'ingnorePackages',
        {js:'never',jsx:'never',ts:'never',tsx:'never'}
    ] 
}

Prettier

代码风格检查

# .prettierrc.json 配置文件
## vue项目:
{
  "$schema": "https://json.schemastore.org/prettierrc",
  "semi": false,
  "tabWidth": 2,
  "singleQuote": true,
  "printWidth": 100,
  "trailingComma": "none"
}

StyleLint

css格式化插件

husky

项目规范的基石——husky 与 lint-staged - 掘金 (juejin.cn)open in new window

TS

  • tsconfig.json ts配置汇总文件
  • tsconfig.app.json 掌管src目录下的声明
  • tsconfig.node.json 外层配置的声明
  • tsconfig.vitest.json vitest

unplugin-auto-import

按需导入

eleUI+自动导入bug

  • css样式未引入

    // 需额外引入  pnpm i vite-plugin-style-import consola -D
    
    // 修改vite.config.js
    import { createStyleImportPlugin, ElementPlusResolve } from 'vite-plugin-style-import'	// 自动引入样式
    
    // plugins下追加配置
    createStyleImportPlugin({
          resolves: [ElementPlusResolve()],
          libs: [
            {
              libraryName: 'element-plus',
              esModule: true,
              resolveStyle: (name: string) => {
                return `element-plus/theme-chalk/${name}.scss`
              }
            }
          ]
        })
    
  • 代码中引入的组件,无法被识别到

    // 在tsconfig.app/json中追加   "types": ["element-plus/global"]
    {
    	....
        "paths": {
          "@/*": ["./src/*"]
        },
        "types": ["element-plus/global"]
      }
    }
    

unocss

官网https://unocss.dev/guide/

  • 安装

    pnpm i unocss @iconify-json/ep @unocss/preset-rem-to-px @unocss/transformer-directives -D
    

    unocss 核心库

    @iconify-json/ep 是 Element Plus 的图标库 https://icones.js.org/ 网站里面找

    @unocss/preset-rem-to-px 把unocss自带的rem转为px

    @unocss/transformer-directives 可以使用@apply @screen theme函数

    icon官网https://unocss.dev/presets/icons

    博客https://blog.csdn.net/qq_42618566/article/details/135680388

  • vite.config.ts 配置

    // unocss vite插件配置
    import UnoCSS from 'unocss/vite'
    
    // https://vitejs.dev/config/
    export default defineConfig({
      // ...
      plugins: [
        // ...
        UnoCSS(),
      ],
    })
    
  • 根目录新建uno.config.ts

    // uno.config.ts
    
    // 预设rem转px
    import presetRemToPx from '@unocss/preset-rem-to-px'
    // transformerDirectives 可以使用@apply @screen theme函数
    import transformerDirective from '@unocss/transformer-directives'
    import {
      defineConfig,
      presetAttributify,
      presetUno,
      transformerVariantGroup,
      presetIcons
    } from 'unocss'
    
    export default defineConfig({
      presets: [
        presetAttributify(),
        presetUno(),
        // 现在mt-1会转换为margin-top: 1px
        presetRemToPx({
          baseFontSize: 4
        }),
        // 自动引入图标配置
        presetIcons({
          scale: 1.2,
          warn: true
        })
      ],
    
      transformers: [transformerVariantGroup(), transformerDirective()],
      //  自定义配置项
      rules: [
        /** 以下官网规则可自定义转换 */
        /* 例如 m-1 转换为 margin:0.25rem */
        // [/^m-(\d+)$/, ([, d]) => ({margin: `${d / 4}rem`})],
        // [/^p-(\d+)$/, match => ({padding: `${match[1] / 4}rem`})],
      ],
      // 自定义属性 一个属性可以对应多个unocss类值
      shortcuts: [
        {
          // 垂直水平居中
          'flex-center': 'flex items-center justify-center',
          // 放在最后
          'flex-end': 'flex items-center justify-end',
          // 垂直居中
          'flex-middle': 'flex items-center',
          // 分开两边
          'flex-between': 'flex items-center justify-between',
          // 竖着居中
          'flex-col-center': 'flex flex-col justify-center'
        }
      ]
    })
    
    
  • main.ts 全局配置

    // eslint-disable-next-line import/no-unresolved
    import 'virtual:uno.css' // uno.css
    
  • 使用

    i前缀-ep图库名:lock图标名称

<i block w100 h100 i-ep:look></i>
<div i-ep:look></div>

gzip压缩

  • 安装

    pnpm i vite-plugin-compression -D
    
  • vite.config.ts配置

    // 压缩gzip
    import viteCompression from 'vite-plugin-compression'
    
    // https://vitejs.dev/config/
    export default defineConfig({
      // ...
      plugins: [
        // ...
        viteCompression({
            verbose: true, // 默认即可
            disable: false, // 开启压缩(不禁用),默认即可
            deleteOriginFile: false, // 删除源文件
            threshold: 10240, // 压缩前最小文件大小
            algorithm: 'gzip', // 压缩算法
            ext: '.gz' // 文件类型
        })
      ],
    })
    

自动重启

插件网站https://www.npmjs.com/package/vite-plugin-restart

  • 安装

    pnpm i vite-plugin-restart -D
    
  • vite.config.ts配置

    // 自动重启
    import ViteRestart from 'vite-plugin-restart'
    
    // https://vitejs.dev/config/
    export default defineConfig({
      // ...
      plugins: [
        // ...
        ViteRestart({
           restart: ['*.config.[jt]s', '**/config/*.[jt]s', '*.config.cjs']
        })
      ],
    })
    

Svg配置

插件网站https://www.npmjs.com/package/vite-svg-loader

  • 安装

    pnpm i vite-svg-loader -D
    
  • vite.config.ts配置

    // svg加载
    import svgLoader from 'vite-svg-loader'
    
    // https://vitejs.dev/config/
    export default defineConfig({
      // ...
      plugins: [
        // ...
       svgLoader({
          defaultImport: 'url', // or 'raw'
          svgo: true
        })
      ],
    })
    
  • 使用

    <template>
        <img w20 h20 :src="sunUrl" />
    </template>
    
    <script setup lang="ts">
    import sunUrl from '@/assets/svg/sun.svg'
    </script>
    

打包拆分 小图片转base64

https://cn.vitejs.dev/config/build-options.html#build-assetsinlinelimit

  • vite.config.ts配置

    // https://vitejs.dev/config/
    export default defineConfig({
      // ...
      build: {
        // 10kb以下,转Base64
        assetsInlineLimit: 1024 * 10,
        // chunkSizeWarningLimit: 1500,//配置文件大小提醒限制,默认500
        rollupOptions: {
          output: {
            // 每个node_modules模块分成一个js文件
            manualChunks(id: string) {
              if (id.includes('node_modules')) {
                // return 'vendor' // 第三方依赖合并在一起
                // 把第三方依赖抽离出来
                return id.toString().split('node_modules/.pnpm/')[1].split('/')[0].toString()
              }
              return undefined
            },
            // 用于从入口点创建的块的打包输出格式[name]表示文件名,[hash]表示该文件内容hash值
            entryFileNames: 'assets/js/[name].[hash].js', // 用于命名代码拆分时创建的共享块的输出命名
            chunkFileNames: 'assets/js/[name].[hash].js', // 用于输出静态资源的命名,[ext]表示文件扩展名
            assetFileNames: 'assets/[ext]/[name].[hash].[ext]'
          }
        }
      }
    })
    
Last Updated:
Contributors: 夏之一周, wudetian.top