vite+vue3+typescript+vuex+vue-router+element-plus構建管理系統前端架構

語言: CN / TW / HK

theme: channing-cyan highlight: arduino-light


我正在參加「掘金·啟航計劃」

一、使用vite初始化

我這裏是使用yarn包管理工具安裝,使用npm或者pnpm的同理 執行下面shell命令創建一個新的項目模板

yarn create vite 項目名稱 --template vue-ts

創建成功後我們使用vscode編輯器打開項目,其中目錄結構如下圖:

Dingtalk_20221009163212.jpg ~~ps:忽略main.js和preload.js~~

此時我們執行yarn install安裝所需要的依賴包,安裝完必執行yarn dev會打開vite+vue的歡迎界面

二、配置eslint,prettier

1:eslint初始化

js // 執行下面命令 eslint --init 按照提示我們依次選擇以下幾個主要選項

``` ? How would you like to use ESLint? ... To check syntax only To check syntax and find problems

To check syntax, find problems, and enforce code style ? What type of modules does your project use? ... JavaScript modules (import/export) CommonJS (require/exports) None of these ? Which framework does your project use? ... React Vue.js None of these ? Does your project use TypeScript? » No / Yes ```

選擇推薦風格,這裏我們直接選第一個跟着引導去選擇aribn或者standard

```

Use a popular style guide Answer questions about your style Inspect your JavaScript file(s) ```

選擇完後,需要安裝一些eslint相關的依賴包,默認是用npm安裝,安裝完會自動生成一個eslintrc.js,內容如下

```js {

"env": {

    "browser": true,

    "es2021": true,

    "node": true

},

"extends": [

    "eslint:recommended",

    "plugin:vue/vue3-essential",

    "plugin:@typescript-eslint/recommended",

    "plugin:prettier/recommended"

],

"overrides": [

],

"parser": "vue-eslint-parser",

"parserOptions": {

    "ecmaVersion": "latest",

    "parser": "@typescript-eslint/parser",

    "sourceType": "module"

},

"plugins": [

    "vue",

    "@typescript-eslint"

],

"rules": {

    "@typescript-eslint/ban-types": [

        "error",

        {

            "extendDefaults": true,

            "types": {

                "{}": false

            }

        }

    ],

    "vue/multi-word-component-names":"off"

}

} ```

創建.eslintignore文件,忽略eslint不需要檢查的文件

js /index.html /lambda/ /scripts /config /plugins .history /tsconfig.json /src/vite-env.d.ts

2:配置prettier

安裝prettier yarn add prettier -D

解決 eslint 和 prettier 衝突\ 安裝 eslint-config-prettier\ \ 解決 ESLint 中的樣式規範和 prettier 中樣式規範的衝突,以 prettier 的樣式規範為準,使 ESLint 中的樣式規範自動失效\ eslint-plugin-prettier\ \ eslint-plugin-prettier插件會調用prettier對你的代碼風格進行檢查,其原理是先使用prettier對你的代碼進行格式化,然後與格式化之前的代碼進行對比,如果過出現了不一致,這個地方就會被prettier進行標記。\ 接下來,我們需要在rules中添加,"prettier/prettier": "error",表示被prettier標記的地方拋出錯誤信息。\ //.eslintrc.js { "plugins": ["prettier"], "rules": { "prettier/prettier": "error" } } 項目下新建 .prettierrc.json 文件 module.exports = { tabWidth: 2, jsxSingleQuote: true, jsxBracketSameLine: true, printWidth: 100, singleQuote: true, semi: false, overrides: [ { files: '*.json', options: { printWidth: 200, }, }, ], arrowParens: 'always', }

三、配置路徑別名,處理import引入時ts報錯

在vite-config.ts中添加如下配置

js base: './', // 設置打包路徑 resolve: { alias: { '@': path.resolve(__dirname, 'src'), }, extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json'], }

在tsconfig.json中增加配置 "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["./src/*"] }, } 此時的@就可以指向我們的src目錄了

在src文件夾下創建shims-vue.d.ts文件 添加我們import引入時ts報錯的模塊 // 例如 declare module 'axios'; declare module 'element-plus'; declare module 'js-cookie';

四、配置element-plus

elementUi的配置非常簡單這裏我就不説了,直接參考官方的配置指南就可以了 https://element-plus.gitee.io/zh-CN/guide/quickstart.html#%E5%85%A8%E5%B1%80%E9%85%8D%E7%BD%AE

五、配置vuex、vue-route、less開發環境

js // 我們一次把所有模塊都安裝上 yarn add vuex vue-router less less-loader less使用跟vue2沒有區別,安裝完loader可以直接在style裏面制定lang="less"

1:配置vuex

我們在src目錄下創建store文件夾,store文件夾下分別創建index.ts 和modules文件夾,其中modules下面是我們的每個不通的store

因為vuex修改了初始化的方法,這裏給vue2使用時略有區別,使用createStore創建store倉庫 ``` import { createStore } from 'vuex'; import getters from './getters'; import userStore from './modules/user'; import systemStore from './modules/system'; import permissionStore from './modules/permission'; const storeObj: any = { modules: { user: userStore, system: systemStore, permission: permissionStore,

},
getters,

}; export default createStore(storeObj); ``` ps:我這裏分別引入了三個store,還可以使用import.meta.globEager引入所有的文件,寫個通用函數來解析最好,因為vite中乜有require,這個功能既類似於require.context

配置完以上回到src/main.ts中,引入store

掛在store js import store from './store'; app.use(store)

2:配置vue-router

在src文件夾下創建router文件夾 ``` import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'; const constantRoutes: Array = [ { path: '/', name: 'layout', component: () => import('@/pages/layout/index.vue'), }, { path: '/login', name: 'login', component: () => import('@/pages/login/index.vue'), }, { path: '/404', name: '404', component: () => import('@/pages/error-page/404.vue'), },

]; // 權限用動態路由添加 export const asyncRoutes: any = []; export const router = createRouter({ history: createWebHistory(), routes: constantRoutes, }); // 權限用動態路由移除 export function resetRouter() { asyncRoutes.forEach((route: any) => { router.removeRoute(route.name); }); } 回到main.ts,仍然是引入掛載js import router from './router'; app.use(router) 這裏到了重點權限控制,我這裏使用動態路由控制權限 // 角色權限,動態路由 const whiteList = ['/login', '/404']; let pageRefresh = true; router.beforeEach(async (to, from) => { // 如果是login或者404頁面直接跳轉過去 if (whiteList.indexOf(to.path) !== -1) { if (to.path == '/login') { pageRefresh = true; } return true; } // 獲取token,如果用户沒登錄,則跳轉登錄頁面 const token = store.getters.token; if (!token) { router.push({ path: 'login', query: { redirect: to.path, }, }); } else { //如果為true説明已添加過直接跳過 if (!pageRefresh) { return true; } else { //後端獲取動態路由 await store .dispatch('permission/generateRoutes') // 到store下的permission中執行路由添加 .then((res: any) => { console.log(router.getRoutes()); // 沒有子路由時則回首頁 if (res && to.matched.length === 0) { router.push(to.fullPath); } }); pageRefresh = false; } } }); import { asyncRoutes, router } from '@/router'; import { RouteRecordRaw } from 'vue-router'; const _modules = import.meta.glob('@/pages//*.vue'); / * 後台查詢的菜單數據拼裝成路由格式的數據 * @param routes */ export function generaMenu(routes: any, data: any) { data.forEach((item: any) => { const menu = { path: item.path, component: () => _modules[/src/pages${item.component}.vue], // 這裏有坑,動態引入的組件無法添加,我嘗試了很多方式,最後使用## defineAsyncComponent引入解決的 children: [], name: item.menuName, meta: { title: item.title, icon: item.icon, noCache: item.noCache, }, }; if (item.children) { generaMenu(menu.children, item.children); } routes.push(menu); }); } const permission = { namespaced: true, state() { return { routes: [], }; }, mutations: { SET_ROUTES: (state: any, routes: any) => { state.routes = routes; }, }, actions: { generateRoutes({ commit }: any) { return new Promise((resolve) => { getRoutes().then((res: any) => { if (res.code === 200) { const { data } = res; const list = data[0].children; //獲取router添加到asyncrouter中

                    generaMenu(asyncRoutes, list);
                    console.log('調整好的路由', asyncRoutes);
                    // 添加路由
                    asyncRoutes.forEach((itemRouter: RouteRecordRaw) => {
                        router.addRoute('layout', itemRouter);
                    });
                    commit('SET_ROUTES', list);
                    resolve(list);
                } else {
                    ElMessage.error('菜單數據獲取異常');
                }
            });
        });
    },
},

}; export default permission; ```

end:到這裏我們基本完成了所有的配置,趕緊嘗試一下吧!!!