前言
Hi,我是大雄! 大雄最近在研究如何搭建一个简易脚手架。核心需求是输入项目命令,clone准备好的项目模板,拉到本地后,装一下依赖,就可以直接开发了。不用每次都花大量时间,去搭建项目规范和做必要的封装配置。
经过简单寻找后,发现没有符合自己预期的。于是大雄从0到1搭建一个具备完善规范的Vue3开发模板✨,并手把手带大家实现,本文你将会学到以下内容,上图👇,话不多说,我们直接开始!!
diff
本文环境:
- win10
- 包管理工具:pnpm
- node版本:16.16
- vite版本:5.0.10
- vue版本:3.3.11
模板地址:https://github.com/1111-stu/vue3-template
项目规范搭建篇
前置包管理工具pnpm安装(已安装的小伙伴可跳过)
vue3项目推荐使用pnpm来作为包管理工具。若当前没安装过pnpm,执行下面的命令安装一下。
安装:
npm install pnpm -g
基本使用:
下载
csharp
pnpm install 包 //
pnpm i 包
pnpm add 包 // -S 默认写入dependencies
pnpm add -D // -D devDependencies
pnpm add -g // 全局安装
移除
csharp
pnpm remove 包 //移除包
pnpm remove 包 --global //移除全局包
更新
csharp
pnpm up //更新所有依赖项
pnpm upgrade 包 //更新包
pnpm upgrade 包 --global //更新全局包
可能遇到的问题:
安装完成后,如果pnpm命令可以在cmd执行,无法在vscode终端运行,参考:blog.csdn.net/weixin_4806...
解决步骤:
- vscode右键以管理员身份打开运行(不是管理员,会无权限更改)
- vscode终端输入命令get-ExecutionPolicy,若显示结果是Restricted,表示关闭命令功能。
arduino
get-ExecutionPolicy
3、输入命令set-ExecutionPolicy,输入参数RemoteSigned即可
arduino
set-ExecutionPolicy
RemoteSigned
示例见下图所示👇
Vite自定义模板
自定义选项前置知识了解,这里引用一下大佬的图片@吃炸鸡的前端,见下图所示👇
下面开始使用vite自定义基础模板配置,这里推荐一开始就选择Eslint和Prettier的预设,项目开发中途再加,一堆坑,实属没必要踩。详细配置选择,见下图👇。
我们使用git init来生成一个仓库。然后git add . ,git commit- m"" 来进行初次提交。
项目构建完成后,切换到对应目录,安装依赖,启动项目。
测试EsLint、Prettier的格式化功能
上文,我们基于Vite选择Eslint和Prettier的预设,下面我们测试一下EsLint的格式化效果
运行pnpm lint,发现没有任何变化(Eslint中没有添加很多的规则,导致通过了)。在运行pnpm format发现,发现确实帮我们做了格式化(根据.prettierrc.json文件中的内容格式化了)。
出现上述问题的原因是,基于Vite在选择Eslint和Prettier的预设时,并没有让两者联系起来,即没有把Prettier加入到Eslint中。下文我们就来构建两者的联系。
构建Prettier和Eslint的联系
插件安装
构建Prettier和Eslint的联系,需要安装一下下面的两个插件。
eslint-config-prettier //用于解决和 Prettier 冲突的 ESLint 的配置
eslint-plugin-prettier //启用 eslint-plugin-prettier
arduino
npm i eslint-config-prettier eslint-plugin-prettier -D
修改 ESLint 配置,使 Eslint 兼容 Prettier 规则
打开.eslintrc.cjs文件,放在extends配置项的末尾,因为extends中后引入的规则会覆盖前面的规则。
那么就可以在.prettierrc.json 中定义自己的代码风格校验。本地的prettier插件会根据这个文件来格式化,项目配置的prettier也会根据该文件来格式化。且eslint的风格与prettier风格冲突的地方会以prettier为主。
bash
plugin:prettier/recommended
java
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = {
root: true,
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript',
'@vue/eslint-config-prettier/skip-formatting',
'plugin:prettier/recommended'
],
parserOptions: {
ecmaVersion: 'latest'
}
}
'
这时我们运行pnpm lint,可以看到已经帮我们格式化好了。下面我们只需要加入commitLint即可完成我们的规范搭建。
可能遇到的问题
如遇到以下的报错,分析日志信息,发现eslint-config-prettier出现了两个版本,猜测是其他插件包依赖的eslint-config-prettier版本是8.10.0,当前安装的是9.1.0。导致出现了版本冲突,删除9.1.0的eslint-config-prettier,装一下8.10.0就可以了。
rust
ESLint couldn't determine the plugin "prettier" uniquely.
集成lint-staged和husky
lint-staged 是一个专门针对已放入 Git 暂存区的文件进行检查的工具
husky 能提供监听 Git 操作并执行脚本代码的能力
安装 lint-staged和husky
css
pnpm i lint-staged husky --save-dev
配置lint-staged
在package.json中添加下面的代码,匹配暂存区所有的js,vue文件,并执行命令。
json
"lint-staged": {
"*.{js,vue,jsx,tsx}": [
"pnpm lint",
"prettier --write",
"eslint --cache --fix",
"git add"
]
}
配置husky,实现在git 提交时执行 lint-staged
配置脚本钩子,实现在"pnpm i"后自动执行对应的hooks
在 package.json的"scripts "中配置快捷命令,用来在安装项目依赖时生成 husky 的相关文件,配置项postinstall 或者prepare都可以。
json
{
// ...
"scripts": {
// ...
"postinstall": "husky install"
},
}
在 package.json 文件中,"postinstall" 是一个特殊的脚本钩子,它在 npm install(或等效的 pnpm i、yarn install)命令执行后自动运行。这个特性是由 npm(以及兼容的包管理器如 pnpm 和 yarn)提供的,旨在在安装包后自动执行某些任务。
当在项目中使用 pnpm i 命令安装依赖时,pnpm 会检查 package.json 文件中的 "scripts" 部分,特别是 "postinstall" 脚本。如果存在 "postinstall" 脚本,pnpm 将在所有包安装完成后自动执行该脚本中定义的命令。
在 package.json 中,"postinstall" 被设置为 "husky install"。这意味着每次执行 pnpm i 安装依赖后,pnpm 会自动执行 husky install 命令。这个命令的作用是安装 Husky,Husky是一个流行的 Git 钩子工具,用于在 Git 操作(如提交、推送等)时自动运行脚本。
"prepare" 和 "postinstall" 是 package.json 文件中定义的两个不同的 npm 生命周期钩子,它们在不同的时间点被触发,适用于不同的用途。下面是它们的主要区别:
- 触发时机:
-
- "prepare" : 这个钩子在几个关键场景中被触发,包括在本地执行 npm install(没有参数)后、在作为 git 依赖安装到其他项目之前、以及在运行 npm pack 和 npm publish 之前(在打包"npm pack"或发布"npm publish"你的库到 npm 之前,会执行 "prepare" 脚本。这样可以确保在打包或发布前运行必要的构建步骤或检查。)。
- "postinstall" : 这个钩子仅在 npm install 或等效命令(如 pnpm i 或 yarn install)执行后触发,不论是在本地安装项目依赖时,还是作为依赖安装到其他项目中时。
- 用途:
-
- "prepare" : 通常用于在发布包之前执行构建脚本或其他准备工作。例如,如果你的包需要编译或转换代码,或者需要在发布前进行某些自动化检查,那么 "prepare" 是合适的选择。
- "postinstall" : 通常用于在安装项目依赖后执行一些设置或配置工作。比如安装或配置工具,或执行一些只在项目初次安装依赖时需要的操作。
- 场景应用:
-
- 使用 "prepare" 当你的包需要在发布前进行构建或准备工作,或者当你的包被作为 git 依赖安装时。
- 使用 "postinstall" 适合在每次安装依赖时都需要执行的操作,如安装 Git 钩子或其他项目配置。
如果对npm script命令不太了解的小伙伴可以参考下方链接进行学习
www.ruanyifeng.com/blog/2016/1...
配置完成后,执行pnpm i,会在项目根目录生成 .husky/_ 目录。
生成pre-commit文件
执行下面的命令, husky会 生成 git 操作的监听钩子脚本。
npx husky add .husky/pre-commit "npx lint-staged"
打开.husky/pre-commit 文件,可以看到以下内容,git commit时,这个脚本作为 Git 钩子运行,使用 lint-staged 来对暂存区中的文件执行代码检查。
bash
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx lint-staged
到此你就完成了git commit时自动去触发eslint的检测和修复。修改代码后git add . git commit,就可以发现代码检测和修复生效了。
补充
值得注意的是,当前这种方式创建的项目,规则很少,适合自己自定义eslint规则。 因为刚初始化好的eslint规则只加入了一些推荐的eslint。(相对来说,踩坑较少)
如果自己需要自定义规则的话,可以在.prettierrc.json或者.eslintrc.cjs的rules中去添加自己的规则。.prettierrc.json定义的规则>.eslintrc.cjs中定义的规则。
如果你需要一套完善的git 提交规范校验,例如:运行 git commmit -m 'xxx' 时,用来检查 xxx 是否满足要求的提交规范, 下文我们一起来实现吧!!🐳
Git 提交规范建设校验commit格式
前置知识
commitlint是什么?
当我们运行 git commmit -m 'xxx' 时,用来检查 xxx 是否满足固定格式的工具。简单来说,就是制定提交规范
提交的格式,与常见的规范
- 提交格式 (注意冒号后面有空格)
git commit -m [optional scope]:
type :用于表明我们这次提交的改动类型,是新增了功能?还是修改了测试代码?又或者是更新了文档?
optional scope:一个可选的修改范围。用于标识此次提交主要涉及到代码中哪个模块。
description:一句话描述此次提交的主要内容,做到言简意赅。
- 常用的 type 类型
安装commitlint
css
pnpm i --save-dev @commitlint/config-conventional @commitlint/cli
生成commit-msg文件
文件中可以配置在 ****git commit 时对 commit 信息的校验指令
可手动创建文件再输入文件内容,但是建议使用命令创建,命令如下:
sql
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'
上面命令执行成功后会在 .husky 目录下生成一个 commit-msg 文件,该文件的内容如下,表示在 git commit 前执行一下 npx --no -- commitlint --edit $1 指令。
当你进行 Git 提交时,这个 commit-msg 文件会被触发,它先初始化 Husky,然后使用commitlint 来检查你的提交信息是否符合预设的规范。
bash
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no -- commitlint --edit $1
项目根目录创建名为commitlint.config.js的文件,配置提交规范
javascript
module.exports = {
extends: ["@commitlint/config-conventional"],
// 定义规则类型
rules: {
// type 类型定义,表示 git 提交的 type 必须在以下类型范围内
"type-enum": [
2,
"always",
[
"feat", // 增加新功能
"fix", // 修复 bug
"del", // 删除功能
"update", // 更新功能
"docs", // 文档相关的改动
"style", // 不影响代码逻辑的改动,例如修改空格,缩进等
"build", // 构造工具或者相关依赖的改动
"refactor", // 代码重构
"revert", // 撤销,版本回退
"test", // 添加或修改测试
"perf", // 提高性能的改动
"chore", // 修改 src 或者 test 的其余修改,例如构建过程或辅助工具的变动
"ci", // CI 配置,脚本文件等改动
],
],
// subject 大小写不做校验
"subject-case": [0],
},
plugins: [
{
rules: {
"commit-rule": ({ raw }) => {
return [
/^[(feat|fix|del|update|docs|style|build|refactor|revert|test|perf|chore)].+/g.test(raw),
`commit备注信息格式错误,格式为 <[type] 修改内容>,type支持${types.join(",")}`,
];
},
},
},
],
};
可能遇到的问题
commitlint.config.js文件,提交时候ESlint会报错,解决方法是,根目录下新建.eslintignore文件,配置路径,忽略对这个文件的Eslint校验。
添加下面这行代码,为什么是.cjs?见下面的报错解决(如未遇到,改为.js就好)
arduino
commitlint.config.cjs
添加.eslintignore后,若git commit如果忽略校验没有奏效。检查package.json文件,
如果lint的配置存在--ignore-path,去掉--ignore-path就可以了。原因是:如果eslint后加了 --ignore-path 后,.eslintignore的配置会失效
json
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
改成:
json
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix"
参考解决方法:
www.cnblogs.com/zouzhongxin...
其他忽略ESlint的校验的方法:blog.csdn.net/a7442358/ar...
如果出现下面的问题,重命名commitlint.config.js为commitlint.config.cjs
提供Commit提示信息,实现交互式commit,简化提交的负担
背景:
如果提交的type比较多,每次都需要翻看一下。那么接入commitizen、cz-customizable,实现交互式提交会是个不错的解决方法。交互效果见下图👇
安装commitizen、cz-customizable
commitizen: commit命令行提示
cz-customizable:自定义的Commitizen的交互信息
csharp
pnpm add commitizen cz-customizable -g
详细可参考:github.com/leonardoana...
配置信息
根目录新建一个.cz-config.cjs文件(一开始创建的是.js文件,提示使用cjs代替,于是修改为.cjs文件),在根目录创建的.cz-config.cjs 添加以下代码,自定义commit提示内容。
css
module.exports = {
types: [
{ value: 'feat', name: 'feat: 新功能' },
{ value: 'fix', name: 'fix: 修复bug' },
{ value: 'del', name: 'del: 删除功能'},
{value: 'update', name: 'update: 更新功能'},
{ value: 'docs', name: 'docs: 文档变更' },
{ value: 'style', name: 'style: 代码格式(不影响代码运行的变动)' },
{
value: 'refactor',
name: 'refactor: 重构(既不是增加feature,也不是修复bug)'
},
{ value: 'perf', name: 'perf: 性能优化' },
{ value: 'test', name: 'test: 测试用例变更' },
{ value: 'chore', name: 'chore: 构建过程或辅助工具的变动' },
{ value: 'revert', name: 'revert: 回退' },
{ value: 'build', name: 'build: 打包' },
//ci变动
{ value: 'ci', name: 'ci: CI 配置或脚本文件的改动' }
],
// override the messages, defaults are as follows
messages: {
type: '请选择提交类型:',
// scope: '请输入文件修改范围(可选):',
// used if allowCustomScopes is true
customScope: '请输入修改范围(可选):',
subject: '请简要描述提交(必填):',
body: '请输入详细描述(可选,待优化去除,跳过即可):',
// breaking: 'List any BREAKING CHANGES (optional):\n',
footer: '请输入要关闭的issue(待优化去除,跳过即可):',
confirmCommit: '确认使用以上信息提交?(y/n/e/h)'
},
allowCustomScopes: true,
// allowBreakingChanges: ['feat', 'fix'],
skipQuestions: ['body', 'footer'],
// limit subject length, commitlint默认是72
subjectLimit: 72
}
package.json添加以下内容:
json
"scripts" : {
...
"commit": "./node_modules/cz-customizable/standalone.js"
}
erlang
...
"config": {
"commitizen": {
"path": "./node_modules/cz-customizable"
},
"cz-customizable": {
"config": "./.cz-config.cjs"
}
}
}
配置完成后,输入git cz,出现下面的内容,说明接入成功了
后面的提交,使用git cz来代替git commit
husky hooks接入
输入git cz后,细心的小伙伴会发现,上文的ESlint、Prettier的校验没有生效,我们希望commitizen和ESlint、Prettier,是一起集成到husky的hooks里面,输入git cz自动执行配置的hooks。达到下图的效果
其实很简单,在 Husky 的 commit-msg 钩子中调用 commitizen。即在 .husky/commit-msg 文件中:添加下面的代码
arduino
npx cz --hook || true
随便找个文件修改一下,"git add ."、"git cz"查看效果,出现下图说明配置成功了。
其他可扩展的规范校验接入
- 集成Style-lint,提交时校验并格式化css、less、scss代码
- 接入Eslint-plugin-filenames,实现对文件夹文件名的命名校验
- 补充Prettier、Eslint自定义规则
项目基础配置
配置全局 scss 样式文件
安装saas
css
pnpm i sass -d
新增样式文件
在 src/assets 下新增 style 文件夹,用于存放全局样式文件,新建 main.scss, 设置一个用于测试的颜色变量
css
$primary-color: #007bff;
$warning-color: #ffc107;
如何将这个全局样式文件全局注入 到项目中呢?vite.config.ts添加下方配置
css
css:{
preprocessorOptions:{
scss:{
additionalData:'@import "@/assets/style/main.scss";'
}
}
},
组件内使用
css
.title {
color: $primary-color;
}
配置路径别名
依赖安装
@types/node 是一个 NPM 包,它的作用是为 Node.js 环境中的 JavaScript 提供 TypeScript 类型定义。当在 TypeScript 项目中使用 Node.js 时,这个包非常重要
css
pnpm i @types/node -D
vite.config.ts:第一种配置
php
// path 模块提供了一些工具函数,用于处理文件与目录的路径
import { resolve } from 'path'
// 使用 defineConfig 工具函数,这样不用 jsdoc 注解也可以获取类型提示
import { defineConfig } from 'vite'
/** 当前执行 node 命令时文件夹的地址(工作目录) */
const root: string = process.cwd()
/** 路径拼接函数,简化代码 */
const pathResolve = (dir: string): string => resolve(root, dir)
export default defineConfig({
resolve: {
alias: [
// 设置 `@` 指向 `src` 目录
{ find: '@', replacement: pathResolve('src') },
// 设置 `@assets` 指向 `src/assets` 目录
{ find: '@assets', replacement: pathResolve('src/assets') },
// 设置 `@components` 指向 `src/components` 目录
{ find: '@components', replacement: pathResolve('src/components') },
// 设置 `@views` 指向 `src/views` 目录
{ find: '@views', replacement: pathResolve('src/views') },
// 设置 `@utils` 指向 `src/utils` 目录
{ find: '@utils', replacement: pathResolve('src/utils') }
// 可以根据需要添加更多的别名
],
},
})
vite.config.ts:第二种配置
javascript
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
'@assets': fileURLToPath(new URL('./src/assets', import.meta.url)),
'@components': fileURLToPath(new URL('./src/components', import.meta.url)),
'@views': fileURLToPath(new URL('./src/views', import.meta.url)),
'@utils': fileURLToPath(new URL('./src/utils', import.meta.url))
}
}
})
tsconfig.json声明paths
无论是使用配置一还是配置二,都需要在tsconfig.json 声明paths
perl
{
"compilerOptions": {
// ... 其他已有的配置
// 设置基础 URL 为项目根目录
"baseUrl": ".",
// 定义别名
"paths": {
"@/": ["./src/"],
"@assets/*": ["./src/assets/*"],
"@components/*": ["./src/components/*"],
"@views/*": ["./src/views/*"],
"@utils/*": ["./src/utils/*"]
}
},
// ... 其他 TypeScript 配置,如 include、exclude 等
}
请求封装
安装axios
css
pnpm i axios
实际使用中可以根据项目修改,比如RESTfulapi中可以自行添加put和delete请求,ResType也可以根据后端的通用返回值动态的去修改
简单二次封装
新增 service 文件夹,service 下新增 http.ts 文件、 api 文件夹。api文件夹下做接口做统一管理,按照模块来划分。详见下方文件树👇。
service
├── api
│ └── login
│ ├── login.ts
│ └── types.ts
└── http.ts
http.ts代码
typescript
//http.ts
import axios from 'axios'
// 设置请求头和请求路径
axios.defaults.baseURL = '/api'
axios.defaults.timeout = 10000
axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8'
axios.interceptors.request.use(
(config) => {
const token = window.sessionStorage.getItem('token')
if (token) {
//@ts-ignore
config.headers.token = token
}
return config
},
(error) => {
return error
}
)
// 响应拦截
axios.interceptors.response.use((res) => {
if (res.data.code === 111) {
sessionStorage.setItem('token', '')
// token过期操作
}
return res
})
interface ResType<T> {
code: number
data?: T
msg: string
err?: string
}
interface Http {
get<T>(url: string, params?: unknown): Promise<ResType<T>>
post<T>(url: string, params?: unknown): Promise<ResType<T>>
upload<T>(url: string, params: unknown): Promise<ResType<T>>
download(url: string): void
}
const http: Http = {
get(url, params) {
return new Promise((resolve, reject) => {
axios
.get(url, { params })
.then((res) => {
resolve(res.data)
})
.catch((err) => {
reject(err.data)
})
})
},
post(url, params) {
return new Promise((resolve, reject) => {
axios
.post(url, JSON.stringify(params))
.then((res) => {
resolve(res.data)
})
.catch((err) => {
reject(err.data)
})
})
},
upload(url, file) {
return new Promise((resolve, reject) => {
axios
.post(url, file, {
headers: { 'Content-Type': 'multipart/form-data' },
})
.then((res) => {
resolve(res.data)
})
.catch((err) => {
reject(err.data)
})
})
},
download(url) {
const iframe = document.createElement('iframe')
iframe.style.display = 'none'
iframe.src = url
iframe.onload = function () {
document.body.removeChild(iframe)
}
document.body.appendChild(iframe)
},
}
export default http
login.ts代码
javascript
import http from '@/service/http'
import * as T from './types'
const loginApi: T.ILoginApi = {
login(params){
return http.post('/login', params)
}
}
export default loginApi
types.ts代码
typescript
export interface ILoginParams {
userName: string
passWord: string | number
}
export interface ILoginApi {
login: (params: ILoginParams)=> Promise<any>
}
至此,一个简单地请求封装完成了!!!!
现成的三方库
除了手动封装 axios外 ,这里推荐一个 vue3 的请求库: VueRequest👇。官网链接: www.attojs.com/
全局状态管理-Pinia的配置
前置知识
pinia的模式有两种:options API 和 composition API。 推荐使用composition API 模式定义store,符合Vue3 setup 的编程模式,让结构更加扁平化。
下图是在项目初始化的时候,vite就帮我们预设好了,我们基于这个基础上做一些改进。
创建总入口
在src/store目录下创建一个入口index.ts,其中包含一个注册函数registerStore(),其作用是把整个项目的store都提前注册好,最后把所有的store实例挂到appStore透传出去。这样以后,只要我们在项目任何组件要使用pinia时,只要import appStore进来,取对应的store实例就行。
typescript
// src/store/index.ts
import { useCounterStore } from "./counter";
export interface IAppStore {
useCounter: ReturnType<typeof useCounterStore>;
// 其他store...
}
const appStore:IAppStore = {} as IAppStore;
/**
* 注册app状态库
*/
export const registerStore = () => {
appStore.useCounter = useCounterStore();
// 其他store...
}
export default appStore;
composition API模式下不支持某些内置方法,如$reset(),解决方式是重写一下reset方法。
src/utils/storeTools
typescript
// src/utils/storeTools
// Pinia store基础集成方法
import type { IAppStore } from '@/store'
/**
* 重构$reset()
* @desc 因为setup模式编程不支持reset方法,这里要手动重构
* @param appStore
*/
export const initResetFun = (appStore: IAppStore) => {
// 遍历 appStore 中的所有项。
Object.values(appStore).forEach((item) => {
// 创建一个空对象 initState 用于存储初始状态。
const initState = {} as Record<string, any>
// 遍历 item 的 $state 对象的所有条目。
Object.entries(item.$state).forEach((item) => {
// 将每个状态的初始值存储到 initState 对象中。
initState[item[0]] = item[1]
})
// 为每个 store 项定义一个 reset 方法。
item.reset = () => {
// 遍历 $state 对象的所有状态。
Object.keys(item.$state).forEach((state) => {
// 将每个状态重置为其初始值。
item.$state[state] = initState[state]
})
}
})
}
src/store/index.ts
typescript
//src/store/index.ts
//导入counter.ts
import { useCounterStore } from "./counter";
import { initResetFun } from '@/utils/storeTools'
export interface IAppStore {
useCounter: ReturnType<typeof useCounterStore>;
// 其他store...
}
const appStore:IAppStore = {} as IAppStore;
/**
* 注册app状态库
*/
export const registerStore = () => {
appStore.useCounter = useCounterStore();
// 其他store...
//重写reset方法
initResetFun(appStore);
}
export default appStore;
简单修改一下counter Store的内容
javascript
//src/store/counter.ts
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
const increment= () => {
count.value++
}
const decrement= () => {
count.value--
}
return { count, doubleCount, increment,decrement }
})
总线注册
在src/main.ts项目总线注册
javascript
import './assets/main.css'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import { registerStore } from './store'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(createPinia())
app.use(router)
//注册pinia状态管理库
registerStore();
app.mount('#app')
具体业务组件使用
xml
//src/components/PiniaSetup.vue
<script setup lang='ts'>
import { storeToRefs } from 'pinia';
import appStore from '@/store/index';
// Pinia composition API 模式
const { count, doubleCount } = storeToRefs(appStore.useCounter)
const { increment,decrement } = appStore.useCounter
</script>
<template>
<div>
<h1>Pinia composition 模式!</h1>
<p>Pinia state:count=<b>{{ count }}</b></p>
<p>pinia getters:doubleCount=<b>{{ doubleCount }}</b></p>
<button @click="increment">
increment
</button>
<button @click="decrement">decrement</button>
</div>
</template>
<style lang='scss' scoped></style>
打包解耦
为了让appStore 实例与项目解耦,在构建时要把appStore 抽取到公共chunk,在vite.config.ts 做以下配置
javascript
build: {
// ...其他配置
rollupOptions: {
output: {
manualChunks(id) {
// 将pinia的全局库实例打包进vendor,避免和页面一起打包造成资源重复引入
if (id.includes(path.resolve(__dirname, 'src/store/index.ts'))) {
return 'vendor';
}
}
}
}
}
其他:
更多Pinia函数式(composition API)用法参考:juejin.cn/post/708903...
Vite.config.ts的全部配置内容
javascript
import { fileURLToPath, URL } from 'node:url'
import path from 'node:path'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
css:{
preprocessorOptions:{
scss:{
additionalData:'@import "@/assets/style/main.scss";'
}
}
},
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
'@assets': fileURLToPath(new URL('./src/assets', import.meta.url)),
'@components': fileURLToPath(new URL('./src/components', import.meta.url)),
'@views': fileURLToPath(new URL('./src/views', import.meta.url)),
'@utils': fileURLToPath(new URL('./src/utils', import.meta.url))
}
},
build: {
// ...其他配置
rollupOptions: {
output: {
manualChunks(id) {
// 将pinia的全局库实例打包进vendor,避免和页面一起打包造成资源重复引入
if (id.includes(path.resolve(__dirname, 'src/store/index.ts'))) {
return 'vendor';
}
}
}
}
}
})
环境变量配置
前置知识
vite 提供了两种模式:具有开发服务器的开发模式(development)和生产模式(production)
在项目根目录下,你可以创建一个或多个环境文件。这些文件以 .env 开头,后面可以跟上为特定模式(如 development、production)指定的后缀。例如:
- .env:在所有的环境中加载。
- .env.local:在所有的环境中加载,但会被 git 忽略。
- .env.development:只在开发环境中加载。
- .env.production:只在生产环境中加载。
新建.env.development、.env.production 文件
根目录新建 .env.development 文件,内容如下:
ini
NODE_ENV=development
VITE_APP_WEB_URL= 'YOUR WEB URL'
根目录新建 .env.production 文件 ,内容如下:
ini
NODE_ENV=production
VITE_APP_WEB_URL= 'YOUR WEB URL'
组件中使用:
arduino
console.log(import.meta.env.VITE_APP_WEB_URL)
打包区分开发环境和生产环境
package.json 的scripts中加入下面内容
json
"build:dev": "vite build --mode development",
"build:pro": "vite build --mode production"
Vite 常用打包优化配置
详见往期文章:基于Vite构建的Vue3+Ts项目打包优化全过程 - 掘金
更多Vite配置细节参考:Vite
Vite常用插件
插件官方文档:vitejs.cn/plugins/
- @vitejs/plugin-vue:这是 Vue 3 项目中的官方插件,用于支持单文件组件(.vue 文件)。
- @vitejs/plugin-react:用于支持 React 项目,提供 JSX 转换和相关优化。
- @vitejs/plugin-legacy: 为打包后的文件提供传统浏览器兼容性支持
- vite-plugin-svelte:用于集成 Svelte,一个类似于 Vue 和 React 的现代前端框架。
- vite-plugin-env-compatible:提供对 .env 环境变量文件的支持。
- vite-plugin-pages:用于自动生成路由,特别适用于 Vue 和 React 项目。
- vite-plugin-windicss:集成 Windi CSS,一种高效的实用工具优先的 CSS 框架。
- vite-plugin-compression:用于在构建过程中压缩资源,支持 gzip 或 brotli 压缩。
- vite-plugin-pwa:添加渐进式网络应用(PWA)支持。
- vite-plugin-svg-icons:用于优化 SVG 文件的处理和使用。
- vite-plugin-eslint:集成 ESLint,确保代码质量和风格的一致性。
- vite-plugin-stylelint:集成 Stylelint,用于 CSS/SCSS/Less 等样式文件的代码质量检查。
- unplugin-vue-components :组件的按需自动导入
- vite-plugin-compression :使用 gzip 或者 brotli 来压缩资源
- .....
参考文章
- vscode中不能使用命令pnpm_vscode无法执行pnpm-CSDN博客
- Vite2 + Vue3 + TypeScript + Pinia 搭建一套企业级的开发脚手架【值得收藏】 - 掘金
- 配置eslint+prettier+husky+lint-staged(pnpm版) - 掘金
- vscode中不能使用命令pnpm_vscode无法执行pnpm-CSDN博客
- 前端codeLint-- 为项目集成ESLint、StyleLint、commitLint实战和原理
- Commitlint 使用总结-CSDN博客
- www.cnblogs.com/walkermag/p...
- Vite 配置路径别名的流程 - 掘金
- GitHook 工具 ------ husky(格式化代码) - 掘金
- Pinia进阶:再谈Pinia函数式(composition API)用法 - 掘金
- www.cnblogs.com/zouzhongxin...
- eslintignore的忽略配置 - 掘金
- blog.csdn.net/a7442358/ar...
- 也许你不知道的npm-scripts - 掘金
- npm scripts 使用指南 - 阮一峰的网络日志