vite+vue3初体验

简介

使用最新的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 吧

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容