vue3.x + vite + ts 搭建前端项目

568 阅读6分钟

截止本文章编写vue已经更新到了vue3.3版本,使用的人也越来越多,再加上vue2已经写很长一段时间,所以决定尝试使用vue3vite来创建个项目提升一下,本文章主要记录自己的一个搭建过程。

本文主要采用npm的构建方式,其他的构建方式可以参考 vite官网

创建项目

image.png 先检查本地nodejs版本,如果版本低于14.18,请先升级node版本,最好到16+ 再进行项目安装。

查看nodejs版本

node -v

image.png

开始创建

npm create vite@latest

image.png

如上一个最基础版本的vite-vue3的项目就已经初始化完成。

启动项目

安装依赖并启动

npm install
npm run dev
image.png image.png

安装工具

1. 安装vue-router

vue-router官网

npm install vue-router@4

image.png

// 创建 `src/router/index.ts` 文件(并创建view文件夹随便写2个页面方便写路由)
import { createRouter, RouteRecordRaw, createWebHashHistory } from 'vue-router';

const constantRoutes: Array<RouteRecordRaw> = [
  {
    path: '/index',
    name: 'Index',
    component: () => import('../view/index/index.vue'),
  },
  {
    path: '/system',
    name: 'System',
    component: () => import('../view/system/system.vue'),
  },
];

const router = createRouter({
  history: createWebHashHistory(),
  routes: constantRoutes,
});

export default router;
// main.ts 中引入router
import { createApp } from 'vue';
import './style.css';
import App from './App.vue';
import router from './router';

const app = createApp(App);
app.use(router).mount('#app');

App.vue 页面中使用<router-view />标签, 此时可以启动项目并查看我们的路由

image.png

image.png

2. 安装Pinia(状态储存-vuex的替代品)

Pinia 官网

npm install pinia

image.png

// 创建 `src/store/index.ts` 文件
import { defineStore } from 'pinia';

export const useMyStore = defineStore({
  id: 'myStore',
  state: () => ({
    counter: 0,
  }),
  getters: {
    doubleCount: (state) => state.counter * 2,
  },
  actions: {
    increment() {
      this.counter++;
    },
  },
});

export default createPinia();
// main.ts 中引入store
import { createApp } from 'vue';
import './style.css';
import App from './App.vue';
import router from './router';
import store from './store';

const app = createApp(App);
app.use(router).use(store).mount('#app');

3. 安装Element Plus

Element Plus 官网

// 这里采用按需引入,需要安装3个包
npm install element-plus --save
npm install -D unplugin-vue-components 
npm install -D unplugin-auto-import

image.png

// vite.config.ts

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import AutoImport from 'unplugin-auto-import/vite';
import Components from 'unplugin-vue-components/vite';
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';
// https://vitejs.dev/config/

// 这里 defineConfig 采用函数式,方便以后项目配置
export default defineConfig(({ command, mode, ssrBuild }) => ({
  plugins: [
    vue(),
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [ElementPlusResolver()],
    }),
  ],
}));

4. 安装Axios

Axios官网

npm install axios

image.png

在根目录下创建utilsapi 两个文件夹

// 创建 `utils/http.ts` 文件
import axios, {
  AxiosInstance,
  InternalAxiosRequestConfig,
  AxiosResponse,
} from 'axios';

/**
 * 创建axios
 */
const http: AxiosInstance = axios.create({
  baseURL: '',
  timeout: 5000,
});

/**
 * 请求拦截器
 */
http.interceptors.request.use((config: InternalAxiosRequestConfig) => {
  console.log('这是请求拦截器');
  return config;
});

/**
 * 响应拦截器
 */
http.interceptors.response.use(
  (response: AxiosResponse) => {
    console.log('这是响应拦截器');
    return response;
  },
  (error) => {
    console.log('请求失败', error);
  }
);
// 在 `api/user.ts` 中使用
import { AxiosPromise } from 'axios';
import http from '../utils/http';

export const userInfo = (params): AxiosPromise => {
  return http({
    url: 'userInfo',
    method: 'get',
    params
  });
};

5. 安装sass

npm install --save-dev sass
npm install --save-dev sass-loader

image.png

项目规范类工具

1. 安装prettier

prettier中文网站

npm i prettier -D

image.png

// 创建 .prettierrc.cjs 规则文件,里面大致内容,更多参考官网
module.exports = {
  // endOfLine: 'auto', // 允许代码结尾是回车或者换行,\n\r
  printWidth: 120, // 换行字符串阈值
  tabWidth: 2, // 水平缩进的空格数
  useTabs: false,
  semi: false, // 句末是否加分号
  vueIndentScriptAndStyle: true,
  singleQuote: true, // 用单引号
  trailingComma: 'none', // 最后一个对象元素加逗号
  bracketSpacing: true, // 对象,数组加空格
  jsxBracketSameLine: true, // jsx > 是否另起一行
  arrowParens: 'always' // (x) => {} 是否要有小括号
}
// 创建 .prettierignore 忽略规则文件,大致内容
/dist/*
.local
.output.js
commitlint.config.js
/node_modules/**
**/*.svg
**/*.sh
/public/*

vscode 可以配合安装 Prettier - Code formatter 进行格式化操作更方便

2. 安装eslint

eslint中文网站

/**
 *  这里安装的包很多
 *  eslint: eslint 主要核心代码
 *  eslint-config-prettier: 解决eslint和prettier冲突
 *  eslint-config-prettier: 将prettier作为eslnt规范
 *  eslint-plugin-vue: eslint的vue规范
 *  eslint-config-airbnb-base: 编码规范
 *  eslint-plugin-import:    eslint-config-airbnb-base包安装前必须安装
 *  @typescript-eslint/parser: eslint的ts相关
 *  @typescript-eslint/eslint-plugin : eslint的ts相关
 *  eslint-import-resolver-alias :主要用户项目配置 @ 别名引入
 */
 
  npm install eslint -D
  npm install eslint-config-prettier -D
  npm install eslint-plugin-prettier -D
  npm install eslint-plugin-vue -D
  npm install @typescript-eslint/parser -D
  npm install @typescript-eslint/eslint-plugin -D
  npm install eslint-plugin-import -D
  npm install eslint-config-airbnb-base -D
  npm install eslint-import-resolver-alias -D

image.png

// .eslintignore eslint 忽略文件

*.sh
node_modules
*.md
*.woff
*.ttf
.vscode
.idea
dist
/public
/docs
.husky
.local
/bin
/src/mock
Dockerfile
commitlint.config.js
// eslint 配置文件
npm init @eslint/config

仅供参考 image.png

// 生成好的eslint规则文件大致如下

module.exports = {
  env: {
    browser: true,
    es2021: true
  },
  extends: ['eslint:recommended', 'plugin:vue/vue3-essential', 'plugin:@typescript-eslint/recommended'],
  overrides: [],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module'
  },
  plugins: ['vue', '@typescript-eslint'],
  rules: {
    indent: ['error', 'tab'],
    'linebreak-style': ['error', 'windows'],
    quotes: ['error', 'single'],
    semi: ['error', 'always']
  }
}

3.项目使用@来引入文件(上面的项目目前都是通过 ./ 或者 ../ 引入的文件,我们现在配置成@别名)

// vite.config.ts 中新增resolve.alias和resolve.extensions配置

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

// https://vitejs.dev/config/

// 这里 defineConfig 采用函数式,方便以后项目配置
export default defineConfig(({ command, mode, ssrBuild }) => ({
  plugins: [
    vue(),
    AutoImport({
      resolvers: [ElementPlusResolver()]
    }),
    Components({
      resolvers: [ElementPlusResolver()]
    })
  ],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src'),
      '@c': path.resolve(__dirname, 'src/components')
    },
    // 解析到文件之后自动添加如下拓展名,根据自己需求配置
    extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json']
  }
}))

image.png

引入测试,可以找到文件

image.png

4. AutoImport 自动导入api配置

因为之前我们在导入element Plus的时候已经安装了unplugin-auto-import插件,这个插件可以帮我们自动导入vue3,vue-router等一些库中的api,不用再写 import {xxx} from xxx

1. 根目录下创建 .eslintrc-auto-import.json 文件

2. 修改vite.config,第一次配置的时候将 eslintrc.enabled 设置成 true

// 修改我们之前的vite.config.ts 中的AutoImport
AutoImport({
  imports: ['vue', 'vue-router', 'pinia'],
  dts: './auto-imports.d.ts',
  resolvers: [ElementPlusResolver()],
  eslintrc: {
    enabled: false, // Default `false`
    filepath: './.eslintrc-auto-import.json', // Default `./.eslintrc-auto-import.json`
    globalsPropValue: true // Default `true`, (true | false | 'readonly' | 'readable' | 'writable' | 'writeable')
   }
 }),

3. .eslintrc.cjs 文件中的 extends 属性中添加 './.eslintrc-auto-import.json',

4. tsconfig.json 文件中的include属性中添加 "./auto-imports.d.ts"

5. 重启项目

image.png

image.png

image.png

5. 一些格式化冲突以及配置

初步解决一些报错

1. 报错:Expected indentation of 2 tabs but found 4 spaces

这种类型的错误主要是eslintprettier对于空格缩进的冲突,基于我们之前prettier的配置文件,可以将.eslintrc.cjs文件中rules.indent属性设置一下。

image.png

2. 报错:Parsing error: '>' expected.eslint

这个主要是针对 <script setup></script> 语法糖的报错,可以在.eslintrc.cjs中设置parser属性和parserOptions.parser属性

image.png

3. 报错:Expected linebreaks to be 'CRLF' but found 'LF'

这个主要和初始化 .eslintrc.cjs 初始化配置, 以及操作系统有关系, mac系统一般文件行尾序列LFwindows系统为CRLF, 这个问题可以通过在vscode设置或者.eslintrc.cjs 文件中的 rules[linebreak-style]属性,建议设置成 unix

image.png

image.png

4. .eslintrc.cjs文件第一行如果提示: 'module' is not defined.eslintno-undef

遇见这个问题在 .eslintrc.cjsenv属性中添加node: true即可

image.png

最后

到这里一个最基本的vue3 + ts + eslint + prettier的项目空壳就已经搭建好了 但是实际开发中 .eslintrc.cjs文件还需要做很多优化,这个空壳项目里面就不过多的处理了。

贴一个自己本地项目的.eslintrc.cjs.prettierrc.cjs

// .eslintrc.cjs
module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true
  },
  globals: {
    defineEmits: 'readonly',
    defineProps: 'readonly'
  },

  parser: 'vue-eslint-parser',
  extends: [
    './.eslintrc-auto-import.json',
    'plugin:vue/vue3-recommended',
    'eslint:recommended',
    'airbnb-base',
    'plugin:@typescript-eslint/recommended',
    'plugin:prettier/recommended',
    'plugin:import/recommended',
    'plugin:import/typescript'
  ],
  parserOptions: {
    ecmaVersion: 'latest',
    parser: '@typescript-eslint/parser',
    sourceType: 'module'
  },
  settings: {
    'import/resolver': {
      alias: {
        map: [['@', './src']],
        extensions: ['.ts', '.js', '.jsx', '.tsx'] // 可忽略的后缀名
      }
    }
  },
  plugins: ['vue', 'prettier', '@typescript-eslint', 'eslint-plugin-import'],
  rules: {
    'prettier/prettier': ['error'],
    'import/extensions': [
      'error',
      'ignorePackages',
      {
        js: 'never',
        jsx: 'never',
        ts: 'never',
        tsx: 'never',
        json: 'never'
      }
    ],
    'vue/no-mutating-props': 'off',
    'no-empty-function': 'off',
    '@typescript-eslint/no-empty-function': ['error'],
    '@typescript-eslint/no-var-requires': 0,
    'vue/multi-word-component-names': 'off',
    '@typescript-eslint/explicit-module-boundary-types': ['off'],
    '@typescript-eslint/no-explicit-any': ['off'],
    'no-param-reassign': [
      'error',
      {
        props: true,
        ignorePropertyModificationsFor: [
          'e', // for e.returnvalue
          'ctx', // for Koa routing
          'req', // for Express requests
          'request', // for Express requests
          'res', // for Express responses
          'response', // for Express responses
          'state', // for vuex state
          'axios'
        ]
      }
    ]
  }
}

// prettierrc.cjs

module.exports = {
  // endOfLine: 'auto', // 允许代码结尾是回车或者换行,\n\r
  printWidth: 120, // 换行字符串阈值
  tabWidth: 2, // 水平缩进的空格数
  useTabs: false,
  semi: false, // 句末是否加分号
  vueIndentScriptAndStyle: true,
  singleQuote: true, // 用单引号
  trailingComma: 'none', // 最后一个对象元素加逗号
  bracketSpacing: true, // 对象,数组加空格
  jsxBracketSameLine: true, // jsx > 是否另起一行
  arrowParens: 'always' // (x) => {} 是否要有小括号
}