记一次使用Vite搭建Vue3项目基础框架的过程

424 阅读5分钟

基础框架项目从零搭建的过程

因公司需要搭建一个基础框架提供后续系统的开发,故使用了Vite和Vue3相关技术框架,记录此基础框架搭建过程。

项目初始化

  • 创建
yarn create vite

57f180f1db7601e1935267fb81dfedbc.png

  • 安装依赖
cd my-vite-demo
yarn

527d530fbfd32e44f8bd75467c447ca3.png

  • 运行
yarn dev

83134bd39f9a4fb72b35b7750d270be6.png

构建生产环境和预览环境

  • 修改配置文件vite.config.ts

    根据模式对环境做相关配置

   export default defineConfig(({ mode }) => {
     return {
       plugins: [vue()],
     };
   });
  • 新增环境文件.env

    一份用于指定模式的文件(例如 .env.production)会比通用形式的优先级更高(例如 .env)

    已经存在的环境变量有最高的优先级,不会被 .env 类文件覆盖

    .env 类文件会在 Vite 启动一开始时被加载,而改动会在重启服务器后生效

    01e525591f5fb4f8061a4c078422b43d.png

  • 添加Typescript提示

    src目录下的 env.d.ts 文件

   /// <reference types="vite/client" />

   interface ImportMetaEnv {
     readonly VITE_APP_TITLE: string
     // 更多环境变量...
   }

   interface ImportMeta {
     readonly env: ImportMetaEnv
   }
  • 环境变量配置

    配置端口、mock服务开关、基础路径等等

   // .env

   # port
   VITE_PORT = 3000

   VITE_USE_MOCK = true
   VITE_MOCK_URL = http://127.0.0.1:8888/mock/8888
   #---------------------------------------------------------
   //.env.development
   NODE_ENV=development

   VITE_PUBLIC_PATH = /
   VITE_BASE_URL = http://192.168.1.123:2323/demo/api
   #---------------------------------------------------------
   // .env.production
   NODE_ENV=production
   VITE_OUTPUT_DIR = dist

   VITE_DROP_CONSOLE = true //删除console
   VITE_DROP_DEBBUGER = true //删除debug

   VITE_PUBLIC_PATH = /
   VITE_BASE_URL = /demo/api
   #---------------------------------------------------------
   // .env.preview
   NODE_ENV=preview
   VITE_OUTPUT_DIR = preview

   VITE_DROP_CONSOLE = false
   VITE_DROP_DEBBUGER = false


   VITE_PUBLIC_PATH = /
   VITE_BASE_URL = http://192.168.1.123:2323/demo/api

  • vite配置

    安装 yarn add @types/node -D

import { defineConfig, loadEnv } from 'vite';
import vue from '@vitejs/plugin-vue';
import { resolve } from 'path';

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
  const root = process.cwd();//获取环境根路径
  // 根据当前工作目录中的 `mode` 加载 .env 文件
  // 设置第三个参数为 '' 来加载所有环境变量,而不管是否有 `VITE_` 前缀。
  const env = loadEnv(mode, root);

  const dropConsole: boolean = env.VITE_DROP_CONSOLE !== 'false'; //删除console
  const dropDebugger: boolean = env.VITE_DROP_DEBBUGER !== 'false';//删除debug

  return {
    base: env.VITE_PUBLIC_PATH, //基础路径
    resolve: {
      alias: [
        {
          find: '@/', //配置别名
          replacement: `${resolve(root, './src')}/`
        }
      ]
    },
    server: { //dev
      host: true, //配置host
      port: Number(env.VITE_PORT), //配置端口
      open: true //运行时打开
    },
    build: { //生产环境
      target: 'es2015',
      outDir: env.VITE_OUTPUT_DIR, //输出路径
      minify: 'terser',
      terserOptions: {
        compress: {
          keep_infinity: true,
          drop_console: dropConsole, //删除console
          drop_debugger: dropDebugger //删除debugger
        }
      },
      chunkSizeWarningLimit: 2000
    },
    preview: { //本地预览环境
      host: true,
      open: true
    },
    plugins: [
      vue(),
    ]
  };
});

  • 配置脚本

    制定相应环境模式 --mode

// package.json

"scripts": {
    "dev": "vite",
    "build": "vue-tsc --noEmit && vite build",
    "preview": "vue-tsc --noEmit && vite build --mode preview && vite preview --mode preview",
  },
  • 配置ts
{
  "compilerOptions": {
    "target": "esnext",
    "useDefineForClassFields": true,
    "module": "esnext",
    "moduleResolution": "node",
    "strict": true,
    "jsx": "preserve",
    "sourceMap": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "lib": ["esnext", "dom"],
    "skipLibCheck": true,
    "baseUrl": "./",
    "paths": {
      "@/*": ["src/*"] // 别名路径
    },
    "types": ["vite/client"]
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.d.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
  ],
  "exclude": ["node_modules", "dist", "preview"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

添加自动导入Vue Api

  • 安装
npm i unplugin-auto-import unplugin-vue-components -D
# or
yarn add unplugin-auto-import unplugin-vue-components -D
  • 配置
// vite.config.ts
import AutoImport from 'unplugin-auto-import/vite';
import Components from 'unplugin-vue-components/vite';

export default defineConfig({
  plugins: [
      vue(),
      AutoImport({
        imports: ['vue']
        // dts: 'src/auto-imports.d.ts'
      }),
      Components({
        
      }),
  ],
})

// .eslintrc.js

rules: {
  'no-undef': 'off'
}

element-ui plus 自动导入参考官方文档

来源:unplugin-vue-components

接入现代CSS工程化

集成sass

  • 安装css预处理器
yarn add sass -D
  • 新建css文件
// src/assets/style/main.scss

$test-color: blue;

  • 配置
// vite.config.ts
export default defineConfig(({ mode }) => {
  return {
    css: {
      preprocessorOptions: {
        scss: {
          additionalData: '@import "@/assets/style/main.scss";',
        },
      },
    },
    plugins: [vue()],
  };
});
  • 使用
color: $test-color

集成 WindiCSS

  • 安装
yarn add windicss vite-plugin-windicss -D
  • 配置
// vite.config.ts
import windi from "vite-plugin-windicss";

export default defineConfig(({ mode }) => {
  return {
    plugins: [vue(), windi()],
  };
});

  • 引入css

    配置添加相关配置文件,查阅windicss官方文档

// main.ts
import 'virtual:windi.css';
import 'virtual:windi-devtools'; //开发时浏览器工具
  • 使用

class="bg-red-200 p-2 border-10 border-yellow-500 text-blue-600 hover:bg-purple-400"

约束代码风格

Eslint

  • 安装
yarn add eslint -D
  • 初始化
yarn eslint --init

1e878693554546a57745d2d3b3bc2fa9.png

选中相应的配置进行安装

eslint-plugin-vue

规范等级:

base 基础
essential 预设
strongly-recommended 推荐
recommended 最严谨

vue3:

Vue 3.x 需要加上 vue3 前綴,'plugin:vue/vue3-essential'

Airbnb:

Airbnb JavaScript编码规范指南(ES6)中文版

  • 配置

    安装完后自动生成 .eslintrc.js

module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  extends: [
    'plugin:vue/essential',
    'airbnb-base',
  ],
  parserOptions: {
    ecmaVersion: 'latest',
    parser: '@typescript-eslint/parser',
    sourceType: 'module',
  },
  plugins: [
    'vue',
    '@typescript-eslint',
  ],
  rules: {
  },
};

安装yarn add eslint-define-config -D

修改:

// eslint-define-config可以帮助我们做语法提示
import defineConfig from "eslint-define-config";

module.exports = defineConfig({
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  extends: ["plugin:vue/essential", "airbnb-base"],
  parserOptions: {
    ecmaVersion: "latest",
    parser: "@typescript-eslint/parser",
    sourceType: "module",
  },
  plugins: ["vue", "@typescript-eslint"],
  rules: {},
});

新增 ESLint 规则,避免 Vite2 环境下错误提示和额外的一些配置:

rules: {
    // 单引号
    quotes: ['error', 'single'],
    // 行末分号
    semi: ['error', 'always'],

    // 配置规则避免 Vite2 环境下错误
    'import/no-unresolved': 'off',
    'import/no-extraneous-dependencies': 'off',
    'import/extensions': 'off',
    'global-require': 'off',
    // 'vue/script-setup-uses-vars': 'off' // 如果使用 script-setup 可开启
    // 关掉其他一些规则
    'no-plusplus': 'off',
    'no-undef': 'off',
    'vue/multi-word-component-names': 'off'
}

创建 .eslintignore 来配置eslint需要忽略哪些文件或者文件夹

node_modules
dist
preview

Prettier

  • 安装
yarn add prettier -D
  • 配置

项目根目录创建 .prettierrc.js

module.exports = {
  printWidth: 80, //一行的字符数,如果超过会进行换行,默认为80
  tabWidth: 2, // 一个 tab 代表几个空格数,默认为 2 个
  useTabs: false, //是否使用 tab 进行缩进,默认为false,表示用空格进行缩减
  singleQuote: true, // 字符串是否使用单引号,默认为 false,使用双引号
  semi: true, // 行尾是否使用分号,默认为true
  trailingComma: 'none', // 是否使用尾逗号
  bracketSpacing: true // 对象大括号直接是否有空格,默认为 true,效果:{ a: 1 }
};

配置项

创建 .prettierignore来配置prettire忽略文件或者文件夹

node_modules
dist
preview

集成Prettier到ESLint工具中

  • 安装
yarn add eslint-config-prettier eslint-plugin-prettier -D

eslint-config-prettier用来覆盖 ESLint 本身的规则配置,而eslint-plugin-prettier则是用于让 Prettier 来接管eslint --fix即修复代码的能力

  • 配置
  // .eslintrc.js
  
  parser: 'vue-eslint-parser' /* 解析.vue文件,需要制定解析vue文件解析器,否则报错*/,
  extends: [
    // 继承ts规则,extends 字段即可自动开启插件中的推荐规则
    'plugin:@typescript-eslint/recommended', 
    'prettier', // 接入 prettier 的规则
    'plugin:prettier/recommended', // eslint-config-prettier 的缩写
  ],
  rules: {
    // 开启 prettier 自动修复的功能
    'prettier/prettier': 'error',
  }
  • 解决vue3 defineProps' is not defined问题
// .eslintrc.js

  globals: {
    defineProps: 'readonly',
    defineEmits: 'readonly',
    defineExpose: 'readonly',
    withDefaults: 'readonly'
  },
  • 配置相关脚本
//package.json
"scripts": {
    "lint:script": "eslint --ext .js,.jsx,.ts,.tsx,.vue --fix ./",
  },
  • 安装插件

在VSCode中安装ESLintPrettier这两个插件,并且在设置区中开启Format On Save,保存自动格式化。

Stylelint

  • 安装
yarn add stylelint stylelint-prettier stylelint-config-prettier stylelint-config-recess-order stylelint-config-standard stylelint-config-standard-scss -D
  • 配置
// .stylelintrc.js
module.exports = {
  // 注册 stylelint 的 prettier 插件
  plugins: ['stylelint-scss', 'stylelint-prettier'],
  // 继承一系列规则集合
  extends: [
    // standard 规则集合
    'stylelint-config-standard',
    // standard 规则集合的 scss 版本
    'stylelint-config-standard-scss',
    // 样式属性顺序规则
    'stylelint-config-recess-order',
    // 接入 Prettier 规则
    'stylelint-config-prettier',
    'stylelint-prettier/recommended'
  ],
  // 配置 rules
  rules: {
    // 开启 Prettier 自动格式化功能
    'prettier/prettier': true,
    'at-rule-no-unknown': null,
    'scss/at-rule-no-unknown': true
  }
};

  • 配置脚本
 // package.json
  "scripts": {
    "lint:style": "stylelint --fix \"src/**/*.{css,scss}\""
  },

其他集成

路由

  • 安装
yarn add vue-router@4
  • 新建路由文件src/router/index.ts
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';

const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    name: 'Home',
    component: () => import('@/views/Home.vue'),
    meta: { requiresAuth: true }
  },
];

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

export default router;

  • 添加ts类型支持自定义meta提示
import 'vue-router';

declare module 'vue-router' {
  interface RouteMeta {
    // 是可选的
    isAdmin?: boolean;
    // 每个路由都必须声明
    requiresAuth: boolean;
  }
}

官网:Vue Router

Pinia 状态管理

  • 安装
yarn add pinia
# 或者使用 npm
npm install pinia
  • 配置插件
//main.ts
import { createPinia } from 'pinia'

app.use(createPinia())
  • 分模块建立独立文件
// user.ts
import { defineStore } from 'pinia';

const useUserStore = defineStore('user', {
  state: () => {
    return { count: 0 };
  },
  // 也可以定义为
  // state: () => ({ count: 0 })
  actions: {
    increment() {
      this.count++;
    }
  }
});

export default { useUserStore };

使用:Pinia 中文文档

Animate.css

  • 安装
yarn add animate.css
  • 引入
// main.ts
import 'animate.css';
  • 使用
 <transition
      name="animate"
      enter-active-class="animate__zoomIn"
      leave-active-class="animate__zoomOut"
      class="animate__animated"
      >
  <div></div>
</transition>

时间日期格式话工具moment.js 和 Axios + VueRequest

参考我的其他文章:

Vite+Vue3中使用moment.js中文国际化无效

Vue3中集成VueRequest的使用

后记

搭建的这一个过程学到了非常多的东西,在此拥抱Vue3的大环境下,我感觉Vue3的写法已经接慢慢的向着react的方向靠近了,反正写起来很“爽”,更多的仍需要我们一步一步地去学习和体验,加油掘友们!