vite+vue3初体验

508 阅读2分钟

简介

使用最新的vue3,vite2,typescript等主流技术搭建的一个供学习参考的模版工程。

包含

  • 技术栈:使用 vue3,vite,typescript等前沿技术开发
  • ajax:二次封装axios,统一管理接口
  • 主题:可自行修改element-plus主题样式
  • 国际化:完善的国际化方案
  • 路由:动态路由生成方案
  • 组件:二次封装了常用的组件
  • 工具:常用的指令,过滤器,storage存储,工具函数

目录结构

|-- public                          # 静态资源
|   |-- config.js                   # 配置文件
|   |-- favicon.ico                 # favicon图标
|-- src                             # 源代码
|   |-- api                         # api请求
|   |   |-- modules                 # 模块
|   |   |-- types                   # 接口定义
|   |   |-- abstract.ts             # 基类
|   |   |-- config.ts               # 字典表
|   |   |-- index.ts                # 入口文件
|   |   |-- intercept.ts            # 拦截器
|   |-- assets                      # 主题 变量等资源
|   |   |-- scss                    # scss变量
|   |   |-- theme                   # elemet主题
|   |-- components                  # 全局公共组件
|   |-- config                      # 全局公共配置
|   |-- layout                      # 全局layout
|   |-- locale                      # 国际化
|   |-- plugin                      # 三方插件
|   |-- router                      # 全局路由
|   |-- store                       # 全局vuex
|   |-- utils                       # 全局公用方法
|   |   |-- directives              # 指令
|   |   |-- storage                 # 持久化
|   |   |-- filters.ts              # 过滤器
|   |   |-- pager.ts                # 发布订阅
|   |   |-- tools.ts                # 工具函数
|   |-- views                       # 所有页面
|   |-- App.vue                     # 入口页面
|   |-- main.ts                     # 入口文件
|   |-- shims-vue.d.ts              # ts声明文件
|-- static                          # 静态资源
|   |-- img                         # img
|   |-- svg                         # svg
|-- .editorconfig                   # editorconfig
|-- .env.dev                        # 环境变量 开发
|-- .env.pro                        # 环境变量 生产
|-- .env.proxy                      # 环境变量 代理
|-- .eslintignore                   # eslintignore
|-- .eslintrc.js                    # eslint 配置项
|-- .gitignore                      # gitignore
|-- babel.config.js                 # babel 配置项
|-- index.html                      # html模板
|-- package.json                    # package.json
|-- README.md                       # README
|-- tsconfig.json                   # tsconfig
|-- vite.config.ts                  # vite 配置文件

API管理

可参考上一章,ts对axios的简单封装

国际化

推荐使用vscode插件i18n Ally来协助开发,具有以下功能

  • 内联翻译显示
  • 自动补全
  • 一键机器翻译
  • 统一管理所有翻译文案
  • 从代码中提取文案
  • 转跳到翻译文件
  • 支持JSON和YAML
  • 支持多目录工作区
  • 支持 vue-i18n,vuex-i18n,vue-i18next和nuxt-i18n
  • 插件自身多语言支持(English,简体中文,繁体中文)
// settings.json配置
...
"i18n-ally.sourceLanguage": "zh-CN",
"i18n-ally.displayLanguage": "zh-CN",
"i18n-ally.enabledParsers": ["json"],
"i18n-ally.extract.targetPickingStrategy": "file-previous",
...

全局注册

  • src/plugin/index.ts
import { Directive } from 'vue';
import filters, { FilterKey } from '@/utils/filters';
import * as directives from '@/utils/directives/index';
import storage from '@/utils/storage';
import customMessage from '@/components/custom/custom-message';
// 三方插件
import element from './element';
import i18n from './i18n';

// 探测是否支持webp
const canvas = document.createElement('canvas');
if (canvas.getContext && canvas.getContext('2d')) {
    try {
        const isWebp = canvas.toDataURL('image/webp').includes('data:image/webp').toString();
        storage('localstorage').set('isWebp', isWebp);
    } catch (e) {
        console.error(e);
    }
}

const install = (app: any): void => {
    // 挂载过滤器
    app.config.globalProperties.$filters = {};
    for(const key in filters) {
        app.config.globalProperties.$filters[key] = filters[key as keyof typeof FilterKey];
    }

    // 挂载指令
    Object.keys(directives).forEach(key => {
        app.directive(key, (directives as { [key: string]: Directive })[key]);
    });

    // 注册element
    element.components.forEach((component) => {
        if (component.name) app.component(component.name as string, component);
    });
    Object.values(element.plugins).forEach(plugin => {
        app.use(plugin);
    });
    app.provide('$message', customMessage);

    // 注册i18n
    app.use(i18n);
};
  • main.ts
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import * as CustomPlugin from './plugin';
import * as CustomComponents from './components/custom';

const app = createApp(App);

// 注册全局组件
app.use(CustomComponents);
// 注册全局 插件/过滤器/指令
app.use(CustomPlugin);

app.use(router).use(store).mount('#container');

项目配置项

环境变量,在import.meta.env对象上暴露环境变量

  • .env.dev
# .env.dev
NODE_ENV=development

VITE_Version = 'v1.0.0'
VITE_BaseURL = '//dev.backendapi.aid.connext.net.cn/'
  • abstract.ts
console.log(import.meta.env.VITE_BaseURL) // dev.backendapi.aid.connext.net.cn/

vite.config.ts

import { defineConfig, loadEnv } from 'vite';
import vue from '@vitejs/plugin-vue';
import viteCompression from 'vite-plugin-compression';
import styleImport from 'vite-plugin-style-import';
import vueI18n from '@intlify/vite-plugin-vue-i18n';
const path = require('path');
const port = 7000;
const timeStamp = Date.now();
  • vite插件使用
export default ({ mode }: { mode: string }): unknown => {
    process.env = {...process.env, ...loadEnv(mode, process.cwd())};
    return defineConfig({
        plugins: [
            vue(),
            viteCompression({
                verbose: true,
                disable: false,
                threshold: 1024 * 10,
                algorithm: 'gzip',
                ext: '.gz'
            }),
            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}`;
                        }
                    }
                ]
            }),
            vueI18n({
                compositionOnly: false,
                include: path.resolve(__dirname, './src/locale/**')
            })
        ]
    });
};
  • 打包chunk命名和代码分割
export default ({ mode }: { mode: string }): unknown => {
  process.env = {...process.env, ...loadEnv(mode, process.cwd())};
  return defineConfig({
    build: {
      assetsDir: 'static/assets',
      rollupOptions: {
        output: {
          entryFileNames: `static/js/[name].${process.env.VITE_Version}.t${timeStamp}.js`,
          chunkFileNames: `static/js/[name].${process.env.VITE_Version}.t${timeStamp}.js`,
          assetFileNames: `static/js/[name].${process.env.VITE_Version}.t${timeStamp}.[ext]`,
        },
        manualChunks(id) {
          const chunkMap = new Map();
          chunkMap.set(/[\\/]src[\\/]layout[\\/]/.test(id), 'basicLayout');
          chunkMap.set(/[\\/]src[\\/]components[\\/]/.test(id), 'basicComponent');
          chunkMap.set(/[\\/]node_modules[\\/]echarts[\\/]/.test(id), 'echarts');
          chunkMap.set(/[\\/]node_modules[\\/]lodash[\\/]/.test(id), 'lodash');
          chunkMap.set(/[\\/]node_modules[\\/]moment[\\/]/.test(id), 'moment');
          chunkMap.set(/[\\/]node_modules[\\/]qiankun[\\/]/.test(id), 'qiankun');
          chunkMap.set(/[\\/]node_modules[\\/]xlsx[\\/]xlsx.js/.test(id), 'xlsxIndex');
          chunkMap.set(/[\\/]node_modules[\\/]xlsx[\\/](?!(xlsx.js))/.test(id), 'xlsx');
          chunkMap.set(/[\\/]node_modules[\\/]element-plus[\\/]/.test(id), 'element');
          return chunkMap.get(true) || 'vendors';
        }
      }
    }
  });
};

安装使用

  • 克隆项目
git clone https://github.com/sunweijieMJ/vite-vue3-temp.git
  • 安装依赖
cd vite-vue3-temp

yarn
或
npm i

  • 运行
yarn serve dev
或
npm run serve dev
  • 打包
yarn build pro
或
npm run build pro

附上 github 的项目地址:vite-vue3-temp,顺手给楼主点个 star 吧