构建工具
Vite
- 与 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:将代码进行压缩变成体积更小性能更高的代码
构建工具的功能
- 将大量模块集成在一起,我们只需要关注自己写的代码,会自动进行构建流程
- 模块化开发支持:支持直接从node_modules中引入代码 + 模块化支持
- 提高项目性能:打包过程进行 文件压缩、代码分割
- 优化开发体验:
- 热更新:构建工具自动监听文件的变化,自动进行重新打包,再浏览器重新运行
- 开发服务器:解决跨域问题,用vue-cli react-cli creat-react-app
市面常见的构建工具
- webpack (国内主流)
- vite
- esbuild
- parcel(国外) rollup grunt
vite脚手架和vite
yarn create vite
命令都做了什么?- 帮我们全局安装一个东西:create-vite(vite脚手架)
- 直接运行 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
的库去完成生产环境的打包
- vite会全权交给一个叫做
- 解决的问题
- 不同的第三方包会有不同的导出格式,vite本身无法约束,借助预构建解决
- 对路径的处理上可直接用 .vite/deps 方便路径重写
- 网络多包传输的性能问题(也是原生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]();
})
环境变量和模式
根据当前的代码环境产生值的变化的变量 == 环境变量,在不同情况下使用不同的配置
代码环境
- 开发环境
- 测试环境
- 预发布环境
- 灰度环境
- 生产环境
在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',
}
webpack
现代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
环境变量
p
rocess.env.NODE_ENV
monorepo管理
优势:
- 安装速度最快:非扁平的包结构、
- 节省磁盘空间:统一安装包到磁盘的某个位置,通过软链接使用
- 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
初始化仓库
// 初始化仓库 - 生成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
代码规范
使用 ESLint 配合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
代码质量检查
# .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
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]' } } } })