vite-v3-ts-0到0.8

从0到0.8

  1. vite 创建项目
  2. eslint
  3. prettier
  4. EditorConfig
  5. 提交代码检测:husky && lint-staged
  6. proxy
  7. env-development
  8. 引入vuex@next
  9. 引入vue-router@next
  10. 引入axios
  11. 按需引入element-plus
  12. 引入scss及初始化样式


vite 创建项目

  • npm init @vitejs/app demo-name


eslint

  1. 安装 eslint: npm install eslint --save-dev
  2. 初始化 eslint 文件:npx eslint --init自动生成.eslintrc.js 文件
  3. 配置 rules、settings,.eslintrc.js 文件:
// .eslintrc.js
module.exports = {
  env: {
    browser: true,
    es2021: true,
  },
  extends: [
    'plugin:vue/essential',
    'airbnb-base',
  ],
  parserOptions: {
    ecmaVersion: 12,
    parser: '@typescript-eslint/parser',
    sourceType: 'module',
  },
  plugins: [
    'vue',
    '@typescript-eslint',
  ],
  rules: {
    'import/no-unresolved': 'off',
    'import/extensions': 'off',
    'import/no-extraneous-dependencies': 'off',
  },
  settings: {
    'import/resolver': {
      alias: {
        map: [
          ['@', './src'],
        ],
      },
    },
  },
};

  1. vite.config.ts 配置了别名之后,tsconfig 也需要配置 paths/baseUrl
// vite.config.ts
{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "moduleResolution": "node",
    "strict": true,
    "jsx": "preserve",
    "sourceMap": true,
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "lib": ["esnext", "dom"],
    "baseUrl": "./",
    "paths": {
      "@/*": ["./src/*"],
    }
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
}

  1. 可建.eslintignore 忽略不需要 eslint 检测的文件
/node_modules/



prettier

  1. 安装npm install --save-dev eslint-plugin-prettier npm install --save-dev --save-exact prettier npm install --save-dev eslint-config-prettier
  2. plugin:prettier/recommended 的配置需要注意的是,一定要放在最后。因为 extends 中后引入的规则会覆盖前面的规则。
  3. eslint 的插件 eslint-config-prettier,这个插件的作用是禁用所有与格式相关的 eslint 规则,也就是说把所有格式相关的校验都交给 prettier 处理。
  4. 修改.eslintrc.js:
// .eslintrc.js
extends: [
  "plugin:vue/vue3-recommended",
  "airbnb-base",
  "plugin:prettier/recommended",
],
rules: {
  "prettier/prettier": "off",
},

  1. 新建.prettierrc.js 自定义 prettier 规则:
// .prettierrc.js
module.exports = {
  useTabs: false,
  tabWidth: 2,
  printWidth: 100,
  singleQuote: true,
  trailingComma: 'es5',
  bracketSpacing: true,
  semi: true,
};

  • ps: 项目中的 prettier 配置生效前提是有动作促使它执行,如 vscode 的 settings.json 中"editor.formatOnSave": true,保存格式化会执行项目中的 prettier 文件,项目中没有该文件会执行编辑器自带的 prettier。


EditorConfig

  1. vscode 安装 EditorConfig for VS Code 插件
  2. 根目录下新建.editorconfig 文件:
// .editorconfig
# Editor configuration, see http://editorconfig.org

# 表示是最顶层的 EditorConfig 配置文件
root = true

[*] # 表示所有文件适用
charset = utf-8 # 设置文件字符集为 utf-8
indent_style = space # 缩进风格(tab | space)
indent_size = 2 # 缩进大小
end_of_line = lf # 控制换行类型(lf | cr | crlf)
trim_trailing_whitespace = true # 去除行尾的任意空白字符
insert_final_newline = true # 始终在文件末尾插入一个新行
curly_bracket_next_line = true # 大括号不另起一行
spaces_around_operators = true # 运算符两遍都有空格

[*.md] # 表示仅 md 文件适用以下规则
max_line_length = off
trim_trailing_whitespace = false



提交代码检测:husky && lint-staged

  1. husky,主要用于关联 git 的钩子函数,在执行相关 git hooks 时候进行自定义操作,如提交前进行 eslint 校验,提交时检验 commit message 等;, npx husky-init && npm install,
  2. v7 版本执行命令后会生成.husky 文件夹,pre-commit 文件便是在 git 提交前会执行的操作,想要在提交前执行 eslint 校验代码,因此修改 husky 的 pre-commit 文件即可:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
# npm test
eslint . --ext .js, .ts, .vue --fix # 校验所有的js-ts-vue文件并修复可自动修复的问题
git add . # 用于将自动修复后盖板的文件添加到暂存区
exit 1 # 终止命令,用来测试钩子
  1. lint-staged:只对暂存区的文件执行 lint,可以实现每次提交时只校验自己修改的文件,npm install lint-staged --save-dev
  2. 修改 package.json 文件
 "scripts": {
    "dev": "vite",
    "build": "vue-tsc --noEmit && vite build",
    "serve": "vite preview",
    "prepare": "husky install",
    "lint-staged": "lint-staged"
  },
  "lint-staged": {
    "*.{ts,js,vue}": [
      "eslint --fix",
      "git add ."
    ]
  },
  1. 修改 husky:添加 lint-staged 配置后,husky 就不在需要直接调用 eslint 了,修改.husky/pre-commit 文件:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
# npm test
# eslint . --ext .js, .ts, .vue --fix # 校验所有的js-ts-vue文件并修复可自动修复的问题
# git add . # 用于将自动修复后盖板的文件添加到暂存区
# exit 1 # 终止命令,用来测试钩子

npm run lint-staged



proxy && port && alias

  1. 新建 compile/proxy.ts 文件
module.exports = {
  '/api': {
    target: 'https://*.**.com/',
    changeOrigin: true,
    rewrite: (path) => path.replace(/^\/api/, ''),
  },
};

  1. 修改 vite.config.ts 文件
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
const proxy = require('./compile/proxy');
export default defineConfig({
  plugins: [
    vue(),
  ],
  server: {
    port: 6688,
    open: true,
    cors: true,
    // 为开发服务器配置自定义代理规则
    proxy,
  },
  // 别名
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src'),
    },
  },
});
  1. 修改 eslintrc.js 文件:
  settings: {
    'import/resolver': {
      alias: {
        map: [['@', './src']],
      },
    },
  },
  1. 修改 tsconfig.json 文件:
{
  "compilerOptions": {
    "paths": {
      "@/*": ["./src/*"],
    }
  }
}


env-development 环境变量

  1. src/.env.development 文件: VITE_BASE_URL = /api
  2. 对应类型声明文件 src/.env.d.ts:
// 建议类型声明文件,方便.提醒,.出存在字段
// 环境变量提醒
// eslint-disable-next-line no-unused-vars
interface ImportMetaEnv {
  VITE_BASE_URL: string;
}
  • ps:这里定义的 VITE_BASE_URL 可用于封装 axios 时的 baseURL 取值;


引入 vuex@next

  • npm i vuex@next -S
  • 引入四步骤
    1. 创建 store 文件夹,并创建 index.ts 文件
    2. 在根目录下创建 vuex 的类型声明文件 vuex.d.ts
    3. 模块化,store/modules/user.ts
    4. main.ts 中引入 Store
    5. 组件中使用 state
  • useStore()类型化:setup 中使用 useStore 时要类型化,三步骤
    1. 定义InjectionKey store/index.ts 中
    2. app 安装时提供InjectionKey main.ts
    3. 传递InjectionKeyuseStore 组件中使用如 CompVuex.vue
// store/index.ts
import { InjectionKey } from 'vue';
import { createStore, Store } from 'vuex';
import users, { UserState} from './modules/todolist';

export type State = {
  ac: number;
  users?: UserState;
};

// 泛型 核心目的 约束State
// 1. 创建一个injectionKey
export const key: InjectionKey<Store<State>> = Symbol('description');

export default createStore({
  state: {
    ac: 0,
  },
  mutations: {
    add(state) {
      Object.assign(state, {
        ac: state.ac + 1,
      });
    },
  },
  // 声明子模块
  modules: {
    users,
  },
});


// modules/list.ts
import { Module } from 'vuex';
import { State } from '../index';
import { Item} from '../../types';
import http from '../../api/request';

const initialState = {
  list: [] as Item[],
};

// 从已有值中推断出类型
export type UserState= typeof initialState;

// Module<S, R>泛型约束 S 子模块的类型 R根模块的类型
export default {
  namespaced: true,
  // 子模块state
  state: initialState,
  mutations: {
    initItem(state, payload: Item[]) {
      // eslint-disable-next-line no-param-reassign
      state.list = payload;
    },
    addItem(state, payload: Item) {
      state.list.push(payload);
    },
  },
  actions: {
    getList() {
      http.get('/*').then((res) => {
        console.log('res: ', res);
      });
    },
    init({ commit }) {
      // 使用相对路径,从而可以被我们的代理所接管,在vite.config.ts中配置代理
      // <Item>请求返回的类型
      http.get<Item>('/*').then((resp) => {
        commit('add', resp.data);
      });
    },
    add({commit, state }, payload: string) {
      commit('add', {
        id: state.list.length + 1,
        title: payload,
        completed: false,
      } as Item);
    },
  },
} as Module<UserState, State>;


// main.ts
import store, { key } from './store/index';
// 2. App注入key
createApp(App)use(store, key).mount('#app');

// 组件中使用
<script lang="ts" setup>
import { computed, defineProps, PropType } from 'vue';
import { useStore } from 'vuex';
import { key } from '../store';
import { TitleInfo } from '../types';
// 有了useStore之后所有的值都被认为计算属性处理

// 3.传递`InjectionKey`给`useStore` 方便于属性提醒
const store = useStore(key);
// 全局state
const cc = computed(() => store.state.c);
// 子模块state
console.log(computed(() => store.state.users?.list));
// users初始化 类似于请求接口 store/index.ts加了命名空间,请求接口时候需要带上
store.dispatch('users/init', 'kk');
// 定义属性
defineProps({
  titleInfo: {
    type: Object as PropType<TitleInfo>,
    required: true,
  },
});
</script>

// 根目录types.d.ts
export type TitleInfo = {
  value: string;
  color: string;
};


export type Item= {
  id: number;
  title: string;
  completed: boolean;
};



引入 vue-router@next

  • 安装npm i vue-router@next -S
  • 引入 src/router/index.ts 创建实例
  • App.vue 中设置路由出口,可能还有路由导航
  • main.ts 中 use 路由
// router/index.ts
// 路由实例,ts默认支持路由,则不需要额外添加类型声明文件
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';

// 对路由定义对象进行扩展,如增加新的字段hidden
export type AppRouteRecordRaw = RouteRecordRaw & {
  hidden?: boolean;
};

const router = createRouter({
  history: createWebHashHistory(),
  // 路由 类型断言
  routes: [
    {
      path: '/',
      component: () => import('../pages/Home.vue'),
      meta: {
        title: 'kkk',
        icon: 'el-icon-edit',
      },
    },
    {
      path: '/add',
      hidden: true,
      component: () => import('../pages/About.vue'),
    },
  ] as AppRouteRecordRaw[],
});

// 路由守卫
router.beforeEach((to, from, next) => {
  console.log('to, from, next: ', to, from, next);
  return next();
});
export default router;


// App.vue
 <!--路由出口-->
 <router-link to="/">todo</router-link>
 <router-link to="/add">add</router-link>
 <router-view></router-view>

// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import router from './router';

// 2. app安装时提供`InjectionKey`
createApp(App).use(router).mount('#app')



axios

  • 安装npm i axios -S
  • 新建 src/api/request.ts
  • 创建 axios 实例,统一处理、统一配置


按需引入 element-plus

  1. 安装npm install element-plus --save
  2. main.ts 中完整引入
import ElementPlus from 'element-plus';
import 'element-plus/lib/theme-chalk/index.css';
createApp(App).use(ElementPlus)
  1. vite.config.ts 配置按需引入
import styleImport from 'vite-plugin-style-import';
export default defineConfig({
  plugins: [
    vue(),
    styleImport({
      libs: [
        {
          libraryName: 'element-plus',
          esModule: true,
          ensureStyleFile: true,
          resolveStyle: (name) => {
            const nameTemp = name.slice(3);
            return `element-plus/packages/theme-chalk/src/${nameTemp}.scss`;
          },
          resolveComponent: (name) => `element-plus/lib/${name}`,
        },
      ],
    }),
  ],
});
  1. 组件页面中使用 ElementPlus
 <el-button type="primary">主要按钮</el-button>


引入 scss 及初始化样式

  1. npm install sass -D npm i normalize.css -S
  2. 新建variables.scss,element-theme.scss,helpers.scss,reset.scss






参考 && 感谢 各路大神:

editorconfig
Vue3+Vite+TS+Eslint-搭建项目,配置 ESLint
Vue3+Vite+TS+Eslint-配置 husky 和 lint-staged
Vue3+Vite+TS+Eslint-引入 Element-plus,解决字体文件 404 问题
Vue3+Vite+TS+Eslint-引入 vuex、vuex 源码类型声明推导
体验 vite + vue3 + ts 搭建项目的全过程
ElementPlus
杨村长-Vue3+Typescript 从整合到项目实战
posted @ 2021-08-11 23:16  安静的嘶吼  阅读(202)  评论(0编辑  收藏  举报