vite5+vue3从零开始搭建项目(一)

9,696 阅读8分钟

vite5+vue3从零开始搭建项目(一)

项目环境node v20.11.1和其自带的npm v10.2.4,node版本推荐最低不低于20.9.0。

本项目技术栈vite5vue3.4piniavue-router4axioselementPlusecharts,基于多方考虑,不上TypeScript,其实也是懒。

以下是系列文章和GitHub仓库地址,点击即可跳转链接。

vite5+vue3从零开始搭建项目(一)

vite5+vue3从零开始搭建项目(二)

vite5+vue3从零开始搭建项目(三)

github代码仓库,搭了架子,后续会填充一些内容

vscode

个人看法:vscode是最好的web编辑器。notepad和sublime有点过时了,功能也略差,webstorm开发web完全是邪教,至于说用txt记事本的,请无视。

拓展插件

  • ESLint:代码格式化
  • Prettier:代码风格检查
  • Git Lens:git提交管理
  • Git History:git日志管理
  • Vue - Official:Vue3语法支持
  • Element Plus Snippets:ElementPlus语法支持
  • JavaScript (ES6) code snippets: JavaScript语法支持
  • HTML CSS Support: html和css语法支持
  • Auto Rename Tag:自动重命名标签
  • Auto Import:自动导入
  • Auto Complete Tag:自动补全标签
  • Auto Close Tag:自动闭合标签
  • Chinese (Simplified) (简体中文) Language Pack for Visual Studio Code: 中文支持

配置项

这里只列出关键性的eslint配置项,其他请根据自己选用的插件自己加。

// setting.json
{
    ...
    "eslint.enable": true, // 打开eslint开关--必要条件
    "editor.codeActionsOnSave": { // 编辑器.代码保存时进行的操作--非必要
        "source.fixAll.eslint": "always" // 通过eslint进行代码修复:总是如此
    },
    "eslint.validate": [ // eslint 需要校验的文件(js,jsx,ts,tsx,vue)--必要条件
        "javascript",
        "typescript",
        "javascriptreact",
        "typescriptreact",
        "vue"
    ]
    ...
}

创建项目

指令安装

vite创建项目跟着官网走,其实没什么好说的。

npm init vite@latest

√ Project name: ... vite-vue3
√ Select a framework: » Vue
√ Select a variant: » JavaScript

目录结构

|-- vue-vite3
    |-- public
    |   |-- vite.svg
    |-- src
        |-- App.vue
        |-- main.js
        |-- style.css
        |-- assets
        |   |-- vue.svg
        |-- components
            |-- HelloWorld.vue
    |-- .gitignore
    |-- index.html
    |-- package.json
    |-- README.md
    |-- vite.config.js

结构解析

public文件夹里面要放的是静态资源,一般来说打包后的路径不会变。查看index.html能看到此处的vite.svg是作为icon图标直接用相对路径 /vite.svg 来使用的。因为默认打包后的public文件里的内容会直接倒出来与index.html平级。

<!doctype html>
// html5的文档声明类型,对比上一个版本的一大串非常简洁
<html lang="en">
// html标签,lang是language代表语言,修改为en为zh,可将默认的英文改成中文,这样就不用每次都出现翻译弹窗了
  <head>
  // 头部信息
    <meta charset="UTF-8" />
    // 文本使用uft-8的编码,出现乱码,可以考虑文本内容是不是使用的gbk之类的其他编码
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    // icon 浏览器左上角页签上的小图标。这里同级没有vite.svg文件,但是依然能显示,是由于vite下public的独特解析模式。
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    // 屏幕像素等于设备提供的像素值。缩放比例为1:1
    <title>Vite + Vue</title>
    // 文章标题,固定的,但是后续会做成动态的,每个页面不同显示不同的标题
  </head>
  <body>
    <div id="app"></div> // 内容渲染区域
    <script type="module" src="/src/main.js"></script> // 入口下一级,主函数
  </body>
</html>

index.hmtl 是项目的第一入口。底部代码<script type="module" src="/src/main.ts"></script>会将入口指引到src下的主函数main.js。里面内容也十分简单,这里用注释一个一个解释。

// src/main.js
import { createApp } from 'vue' // 引用vue的createApp方法
import './style.css' // 引用样式,自带样式不需要关注
import App from './App.vue' // 引用App文件,入口的下一个层级

// 通过vue自带的createApp创建一个应用,并挂载到index.html里id为app的dom节点上。
createApp(App).mount('#app')

然后App里面的内容就渲染到页面上来了。src里剩下一个存放资源的assets的文件夹,一个存放组件的components文件夹。

.gitignore 里面列出了需要忽略而不是每次都上传到代码仓库的文件或文件列表

package.json 可简单理解为npm的解析配置文件。npm相关的指令和插件都在这里。

{
  "name": "vite-vue3", // 项目名
  "private": true, // 是否私有,私有库中这个属性没什么意义,主要是公有库如github/gitee上,不设置这个会被搜索。
  "version": "0.0.0", // 版本号,做版本管理
  "type": "module", // 引用类型,vite是只支持esm的模块化引用,而不是webpack的require。
  "scripts": { // npm run指令集,通过不同的参数,启动不同的模块或添加不同的配置
    "dev": "vite", // 自带指令 本地运行,mode = development
    "build": "vite build", // 自带命令  生产运行  mode = production
    "preview": "vite preview" // 自带命令 本地运行生产  mode = production 这个命令是生成dist,然后调用本地web服务,加入代理,模拟生产环境。
  },
  "dependencies": { // 在开发环境和生产环境下运行的插件  npm i xx -S
    "vue": "^3.4.29"
  },
  "devDependencies": { // 只在开发环境下运行的插件  npm i xx -D 
    "@vitejs/plugin-vue": "^5.0.5",
    "vite": "^5.3.1"
  }
}

README.md 最好介绍一下项目和代码。

vite.config.js 走vite方向的核心配置项,后续展开。

vite.config.js相关插件安装

JSX

vue3也支持JSX/TSX,这里通过安装@vitejs/plugin-vue-jsx来获得支持。

npm i @vitejs/plugin-vue-jsx -D

vite.config.js增加配置

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue(), vueJsx()],
})

VueSetupExtend

因为使用了setup语法,所以再按照vue2的optionApi写法去标注组件名会非常麻烦。这里引用VueSetupExtend插件。

<script setup name="FtDialog">
    ...
</script>

// 等价于
<script>
export default {
    name: 'FtDialog'
}
</script>
<script setup>
    ...
</script>

对比两种写法,如果不使用插件,需要写两块script才行。所以安装vite-plugin-vue-setup-extend插件。

npm i vite-plugin-vue-setup-extend -D

vite配置修改如下

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import VueSetupExtend from 'vite-plugin-vue-setup-extend'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue(), vueJsx(), VueSetupExtend()],
})

别名

别名是为了方便引用路径时候更加方便,但是如果使用了vscode的Auto-Import插件,会出现无法自动识别别名后路径的问题。为此需要在根目录新建一个jsconfig.json文件,并写入配置如下:

{
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
      "@/*": ["src/*"]
    }
  }
}

vite配置修改如下

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import VueSetupExtend from 'vite-plugin-vue-setup-extend'

import { resolve } from 'path'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue(), vueJsx(), VueSetupExtend()],
  resolve: {
    alias: [
      {
        find: '@',
        replacement: resolve(__dirname, 'src')
      }
    ]
  },
})

代码规范

这里给个链接eslint9.0之后如何安装旧版本eslint+prettier规范

elementPlus

首先接入UI库,这里是介绍的是按需自动导入,这里可以根据官网的按需自动导入

npm i element-plus -S

npm i unplugin-vue-components unplugin-auto-import -D

同时可以考虑加上自定义主题,这里不仅仅可改变主题色,也可以改变组件其他样式,例如通过border-radius改变全局属性和通过input改变组件属性。

综上,再加上代理,修改vite.config.js配置如下:

import { defineConfig } from 'vite'

import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import VueSetupExtend from 'vite-plugin-vue-setup-extend'

import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

// 引入path: 别名
import { resolve } from 'path'

export default defineConfig({
  plugins: [ // 插件引用(标准vite插件放这里引用)
    vue(), // vue插件
    vueJsx(), // jsx拓展插件
    VueSetupExtend(), // setup拓展插件
    AutoImport({ // 自动引入,不需要手动去写import
      // 这里可以不需要写import调用大部分vue/vue-router/pinia方法(记住是大部分)
      imports: ['vue', 'vue-router', 'pinia'],
      // element需要通过resolvers引用
      resolvers: [ElementPlusResolver()],
      // 会自动生成eslint规则,防止eslint报错,后续selint配置的时候会讲到
      eslintrc: {
        enabled: true
      }
    }),
    Components({ // 按需引入,避免没使用的组件也打包
      resolvers: [ElementPlusResolver({ importStyle: 'sass' })]
    })
  ],
  resolve: {
    // 别名配置
    alias: [
      {
        find: '@',
        replacement: resolve(__dirname, 'src')
      }
    ]
  },
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: '@use "@/style/globalvar.scss" as *;'
      }
    }
  },
  server: {
    host: '0.0.0.0', // 服务监听地址,设置该值表示监听所有
    cors: true, // 允许跨源
    port: 9527, // 本地服务端口号
    proxy: { // 代理
      '^/api': { // api地址匹配的字符串,可以使用正则,此处表示以/api为开头的接口地址
        target: 'http://xxx.com/', // 指向,表示上述需要匹配的地址都指向这个域名,注意要用/结尾
        rewrite: (path) => path.replace(/^\/api/, ''), // 如果匹配字符不需要了,可以使用重写去掉
        changeOrigin: true // 是否修改请求头的origin,让服务器认为这个请求来自本域名
      }
    }
  }
})

上面配置项中,当使用npm run dev根目录会自动生成一个.eslintrc-auto-import.json文件。里面包含eslint自动引入的代码,这个文件的路径需要添加到eslint配置文件中去。

// .eslintrc.cjs
module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true
  },
  // 新增./.eslintrc-auto-import.json
  extends: ['standard', 'plugin:vue/vue3-essential', 'prettier', './.eslintrc-auto-import.json'],
  overrides: [
    {
      env: {
        node: true
      },
      files: ['.eslintrc.{js,cjs}'],
      parserOptions: {
        sourceType: 'script'
      }
    }
  ],
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module'
  },
  plugins: ['vue', 'prettier'],
  rules: {
    'vue/multi-word-component-names': 'off',
    'vue/no-useless-template-attributes': 'off',
    'prettier/prettier': 'error'
  }
}
// .eslintrc-auto-import.json
{
  "globals": {
    "Component": true,
    "ComponentPublicInstance": true,
    "ComputedRef": true,
    "EffectScope": true,
    "ExtractDefaultPropTypes": true,
    "ExtractPropTypes": true,
    "ExtractPublicPropTypes": true,
    "InjectionKey": true,
    "PropType": true,
    "Ref": true,
    "VNode": true,
    "WritableComputedRef": true,
    "acceptHMRUpdate": true,
    "computed": true,
    "createApp": true,
    "createPinia": true,
    "customRef": true,
    "defineAsyncComponent": true,
    "defineComponent": true,
    "defineStore": true,
    "effectScope": true,
    "getActivePinia": true,
    "getCurrentInstance": true,
    "getCurrentScope": true,
    "h": true,
    "inject": true,
    "isProxy": true,
    "isReactive": true,
    "isReadonly": true,
    "isRef": true,
    "mapActions": true,
    "mapGetters": true,
    "mapState": true,
    "mapStores": true,
    "mapWritableState": true,
    "markRaw": true,
    "nextTick": true,
    "onActivated": true,
    "onBeforeMount": true,
    "onBeforeRouteLeave": true,
    "onBeforeRouteUpdate": true,
    "onBeforeUnmount": true,
    "onBeforeUpdate": true,
    "onDeactivated": true,
    "onErrorCaptured": true,
    "onMounted": true,
    "onRenderTracked": true,
    "onRenderTriggered": true,
    "onScopeDispose": true,
    "onServerPrefetch": true,
    "onUnmounted": true,
    "onUpdated": true,
    "provide": true,
    "reactive": true,
    "readonly": true,
    "ref": true,
    "resolveComponent": true,
    "setActivePinia": true,
    "setMapStoreSuffix": true,
    "shallowReactive": true,
    "shallowReadonly": true,
    "shallowRef": true,
    "storeToRefs": true,
    "toRaw": true,
    "toRef": true,
    "toRefs": true,
    "toValue": true,
    "triggerRef": true,
    "unref": true,
    "useAttrs": true,
    "useCssModule": true,
    "useCssVars": true,
    "useLink": true,
    "useRoute": true,
    "useRouter": true,
    "useSlots": true,
    "watch": true,
    "watchEffect": true,
    "watchPostEffect": true,
    "watchSyncEffect": true
  }
}

这样就不用每次都去import了。

image.png

生成之后一直有人问,自动引用elementPlus但是ElMessage还是会报错怎么办。

  1. .eslintrc-auto-import.json手动添加
// .eslintrc-auto-import.json
{
  "globals": {
     // ...
    "ElMessage": true,
    "ElMessageBox": true
  }
}
  1. 先在代码区块内import,等到终端窗口出现如下提示,查看.eslintrc-auto-import.json会自动添加ElMessageBoxElMessage的配置项。这时再删掉import语句即可。

image.png image.png image.png

至此与vite.config.js相关的配置项已经完成。