Vue实战之从零搭建Vite2+Vue3全家桶(一)

2,680 阅读5分钟

前言

开启2021学习之旅,主要介绍学习vite2和vue3的实战过程。
本篇主要介绍从零开始搭建Vite2 + Vue3+Element-Plus + Vue-router4 + Vuex + Eslint。

vite介绍

 Vite (法语意为 "快速的",发音 /vit/)是一种全新的前端构建工具。
 由一个开箱即用的开发服务器 + 一套构建    指令组成。
 Vite 利用浏览器原生的 ES 模块支持和基于 esbuild 的依赖预打包来显著提升前端开发体验。

初始化项目

  # npm 6.x
  npm init @vitejs/app my-vue-app --template vue

  # npm 7+, 需要额外的双横线:
  npm init @vitejs/app my-vue-app -- --template vue

  # yarn
  yarn create @vitejs/app my-vue-app --template vue

别名设置

修改vite.config.js

  import path from 'path'
  export default defineConfig({
      ...,
      resolve: {
        alias: {
          '@': path.resolve(__dirname, 'src'),
          components: path.resolve(__dirname, 'src/components'),
          assets: path.resolve(__dirname, 'src/assets'),
          views: path.resolve(__dirname, 'src/views'),
          utils: path.resolve(__dirname, 'src/utils'),
          apis: path.resolve(__dirname, 'src/apis'),
        },
      }
  })

SCSS预处理

scss是一款css预处理语言,是sass的一个升级版本,SCSS 是 Sass 3 引入新的语法,其语法完全兼容 CSS3,并且继承了 Sass 的强大功能。

安装sass

  npm i -d sass node-sass sass-loader

引入SASS全局变量/样式

  # vite.config.js
  export default defineConfig({
      ...,
      css: {
        preprocessorOptions: {
          scss: {
            // @/ 是 src/ 的别名
            // 所以这里假设你有 `src/assets/scss/variables.scss` 这个文件
            additionalData: `@import "@/assets/scss/variables.scss";`
          },
        },
      }
  })

ElementUI

开始引入UI框架,这里使用Element适配vue3版本的element-plus

安装element

  npm i -s element-plus

按需加载组件

借助 vite-plugin-style-import实现按需加载组件,以达到减小项目体积的目

安装\textrm\color{red}{vite-plugin-style-import}

npm install vite-plugin-style-import -D

修改\textrm\color{red}{vite.config.js}

import styleImport from 'vite-plugin-style-import'
plugins: [
  vue(),
  styleImport({
    libs: [
      {
        libraryName: 'element-plus',
        esModule: true,
        ensureStyleFile: true,
        resolveStyle: (name) => {
          name = name.slice(3);
          return `element-plus/packages/theme-chalk/src/${name}.scss`;
        },
        resolveComponent: (name) => {
          return `element-plus/lib/${name}`;
        },
      },
    ],
  })
]

新建element.js文件

// 如果要使用.scss样式文件,则需要引入base.scss文件
// import 'element-plus/packages/theme-chalk/src/base.scss'
import 'element-plus/packages/theme-chalk/src/base.scss'
import {
  ElAlert,
  ElAside,
  ElAutocomplete,
  ElAvatar,
  ElBacktop,
  ElBadge,
  ElBreadcrumb,
  ElBreadcrumbItem,
  ElButton,
  ElButtonGroup,
  ElCalendar,
  ElCard,
  ElCarousel,
  ElCarouselItem,
  ElCascader,
  ElCascaderPanel,
  ElCheckbox,
  ElCheckboxButton,
  ElCheckboxGroup,
  ElCol,
  ElCollapse,
  ElCollapseItem,
  ElCollapseTransition,
  ElColorPicker,
  ElContainer,
  ElDatePicker,
  ElDialog,
  ElDivider,
  ElDrawer,
  ElDropdown,
  ElDropdownItem,
  ElDropdownMenu,
  ElFooter,
  ElForm,
  ElFormItem,
  ElHeader,
  ElIcon,
  ElImage,
  ElInput,
  ElInputNumber,
  ElLink,
  ElMain,
  ElMenu,
  ElMenuItem,
  ElMenuItemGroup,
  ElOption,
  ElOptionGroup,
  ElPageHeader,
  ElPagination,
  ElPopconfirm,
  ElPopover,
  ElPopper,
  ElProgress,
  ElRadio,
  ElRadioButton,
  ElRadioGroup,
  ElRate,
  ElRow,
  ElScrollbar,
  ElSelect,
  ElSlider,
  ElStep,
  ElSteps,
  ElSubmenu,
  ElSwitch,
  ElTabPane,
  ElTable,
  ElTableColumn,
  ElTabs,
  ElTag,
  ElTimePicker,
  ElTimeSelect,
  ElTimeline,
  ElTimelineItem,
  ElTooltip,
  ElTransfer,
  ElTree,
  ElUpload,
  ElInfiniteScroll,
  ElLoading,
  ElMessage,
  ElMessageBox,
  ElNotification,
} from 'element-plus';

const components = [
  ElAlert,
  ElAside,
  ElAutocomplete,
  ElAvatar,
  ElBacktop,
  ElBadge,
  ElBreadcrumb,
  ElBreadcrumbItem,
  ElButton,
  ElButtonGroup,
  ElCalendar,
  ElCard,
  ElCarousel,
  ElCarouselItem,
  ElCascader,
  ElCascaderPanel,
  ElCheckbox,
  ElCheckboxButton,
  ElCheckboxGroup,
  ElCol,
  ElCollapse,
  ElCollapseItem,
  ElCollapseTransition,
  ElColorPicker,
  ElContainer,
  ElDatePicker,
  ElDialog,
  ElDivider,
  ElDrawer,
  ElDropdown,
  ElDropdownItem,
  ElDropdownMenu,
  ElFooter,
  ElForm,
  ElFormItem,
  ElHeader,
  ElIcon,
  ElImage,
  ElInput,
  ElInputNumber,
  ElLink,
  ElMain,
  ElMenu,
  ElMenuItem,
  ElMenuItemGroup,
  ElOption,
  ElOptionGroup,
  ElPageHeader,
  ElPagination,
  ElPopconfirm,
  ElPopover,
  ElPopper,
  ElProgress,
  ElRadio,
  ElRadioButton,
  ElRadioGroup,
  ElRate,
  ElRow,
  ElScrollbar,
  ElSelect,
  ElSlider,
  ElStep,
  ElSteps,
  ElSubmenu,
  ElSwitch,
  ElTabPane,
  ElTable,
  ElTableColumn,
  ElTabs,
  ElTag,
  ElTimePicker,
  ElTimeSelect,
  ElTimeline,
  ElTimelineItem,
  ElTooltip,
  ElTransfer,
  ElTree,
  ElUpload,
];

const plugins = [
  ElInfiniteScroll,
  ElLoading,
  ElMessage,
  ElMessageBox,
  ElNotification,
];

const option = { size: 'small', zIndex: 3000 }
export default (app) => {
  // element全局配置
  app.config.globalProperties.$ELEMENT = option
  components.forEach((component) => {
    app.component(component.name, component);
  });

  plugins.forEach((plugin) => {
    app.use(plugin);
  });
};

修改main.js

import useElement from '@/utils/element.js';
const app = createApp(App)
useElement(app)
app.mount('#app')

注意事项

  # 如果报错 Error: @use rules must be written before any other rules.

  # 修改vite.config.js
  - additionalData: `@import "assets/scss/variables.scss";`
  + additionalData: `@use "assets/scss/variables.scss" as *;`

vue-router

Vue Router 是 Vue的路由管理器,它和 Vue.js 的核心深度集成,是Vue的核心插件之一。

安装vue-router

  npm i -s vue-router@4.0.10

创建router目录及文件

新建router目录

src目录下新建router目录文件夹

新建index.js

router目录下新建index.js

  // 引入vue-router对象
  import { createRouter, createWebHistory } from "vue-router";
  import Layout from '@/layout'
  /**
  * 定义路由数组
  */
  const routes = [
    {// 404路由
      name: '404',
      path: '404',
      component: () => import('/@/views/error/404.vue')
    },
    {// 401路由
      name: '401',
      path: '401',
      component: () => import('@/views/error/401.vue'),
      hidden: true
    },
    {
      name: 'home',
      path: "home",
      component: () => import("/@/views/home/home.vue"),
    }
  ];

  /**
  * 创建路由
  */
  const router = createRouter({
    // hash模式:createWebHashHistory,
    // history模式:createWebHistory
    history: createWebHistory("/"),
    // history:createWebHashHistory(),
    routes,
  });

  /**
  * 路由守卫
  */
  router.beforeEach((guard) => {
    beforeEach.checkAuth(guard, router);
  });

  /**
  * 路由错误回调
  */
  router.onError((handler) => {
    console.log("error:", handler);
  });

  /**
  * 输出对象
  */
  export default router

修改main.js

import { createApp } from 'vue'
import App from './App.vue'
import useElement from '@/utils/element.js';
import router from '@/router/index.js'

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

vuex

安装vuex

npm i vuex@4 -s

新建store目录及文件

新建store目录

在src目录下新建store目录

新建index.js文件

store目录下新建index.js文件

import { createStore, Store } from 'vuex';
import user from './modules/user';
import getters from './getters'

const store = createStore({
  modules: { user },
  getters
});

export default store

新建modules目录和module文件

// src/store/modules/user.js
const state = {
  name: 'hello vue3',
  age: 18
}

const mutations = {
  SET_NAME: (state, name) => {
    state.name = name
  },
  SET_AGE: (state, age) => {
    state.age = age
  }
}

const actions = {
  setName({ commit }, name) {
    commit('SET_NAME', name)
  },
  setAge({ commit }, age) {
    commit('SET_AGE', age)
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

修改main.js

import { createApp } from 'vue'
import App from './App.vue'
import useElement from '@/utils/element.js';
import router from '@/router/index.js'
import i18n from '@/i18n/index.js'
import store from '@/store/index.js' //++++

const app = createApp(App)
app.use(router)
app.use(store)                       //++++
app.use(i18n)
useElement(app)
app.mount('#app')

国际化

通过vue-i18n实现国际化

安装vue-i18n

npm i vue-i18n@next -s

增加i18n配置文件

src目录下新建i18n目录,新建cn.js、en.js多语言配置文件

  // src/i18n/cn.js
  export default {
    message: {
      hello: '你好,欢迎使用Vue3'
    }
  };




  // src/i18n/en.js
  export default {
    message: {
      hello: 'Hello Vue3'
    }
  };

增加i18n入口文件

i18n目录下新建index.js

// src/i18n/index.js
import { createI18n } from 'vue-i18n';
import cn from './cn.js';
import en from './en.js';
const messages = {
  en: {
    ...en
  },
  'zh-cn': {
    ...cn
  }
}
const i18n = createI18n({
  locale: localStorage.getItem('lang') || 'zh-cn',
  messages
});
export default i18n;

修改main.js

import { createApp } from 'vue'
import App from './App.vue'
import useElement from '@/utils/element.js';
import router from '@/router/index.js'
import i18n from '@/i18n/index.js'

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

ESLint

编码过程中,代码规范很重要,采用ESLint可以避免很多编码错误,提高代码可读性,这里采用Airbnb JavaScript 这套代码规范。

安装eslint

npm i -d eslint eslint-config-airbnb-base eslint-plugin-import eslint-plugin-vue

增加.eslintrc.js配置文件

# src目录下新建.eslintrc.js文件,参考如下配置:
module.exports = {
  extends: ['plugin:vue/vue3-essential', 'airbnb-base'],
  parserOptions: {
    sourceType: 'module',
    ecmaVersion: 2020,
  },
  plugins: ['vue'],
  rules: {
    ...
  },
};

配置.eslintignore文件

# 配置ESLint忽略文件,根目录创建.eslintignore文件,内如根据需求添加配置,例如:
/node_modules
/dist

总结

折腾了一两天,基本上按照官网指南进行操作,按步骤即可完成搭建。

往期传送门

基于Vue的架构设计

nodejs版本管理

vscode 开发工具优化