距离上一次,脚手架文章《手把手Vue3项目(一)》已经过去了10个月,
这一次,随着Vue3正式普及,同时也能让更多的小伙伴,快速进入Vue3项目的开发,
这里我重新搭建了一个Vue3脚手架模板,并试图教会大家如何安装和配置一个Vue3的项目,
其中涉及几乎一个企业项目所包含的所有内容,希望可以帮到大家,
此项目可以从gitee上clone后直接使用,地址在文末
使用手册 1 2 3 4 5 6 1. cd vue3-scaffold-template 2. pnpm install 或 npm install 3. pnpm dev 或 npm run dev 启动项目 4. pnpm jsondb 或 npm run jsondb 启动json-server服务器 有两个案例,配置管理、时间管理App供大家参考。
安装和配置过程
授人以鱼不如授人以渔,
这个脚手架,大家可以clone下来,直接进入自己的项目开发中,希望大家用的开心。
创建项目
然后按照提示操作即可!
这里我选择的是:Vue、TypeScript,Vite 目前默认Vue3
配置src目录为默认目录 vite.config.ts 中配置
1 2 3 resolve : { alias : [{ find : '@' , replacement : path.resolve (__dirname, './src' ) }] },
安装Element-Plus 参照 Element-Plus 快速上手
安装 Element-Plus
需要先安装按需导入的两款插件
1 pnpm add unplugin-vue-components unplugin-auto-import -D
vite.config.ts 中配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import { defineConfig } from 'vite' import AutoImport from 'unplugin-auto-import/vite' import Components from 'unplugin-vue-components/vite' import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' export default defineConfig ({ plugins : [ AutoImport ({ resolvers : [ElementPlusResolver ()], }), Components ({ resolvers : [ElementPlusResolver ()], }), ], })
在实际代码中测试,是否生效
安装Element Plus 图标
安装Element Icon图标
1 pnpm install @element-plus/icons-vue
自动导入图标(可以使用,但考虑到项目开发,本人弃用此方案)
从 iconify(图标网站) 中自动导入任何图标集
自动导入必须遵循名称格式 {prefix:默认为i}-{collection:图标集合的名称}-{icon:图标名称}
<**el-icon** color=”#000” size=”22”>
<**i-ep-expand** />
</**el-icon**>
需要先安装按需导入的两款插件
1 pnpm add unplugin-icons unplugin-auto-import -D
vite.config.ts 中配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 import path from 'path' import { defineConfig } from 'vite' import Vue from '@vitejs/plugin-vue' import Icons from 'unplugin-icons/vite' import IconsResolver from 'unplugin-icons/resolver' import AutoImport from 'unplugin-auto-import/vite' import Components from 'unplugin-vue-components/vite' import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' import Inspect from 'vite-plugin-inspect' const pathSrc = path.resolve (__dirname, 'src' )export default defineConfig ({ plugins : [ AutoImport ({ imports : ['vue' ], resolvers : [ ElementPlusResolver (), IconsResolver ({ prefix : 'Icon' , }), ], dts : path.resolve (pathSrc, 'auto-imports.d.ts' ), }), Components ({ resolvers : [ IconsResolver ({ enabledCollections : ['ep' ], }), ElementPlusResolver (), ], dts : path.resolve (pathSrc, 'components.d.ts' ), }), Icons ({ autoInstall : true , }), Inspect (), ], })
在实际代码中测试,是否生效
1 2 3 <el-icon color="#000" size="22"> <i-ep-expand /> </el-icon>
全局注册图标(本人选用方案) 1 2 3 4 5 6 7 import * as ElementPlusIconsVue from '@element-plus/icons-vue' const app = createApp (App )for (const [key, component] of Object .entries (ElementPlusIconsVue )) { app.component (key, component) }
Eslint、Prettier、 Husky、Githooks、commit-msg
需要安装的依赖
1 2 3 4 5 6 7 8 pnpm add eslint eslint-plugin-vue @typescript-eslint/parser @typescript-eslint/eslint-plugin vue-eslint-parser -D pnpm add prettier eslint-config-prettier eslint-plugin-prettier -D pnpm add husky lint-staged -D pnpm add @commitlint/config-conventional @commitlint/cli -D
相关配置
eslint .eslint.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 module .exports = { root : true , env : { browser : true , es2021 : true , node : true }, parser : 'vue-eslint-parser' , parserOptions : { parser : '@typescript-eslint/parser' , ecmaVersion : 2021 , sourceType : 'module' , ecmaFeatures : { tsx : true , jsx : true }, extends : [ 'plugin:vue/vue3-recommended' , 'eslint:recommended' , 'plugin:@typescript-eslint/recommended' , 'prettier/@typescript-eslint' , 'plugin:prettier/recommended' ], rules : {} } };
.eslintignore 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 *.sh node_modules *.md *.woff *.ttf .vscode .idea dist *.zip /public /docs .husky .local /bin Dockerfile /src/utils/vendor
prettier .prettierrc.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 module .exports = { printWidth : 100 , tabWidth : 2 , semi : false , singleQuote : true , quoteProps : 'as-needed' , bracketSpacing : true , jsxBracketSameLine : true , htmlWhitespaceSensitivity : 'ignore' , trailingComma : 'none' , useTabs : false , jsxSingleQuote : false , arrowParens : 'always' , rangeStart : 0 , proseWrap : 'always' , endOfLine : 'lf' };
.prettierignore 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package.json /dist .DS_Store .eslintignore *.png .editorconfig .gitignore .prettierignore .eslintcache *.lock yarn-error.log .history CNAME yarn.lock
husky 参考链接:
pre-commit 代码提交前(代码格式化、修复)
配置husky
1 2 3 4 5 npx husky-init && npm install npx husky-init && yarn yarn dlx husky-init --yarn2 && yarn pnpm dlx husky-init && pnpm install
它将设置 husky,修改package.json
并创建一个pre-commit
您可以编辑的示例挂钩。默认情况下,它将npm test
在您提交时运行,但是你需要自己找到.husky/pre-commim文件
把其中的npm test
改成npm run lint-staged
,并在package.json
中配置提交前所需要做的操作,配置内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 { "scripts" : { "lint-staged" : "lint-staged" , } , "lint-staged" : { "*.{js,jsx,ts,tsx,less,scss}" : [ "prettier --write" , "eslint --cache --fix" , "git add" ] } }
commit-msg配置
要使用husky add
添加另一个钩子commit-msg
1 npx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'
它将在.husky目录
下生成一个commit-msg
文件,进行提交的commit-msg检测,如果不符合规范会给出提示;同时需要在.commitment.config.js
中添加配置,下面的配置可以直接使用,也可以自定义
commitment.config.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 module .exports = { extends : ['@commitlint/config-conventional' ], rules : { 'body-leading-blank' : [2 , 'always' ], 'footer-leading-blank' : [1 , 'always' ], 'header-max-length' : [2 , 'always' , 108 ], 'subject-empty' : [2 , 'never' ], 'type-empty' : [2 , 'never' ], 'type-enum' : [ 2 , 'always' , [ 'feat' , 'fix' , 'perf' , 'style' , 'docs' , 'refactor' , 'build' , 'ci' , 'test' , 'revert' , 'merge' , 'chore' ] ] } }
测试
1 2 npx commitlint --from HEAD~1 --to HEAD --verbose
Vue-Router 4
安装依赖
配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 import {createRouter, createWebHistory} from "vue-router" ;import {routes} from "@/router/config" ;const router = createRouter ({ history : createWebHistory (), routes }) export default routerexport const routes = [ { path : '/' , redirect : '/home' , }, { path : '/home' , component : () => import ("@modules/home/Index.vue" ) }, { path : '/about' , component : () => import ("@modules/about/Index.vue" ) } ] import {createApp} from 'vue' import router from "@/router" ;import App from './App.vue' import "ant-design-vue/dist/antd.less" const app = createApp (App )app.use (router) app.mount ('#app' ) <script setup lang="ts" > </script> <template > <router-view > </router-view > </template > <style > </style >
路由权限、nprogress
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 import router from '@/router' import './permission' app.use (router) app.mount ('#app' ) import router from '@/router/index' import NProgress from 'nprogress' import 'nprogress/nprogress.css' import { RouteLocationNormalized } from 'vue-router' NProgress .configure ({ showSpinner : false })router.beforeEach (async (to, from ) => { NProgress .start () if (to.path .indexOf ('40' ) > -1 ) { to.meta = from .meta to.name = from .name } await handleRouterQuery (to, from ) }) router.afterEach (() => { NProgress .done () }) let currentPath : string const Reg = /(^\/user(?!\/dashboard).*)/ async function handleRouterQuery (to : RouteLocationNormalized , from : RouteLocationNormalized ) { const { path, fullPath } = to if (!Reg .test (path)) return if (currentPath !== fullPath) { currentPath = fullPath } return }
Pinia
安装依赖
配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import { createPinia } from 'pinia' import '@/store/index' app.use (createPinia ()) app.mount ('#app' ) import { acceptHMRUpdate } from 'pinia' const modulesFiles = import .meta .globEager ('./modules/*.ts' )Object .keys (modulesFiles).forEach ((modulePath ) => { const store = modulesFiles[modulePath] Object .keys (store).forEach ((key ) => { if (key.startsWith ('use' )) { if (import .meta .hot ) { import .meta .hot .accept (acceptHMRUpdate (store[key], import .meta .hot )) } } }) }) import { defineStore } from 'pinia' interface IState { topic : any } export const useMessageStore = defineStore<'message' , IState >('message' , { state : () => ({ topic : {} }) })
Scss、tailwindcss、postcss、autoprefixer
需要的依赖
1 pnpm add postcss sass tailwindcss @tailwindcss/line-clamp autoprefixer -D
posts.config.js
1 2 3 4 5 6 7 module .exports = { plugins : { tailwindcss : {}, autoprefixer : {}, }, }
tailwind.config.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 module .exports = { content : ['./index.html' , './src/**/*.{vue,js,ts,jsx,tsx}' ], theme : { extend : { colors : { normal : '#3693FF' , hover : '#0068E0' , active : '#004799' , background : '#f4f6fa' , title : '#333333' , content : '#666666' , username : '#303133' , operate : '#959EAD' }, spacing : { 32 : '32px' , 4 : '4px' , 36 : '36px' , 16 : '16px' , 24 : '24px' , 8 : '8px' , 12 : '12px' , 10 : '10px' , 18 : '18px' , 20 : '20px' , 48 : '48px' }, borderRadius : { none : '0' , small : '8px' , large : '16px' }, fontSize : { base : '14px' , lg : '16px' , '2lg' : '19px' , m : '20px' , xl : '24px' , '2xl' : '32px' , '3xl' : '40px' , '4xl' : '48px' } } }, mode : 'jit' , plugins : [require ('@tailwindcss/line-clamp' )] };
vite.config.ts
1 2 3 4 5 6 7 8 9 10 11 12 import { defineConfig } from 'vite' export default defineConfig ({ css : { modules : { scopeBehaviour : 'local' , generateScopedName : (name ) => { return name } } } })
axios封装和使用 1 2 3 1 . src/service/index.ts 2 . src/api/index.ts
全局参数 1 2 3 4 5 import Global from './config/global' app.config .globalProperties .GLOBAL = Global
Element Plus 国际化 1 2 3 4 5 6 7 8 import ElementPlus from 'element-plus' import zhCn from 'element-plus/es/locale/lang/zh-cn' app.use (ElementPlus , { locale : zhCn, size : 'default' }) app.mount ('#app' )
Find me Gitee:gitee.com/heyhaiyon
微信公众号:heyhaiyang
掘金:heyhaiyang
头条号:heyhaiyang
微信群:可以在公众号中获取,文章不让放群二维码