使用最新的
vue3
,vite2
,typescript
等主流技术搭建的一个供学习参考的模版工程。
vue3
,vite
,typescript
等前沿技术开发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 配置文件
可参考上一章,ts对axios的简单封装
推荐使用
vscode
插件i18n Ally
来协助开发,具有以下功能
// 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
NODE_ENV=development
VITE_Version = 'v1.0.0'
VITE_BaseURL = '//dev.backendapi.aid.connext.net.cn/'
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();
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 吧