Vite 需要 Node.js 版本 >= 12.0.0
npm init vite@latest
yarn create vite
// 或者
# npm 6.x
npm init vite@latest 项目名称 --template vue
# npm 7+, 需要额外的双横线:
npm init vite@latest 项目名称 -- --template vue
# yarn
yarn create vite 项目名称 --template vue
以上命令,根据自己需要取一行即可。我用的是yarn create vite,没有yarn的可以安装一下
npm install -g yarn
yarn add @types/node -D //或者 npm i --save-dev @types/node
修改vue.config.ts
import { resolve } from 'path'
export default defineConfig({
//...
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
},
base: `./`, // 设置打包路径
})
修改tsconfig.ts
{
"compilerOptions": {
//...
"baseUrl": "./",
"paths": {
"@/*":["./src/*"],
}
},
//...
}
若未生效,关闭vscode重新打开下就好了。
yarn add ant-design-vue //或者 npm i --save ant-design-vue
修改main.ts(下方为全局引入模式)
import { createApp } from 'vue'
import App from './App.vue'
import Antd from 'ant-design-vue'
import 'ant-design-vue/dist/antd.css'
const app = createApp(App)
app.use(Antd).mount('#app')
文档地址: https://www.antdv.com/docs/vue/getting-started-cn
yarn add less -D // npm install --save-dev less
修改vue.config.ts
export default defineConfig({
//...
css: {
preprocessorOptions: {
less: {
modifyVars: {
'primary-color': `#333`, //此处可以写一些自定义变量
},
javascriptEnable: true
}
}
}
})
在src/components下新建index.ts
import * as Icons from '@ant-design/icons-vue'
// import ComponentVue from './ComponentVue.vue' // 替换为想要全局注册的组件
const icons: any = Icons
export default function install(app: any) {
// app.component('ComponentVue', ComponentVue) //注册
for(const i in icons){
app.component(i, icons[i])
}
}
修改main.ts
import components from '@/components/index'
app
.use(Antd)
.use(components)
.mount('#app')
yarn add vue-router -D //或者 npm install vue-router -D
在src下新建router文件夹,在其中建index.ts
import { createRouter, createWebHashHistory, createWebHistory, RouteRecordRaw } from 'vue-router'
const routes:Array = [
{
path: '/',
name: 'Home',
component: () => import(`@components/Home.vue`),
meta: {title: '首页'},
},
...
]
const router = createRouter({
history: createWebHashHistory(),//路径带# http://127.0.0.1:5173/#/
// history: createWebHistory(),//路径带# http://127.0.0.1:5173/
routes
})
export default router
修改main.ts
import router from '@/router/index'
app
.use(router)
.use(Antd)
.use(components)
.mount('#app')
yarn add pinia // 或者 npm install --save pinia
修改main.ts
import { createPinia } from 'pinia'
app
.use(router)
.use(createPinia())
.use(Antd)
.use(components)
.mount('#app')
store的创建及应用,请参考:
【学习vite + vue3 + pinia + ts】pinia应用 store的创建及应用_糖糖246的博客-CSDN博客
官方文档:
定义一个 Store | Pinia 中文文档
根目录下新建 .env.development 文件(开发环境)
VITE_BASE_URL = http://127.0.0.1:8080
根目录下新建 .env.production文件(生产环境)
VITE_BASE_URL = http://127.0.0.1:9090
修改 package.json
"scripts": {
"dev": "vite --mode development", //development为之前新建的开发环境env后边名字
...
},
在组件中使用环境变量
console.log(import.meta.env)
在vue.config.ts中使用环境变量
import { defineConfig, loadEnv } from 'vite'
export default ({mode}:any) => {
const obj = loadEnv(mode, process.cwd())
console.log(obj)
return defineConfig({ ..... })
}
yarn add axios //或者 npm install --save axios
import axios from 'axios'
import { notification } from "ant-design-vue"
interface CustomObj {
[propName: string]: any
}
interface ErrorObj {
code: string,
message: string,
}
//开发环境下解决不能添加cookie
if (import.meta.env.MODE === `development`) {
axios.defaults.headers.post[`User`] = `admin` //与后台配合识别登录用户
axios.defaults.headers.post[`Uid`] = `12345678913` //与后台配合识别登录用户
}
axios.defaults.headers.post[`Content-Type`] = `application/json;charset=UTF-8`
const $http = axios.create({ baseURL: import.meta.env.VITE_BASE_URL })
//定义错误情况的处理函数
const errorHandler = (error: ErrorObj) => {
notification.warning({
message: error.code,
description: error.message
})
}
// 请求拦截器
$http.interceptors.request.use(
config => {
return config
},
error => {return Promise.reject(error)}
)
//定义记录请求取消的相关函数与变量
let source: CustomObj = {}
let requestList:string[] = []
function cancelRequest(path:string, allCancel?:boolean):void {
if (requestList.includes(path) && typeof source[path]==='function'){
source[path]('终止请求')
}
else if(allCancel) {
requestList.forEach(el =>{
source[el]('批量终止请求')
})
}
}
// 响应拦截器
$http.interceptors.response.use(
(res: any) => {
//从记录的可能取消的路径数据中剔除已经完成请求的路径
const path = JSON.stringify(res.config.url)
requestList = requestList.filter(item => !path.includes(item))
//根据返回的code,对响应结果进行处理
if (String(res.data.code) === '000000') {
return Promise.resolve(res.data.data)
}
else {
return errorHandler(res.data as ErrorObj)
}
},
error => {
return Promise.reject(error)
},
)
//封装请求
const get = (url:string = ``, config?:CustomObj):Promise => {
return $http.get(url, config)
}
const post = (url = ``, params:CustomObj = {}, config?:CustomObj):Promise => {
//取消未结束的上次同路径请求
if(requestList.length) {
cancelRequest(url)
}
//根据配置情况,决定是否将该路径加到取消请求路径数组中
if(config?.isCancelRequest){
requestList.push(url)
}
return $http.post(url, params, {
...config,
cancelToken: new axios.CancelToken(c=>{
source[url] = c
}) //取消请求设置
}).catch(error => {
throw new Error(error)
})
}
const ssoPost = (url = ``, params:CustomObj = {}, config?:CustomObj):Promise => {
const formatDate = new FormData()
for (const key in params) {
formatDate.append(key, params[key])
}
return $http.post(url, formatDate, {
...config,
baseURL: import.meta.env.VITE_BASE_URL_SSO,
}).catch(error => {
throw new Error(error)
})
}
export {
get, post, ssoPost,
}
import { post, ssoPost } from '@/servers/axios'
enum Url {
login = '/login', //登录接口
list = '/list', //列表接口
}
//params:any config?:any 根据自己需求写类型接口
export function login(params:any,config?:any){
return ssoPost(Url.login, params, config)
}
export function getList(params:any,config?:any){
return post(Url.list, params, {...config, isCancelRequest: true})
}
yarn add -D eslint eslint-plugin-import eslint-plugin-vue
yarn add -D prettier eslint-plugin-prettier eslint-config-prettier
yarn add -D stylelint stylelint-config-standard stylelint-order
yarn add -D @typescript-eslint/parser postcss-html
module.exports = {
env: {
browser: true,
es2021: true,
node: true,
},
extends: [`plugin:vue/vue3-recommended`, `prettier`],
parserOptions: {
ecmaVersion: 12,
parser: `@typescript-eslint/parser`,
sourceType: `module`,
},
plugins: [`vue`, `@typescript-eslint`, `prettier`],
rules: {
'block-scoped-var': `error`, // 强制变量在其作用域内使用
'class-methods-use-this': [
// 强制class使用this
`error`,
{ exceptMethods: [] },
],
'no-debugger': `warn`,
'no-console': `warn`,
'no-undef': `off`,
'no-unused-vars': `off`,
'no-alert': `error`, // 禁用alert confirm
'no-eval': `error`, // 金庸eval
'no-multi-spaces': `error`, // 禁止使用多个空格
'no-multi-str': `error`, // 禁止使用多行字符串
'no-new-func': `error`, // 禁止使用new Function
'no-new-wrappers': `error`, // 禁止对 String,Number 和 Boolean 使用 new 操作符
'no-return-assign': `error`, // 禁止在return 中使用赋值语句
'no-return-await': `error`, // 禁止不必要的return await
radix: `error`, // 强制paserInt使用基数参数
// 以下是代码风格
semi: [`error`, `never`], //没有分号
'no-extra-parens': [`error`, `all`], // 禁止任何地方出现不必要的圆括号
'array-bracket-spacing': [`error`, `never`], // 中括号内禁用多余的空格或空行
'array-bracket-newline': [`error`, `consistent`], // 中括号使用一致的换行规则
'array-element-newline': [`error`, `consistent`], // 数组间使用一致的换行规则
'block-spacing': `error`, // 左花括号前后必须有一个空格
camelcase: [`error`, { properties: `never` }], // 强制使用驼峰命名法
'comma-dangle': [`error`, `always-multiline`], // 当最后一个元素或属性与闭括号 ] 或 } 在 不同的行时,要求使用拖尾逗号;当在 同一行时,禁止使用拖尾逗号
'comma-spacing': [`error`, { before: false, after: true }], // 逗号前禁止使用空格,逗号后使用必须一个或多个空额
'comma-style': [`error`, `last`], //要求逗号放在数组元素、对象属性或变量声明之后,且在同一行
'computed-property-spacing': [`error`, `never`], // 禁止在计算属性中括号中使用空格
'eol-last': [`error`, `always`], // 禁止文件末尾存在空行
'func-call-spacing': [`error`, `never`], // 禁止在函数调用的函数名和开括号之间有空格
'function-paren-newline': [`error`, `multiline`], // 如果函数的任一参数有换行,则要求在函数括号内换行。否则禁止换行
'implicit-arrow-linebreak': [`error`, `beside`], // 禁止在箭头函数体之前出现换行
indent: [`error`, 2], // 强制使用两个空格换行
// 'id-length': ["error", { min: 3, max: 30 }], // 强制标识符的最大为20和最小长度为3
'jsx-quotes': [`error`, `prefer-single`], // 强制所有不包含单引号的 JSX 属性值使用单引号
'key-spacing': [`error`, { beforeColon: false, afterColon: true }], // 要求对象字面量冒号前无空格,冒号与值之间有一个空格
'keyword-spacing': [`error`, { before: true, after: true }], // 强制关键字前后必须有一个空格
'new-cap': `error`, //要求构造函数首字母大写
'newline-per-chained-call': [`error`, { ignoreChainWithDepth: 2 }], // 要求链式调用多于两层时换行
'no-array-constructor': `error`, // 禁止使用Array构造函数
'no-new-object': `error`, // 禁用Object构造函数
'no-lonely-if': `error`, // 禁止 if 语句作为唯一语句出现在 else 语句块中
'no-multi-assign': `error`, // 禁止连续赋值
'no-multiple-empty-lines': [`error`, { max: 2 }], // 强制连续换行不得大于两行
'no-trailing-spaces': [`error`, { skipBlankLines: false, ignoreComments: false }], // 禁止在空行和块注释中使用空白符
'no-unneeded-ternary': `error`, // 禁止在有更简单的表达式时使用三元操作符
'no-whitespace-before-property': `error`, // 禁止点操作符前后有空白
'nonblock-statement-body-position': [`error`, `beside`], // 禁止单行语句前有换行
'object-curly-newline': [`error`, { multiline: true }], // 要求花括号间有一致的换行操作
'object-curly-spacing': [`error`, `always`], // 要求花括号内有空格
quotes: [`error`, `backtick`], // 要求尽可能地使用反引号
'semi-spacing': [`error`, { before: false, after: true }], // 强制分号之后有空格,禁止分号之前有空格
'space-before-blocks': `error`, // 要求块之前有空格
'space-before-function-paren': `off`, // 要求function函数左圆括号之前有一个空格
'space-in-parens': [`error`, `never`], // 强制圆括号内不能有空格
'space-unary-ops': `error`, // 强制 words 一元操作符后空格和 nonwords 一元操作符之前或之后的空格的一致性
// es6
'arrow-spacing': `error`, // 强制箭头函数箭头左右有一个空格
'no-var': `error`, // 禁用var
'prefer-template': `error`, // 禁用字符串连接,使用模板字符串
'prefer-const': `error`, // 不变量使用const
'no-console': `off`,
'generator-star-spacing': `warn`,
'no-global-assign': [`error`],
'vue/no-unused-components': `off`,
'vue/multi-word-component-names': `off`,
'vue/no-parsing-error': [2, { 'x-invalid-end-tag': false }],
indent: `off`,
'vue/script-indent': [
`error`,
2,
{
baseIndent: 1,
switchCase: 0,
},
],
'vue/html-self-closing': [
`error`,
{
html: {
void: `always`,
normal: `always`,
component: `always`,
},
svg: `always`,
math: `always`,
},
],
},
}
# Created by .ignore support plugin (hsz.mobi)
### Example user template template
### Example user template
codebase
# IntelliJ project files
.idea
.vscode
.git
*.iml
out
gen
dist
*.d.ts
# Created by .ignore support plugin (hsz.mobi)
### Example user template template
### Example user template
codebase
# IntelliJ project files
.idea
.vscode
.git
*.iml
out
gen
dist
*.d.ts
node_modules
public
src/assets
{
"tabWidth": 2,
"jsxSingleQuote": true,
"bracketSameLine": false,
"printWidth": 100,
"singleQuote": true,
"semi": false,
"overrides": [
{
"files": "*.json",
"options": {
"printWidth": 200
}
}
],
"arrowParens": "avoid",
"htmlWhitespaceSensitivity": "ignore",
"vueIndentScriptAndStyle": true
}
{
"extends": ["stylelint-config-standard"],
"overrides": [
{
"files": ["*.vue", "**/*.vue"],
"customSyntax": "postcss-html"
},
{
"files": ["*.html", "**/*.html"],
"customSyntax": "postcss-html"
}
],
"plugins": ["stylelint-order"],
"rules": {
"order/order": ["declarations", "custom-properties", "dollar-variables", "rules", "at-rules"],
"order/properties-order": [
"position",
"z-index",
"top",
"bottom",
"left",
"right",
"float",
"clear",
"columns",
"columns-width",
"columns-count",
"column-rule",
"column-rule-width",
"column-rule-style",
"column-rule-color",
"column-fill",
"column-span",
"column-gap",
"display",
"grid",
"grid-template-rows",
"grid-template-columns",
"grid-template-areas",
"grid-auto-rows",
"grid-auto-columns",
"grid-auto-flow",
"grid-column-gap",
"grid-row-gap",
"grid-template",
"grid-template-rows",
"grid-template-columns",
"grid-template-areas",
"grid-gap",
"grid-row-gap",
"grid-column-gap",
"grid-area",
"grid-row-start",
"grid-row-end",
"grid-column-start",
"grid-column-end",
"grid-column",
"grid-column-start",
"grid-column-end",
"grid-row",
"grid-row-start",
"grid-row-end",
"flex",
"flex-grow",
"flex-shrink",
"flex-basis",
"flex-flow",
"flex-direction",
"flex-wrap",
"justify-content",
"align-content",
"align-items",
"align-self",
"order",
"table-layout",
"empty-cells",
"caption-side",
"border-collapse",
"border-spacing",
"list-style",
"list-style-type",
"list-style-position",
"list-style-image",
"ruby-align",
"ruby-merge",
"ruby-position",
"box-sizing",
"width",
"min-width",
"max-width",
"height",
"min-height",
"max-height",
"padding",
"padding-top",
"padding-right",
"padding-bottom",
"padding-left",
"margin",
"margin-top",
"margin-right",
"margin-bottom",
"margin-left",
"border",
"border-width",
"border-top-width",
"border-right-width",
"border-bottom-width",
"border-left-width",
"border-style",
"border-top-style",
"border-right-style",
"border-bottom-style",
"border-left-style",
"border-color",
"border-top-color",
"border-right-color",
"border-bottom-color",
"border-left-color",
"border-image",
"border-image-source",
"border-image-slice",
"border-image-width",
"border-image-outset",
"border-image-repeat",
"border-top",
"border-top-width",
"border-top-style",
"border-top-color",
"border-top",
"border-right-width",
"border-right-style",
"border-right-color",
"border-bottom",
"border-bottom-width",
"border-bottom-style",
"border-bottom-color",
"border-left",
"border-left-width",
"border-left-style",
"border-left-color",
"border-radius",
"border-top-right-radius",
"border-bottom-right-radius",
"border-bottom-left-radius",
"border-top-left-radius",
"outline",
"outline-width",
"outline-color",
"outline-style",
"outline-offset",
"overflow",
"overflow-x",
"overflow-y",
"resize",
"visibility",
"font",
"font-style",
"font-variant",
"font-weight",
"font-stretch",
"font-size",
"font-family",
"font-synthesis",
"font-size-adjust",
"font-kerning",
"line-height",
"text-align",
"text-align-last",
"vertical-align",
"text-overflow",
"text-justify",
"text-transform",
"text-indent",
"text-emphasis",
"text-emphasis-style",
"text-emphasis-color",
"text-emphasis-position",
"text-decoration",
"text-decoration-color",
"text-decoration-style",
"text-decoration-line",
"text-underline-position",
"text-shadow",
"white-space",
"overflow-wrap",
"word-wrap",
"word-break",
"line-break",
"hyphens",
"letter-spacing",
"word-spacing",
"quotes",
"tab-size",
"orphans",
"writing-mode",
"text-combine-upright",
"unicode-bidi",
"text-orientation",
"direction",
"text-rendering",
"font-feature-settings",
"font-language-override",
"image-rendering",
"image-orientation",
"image-resolution",
"shape-image-threshold",
"shape-outside",
"shape-margin",
"color",
"background",
"background-image",
"background-position",
"background-size",
"background-repeat",
"background-origin",
"background-clip",
"background-attachment",
"background-color",
"background-blend-mode",
"isolation",
"clip-path",
"mask",
"mask-image",
"mask-mode",
"mask-position",
"mask-size",
"mask-repeat",
"mask-origin",
"mask-clip",
"mask-composite",
"mask-type",
"filter",
"box-shadow",
"opacity",
"transform-style",
"transform",
"transform-box",
"transform-origin",
"perspective",
"perspective-origin",
"backface-visibility",
"transition",
"transition-property",
"transition-duration",
"transition-timing-function",
"transition-delay",
"animation",
"animation-name",
"animation-duration",
"animation-timing-function",
"animation-delay",
"animation-iteration-count",
"animation-direction",
"animation-fill-mode",
"animation-play-state",
"scroll-behavior",
"scroll-snap-type",
"scroll-snap-destination",
"scroll-snap-coordinate",
"cursor",
"touch-action",
"caret-color",
"ime-mode",
"object-fit",
"object-position",
"content",
"counter-reset",
"counter-increment",
"will-change",
"pointer-events",
"all",
"page-break-before",
"page-break-after",
"page-break-inside",
"widows"
],
"no-empty-source": null,
"property-no-vendor-prefix": [true, { "ignoreProperties": ["background-clip"] }],
"number-no-trailing-zeros": true,
"length-zero-no-unit": true,
"value-list-comma-space-after": "always",
"declaration-colon-space-after": "always",
"value-list-max-empty-lines": 0,
"shorthand-property-no-redundant-values": true,
"declaration-block-no-duplicate-properties": true,
"declaration-block-no-redundant-longhand-properties": true,
"declaration-block-semicolon-newline-after": "always",
"block-closing-brace-newline-after": "always",
"media-feature-colon-space-after": "always",
"media-feature-range-operator-space-after": "always",
"at-rule-name-space-after": "always",
"indentation": 2,
"no-eol-whitespace": true,
"string-no-newline": null
}
}
"scripts": {
...
"lint": "eslint src --fix --ext .ts,.tsx,.vue,.js,.jsx",
"prettier": "prettier --write .",
"lintless": "stylelint src/**/* --fix"
},
修改vscode的setting.json
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
根据以下命令执行
npm install husky --save-dev
npx husky install
npm set-script prepare "husky install"
npx husky add .husky/pre-commit "npm run lint"
git add .husky/pre-commit
npm install -D lint-staged
修改package.json
{
"lint-staged": {
"*.{ts,js,vue}": [
"eslint --fix",
"prettier --write ."
],
"*.{css,less,vue}": [
"stylelint --fix"
]
}
}
npx husky add .husky/pre-commit "npx lint-staged"
giteed地址:vue3_antd: vite_vue3_pinia_ts_antd_less打包构建工具是vite,技术库是vue3+ts+pinia+vue-router@4,ui库是ant design for vue,css预编译器是less,