✨ feat: 2048支持移动端
This commit is contained in:
parent
47952a774e
commit
656538fecc
20
package.json
20
package.json
@ -18,7 +18,7 @@
|
||||
"@vueuse/core": "^10.11.1",
|
||||
"axios": "^1.7.9",
|
||||
"crypto-js": "^4.2.0",
|
||||
"element-plus": "^2.9.0",
|
||||
"element-plus": "^2.9.1",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"mitt": "^3.0.1",
|
||||
@ -26,18 +26,19 @@
|
||||
"vfonts": "^0.0.3",
|
||||
"vue": "^3.5.13",
|
||||
"vue-router": "^4.5.0",
|
||||
"zod": "^3.23.8"
|
||||
"vue3-touch-events": "^4.2.0",
|
||||
"zod": "^3.24.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.26.0",
|
||||
"@babel/preset-env": "^7.26.0",
|
||||
"@iconify-json/ep": "^1.2.1",
|
||||
"@iconify-json/ep": "^1.2.2",
|
||||
"@rushstack/eslint-patch": "^1.10.4",
|
||||
"@tsconfig/node20": "^20.1.4",
|
||||
"@types/crypto-js": "^4.2.2",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/node": "^20.17.9",
|
||||
"@unocss/transformer-directives": "^0.65.1",
|
||||
"@types/node": "^20.17.10",
|
||||
"@unocss/transformer-directives": "^0.65.2",
|
||||
"@vitejs/plugin-legacy": "^6.0.0",
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"@vitejs/plugin-vue-jsx": "^4.1.1",
|
||||
@ -48,15 +49,14 @@
|
||||
"eslint-plugin-vue": "^9.32.0",
|
||||
"npm-run-all2": "^6.2.6",
|
||||
"prettier": "^3.4.2",
|
||||
"sass": "^1.82.0",
|
||||
"sass": "^1.83.0",
|
||||
"terser": "^5.37.0",
|
||||
"typescript": "^5.7.2",
|
||||
"unocss": "^0.65.1",
|
||||
"unplugin-auto-import": "^0.17.8",
|
||||
"unocss": "^0.65.2",
|
||||
"unplugin-icons": "^0.18.5",
|
||||
"unplugin-vue-components": "^0.26.0",
|
||||
"vite": "^6.0.0",
|
||||
"vue-tsc": "^1.8.27"
|
||||
"vite": "^6.0.5",
|
||||
"vue-tsc": "^2.1.10"
|
||||
},
|
||||
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
||||
}
|
||||
|
@ -114,6 +114,8 @@ import LoginRegisterDialog, {
|
||||
loginImplKey,
|
||||
registerImplKey,
|
||||
} from '@/components/app/LoginRegisterDialog.vue';
|
||||
import router from '@/router';
|
||||
import { loginRespSchema, registerRespSchema } from '@/schemas/response';
|
||||
import { useMediaStore } from '@/stores/media';
|
||||
import { usePageStore } from '@/stores/page.js';
|
||||
import { useUserStore } from '@/stores/user';
|
||||
@ -123,8 +125,6 @@ import type { AxiosError } from 'axios';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { provide, ref, watch } from 'vue';
|
||||
import { loginResponseSchema, registerResponseSchema } from './schemas/response';
|
||||
import router from '@/router';
|
||||
const userStore = useUserStore();
|
||||
const pageStore = usePageStore();
|
||||
const { mdLess } = storeToRefs(useMediaStore());
|
||||
@ -138,7 +138,7 @@ provide(loginImplKey, async (params) => {
|
||||
ElMessage.error([err.code, err.message].join(':'));
|
||||
});
|
||||
if (!loginRespRaw) return false;
|
||||
const resp = loginResponseSchema.parse(loginRespRaw);
|
||||
const resp = loginRespSchema.parse(loginRespRaw);
|
||||
if (resp.type === 'error') {
|
||||
ElMessage.error([resp.code, resp.msg].join(':'));
|
||||
return false;
|
||||
@ -153,7 +153,7 @@ provide(registerImplKey, async (params) => {
|
||||
ElMessage.error([err.code, err.message].join(':'));
|
||||
});
|
||||
if (!raw) return false;
|
||||
const resp = registerResponseSchema.parse(raw);
|
||||
const resp = registerRespSchema.parse(raw);
|
||||
if (resp.type === 'error') {
|
||||
ElMessage.error([resp.code, resp.msg].join(':'));
|
||||
return false;
|
||||
|
@ -1,4 +1,9 @@
|
||||
import { userInfoResponseSchema } from '@/schemas';
|
||||
import {
|
||||
userInfoRespSchema,
|
||||
userInfoRespSchemaNullable,
|
||||
type SucceedUserInfoResp,
|
||||
type SucceedUserInfoRespNullable,
|
||||
} from '@/schemas';
|
||||
import { useUserStore } from '@/stores/user';
|
||||
import axios, { type AxiosError } from 'axios';
|
||||
import { ElMessage } from 'element-plus';
|
||||
@ -26,9 +31,14 @@ axiosInstance.interceptors.response.use((response) => {
|
||||
});
|
||||
export default axiosInstance;
|
||||
export type RawResp = Record<string, unknown>;
|
||||
export async function getUserInfo(showErrorMessage: boolean, userID?: string) {
|
||||
export async function getUserInfo(showErrorMessage: boolean): Promise<SucceedUserInfoResp>;
|
||||
export async function getUserInfo(
|
||||
showErrorMessage: boolean,
|
||||
userID: number,
|
||||
): Promise<SucceedUserInfoRespNullable>;
|
||||
export async function getUserInfo(showErrorMessage: boolean, userID?: number) {
|
||||
let url = '/api/user/info';
|
||||
if (userID) {
|
||||
if (userID !== undefined) {
|
||||
url += `/${userID}`;
|
||||
}
|
||||
const raw = await axiosInstance
|
||||
@ -39,7 +49,7 @@ export async function getUserInfo(showErrorMessage: boolean, userID?: string) {
|
||||
ElMessage.error(errorMessage('获取用户信息失败', e.code, e.message));
|
||||
});
|
||||
if (!raw) return;
|
||||
const resp = userInfoResponseSchema.parse(raw);
|
||||
const resp = (userID !== undefined ? userInfoRespSchemaNullable : userInfoRespSchema).parse(raw);
|
||||
if (resp.type === 'error') {
|
||||
if (showErrorMessage) {
|
||||
ElMessage.error(errorMessage('获取用户信息失败', resp.code, resp.msg));
|
||||
|
@ -1,4 +0,0 @@
|
||||
import mitt from 'mitt';
|
||||
|
||||
type Events = {};
|
||||
export const bus = mitt<Events>();
|
@ -179,7 +179,7 @@ const inputLength = 3;
|
||||
const loginFormRules = reactive<FormRules<typeof loginFormData>>({
|
||||
username: [
|
||||
{ required: true, message: '请输入用户名' },
|
||||
{ min: inputLength, message: `用户名长度不能小${inputLength}6位` },
|
||||
{ min: inputLength, message: `用户名长度不能小于${inputLength}位` },
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: '请输入密码' },
|
||||
|
@ -36,7 +36,7 @@
|
||||
</style>
|
||||
<script lang="ts" setup>
|
||||
import axiosInstance from '@/api';
|
||||
import { verifyResponseSchema } from '@/schemas';
|
||||
import { verifyRespSchema } from '@/schemas';
|
||||
import { timeout } from '@/utils';
|
||||
import { errorMessage } from '@/utils/api';
|
||||
import { AxiosError } from 'axios';
|
||||
@ -96,7 +96,7 @@ async function updateVerifyImage() {
|
||||
model.value.verifyImage = 'fetching';
|
||||
try {
|
||||
try {
|
||||
const verifyResponse = verifyResponseSchema.parse(
|
||||
const verifyResponse = verifyRespSchema.parse(
|
||||
(await axiosInstance.get('/api/user/verify')).data,
|
||||
);
|
||||
console.log(verifyResponse);
|
||||
|
@ -190,28 +190,27 @@
|
||||
}
|
||||
</style>
|
||||
<script lang="ts" setup>
|
||||
import { type GameState, type Tile, useGame2048Store } from '@/stores/2048';
|
||||
import { useGame2048Store, type GameState, type Tile } from '@/stores/2048';
|
||||
import { chainIterables } from '@/utils';
|
||||
import { get2DArrayItem } from '@/utils/array';
|
||||
import { useEmitterEventListener } from '@/utils/emitter';
|
||||
import type { Future } from '@/utils/types';
|
||||
import { Directions, swipeEmitterKey } from '@/views/Game2048Page.vue';
|
||||
import { useEventListener } from '@vueuse/core';
|
||||
import { ElNotification } from 'element-plus';
|
||||
import { add, pick, sample, shuffle } from 'lodash-es';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { computed, onMounted, onUnmounted, reactive, ref, watch } from 'vue';
|
||||
|
||||
import {
|
||||
computed,
|
||||
inject,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
reactive,
|
||||
ref,
|
||||
watch
|
||||
} from 'vue';
|
||||
const game2048Store = useGame2048Store();
|
||||
|
||||
/**
|
||||
* 方向键代码.
|
||||
*/
|
||||
enum Directions {
|
||||
UP = 'ArrowUp',
|
||||
DOWN = 'ArrowDown',
|
||||
LEFT = 'ArrowLeft',
|
||||
RIGHT = 'ArrowRight',
|
||||
}
|
||||
|
||||
type SingleTileLine = (Tile | undefined)[];
|
||||
type OverlappedTileLine = Tile[][];
|
||||
/**
|
||||
@ -575,14 +574,14 @@ async function mergeTiles(direction: Directions) {
|
||||
return Array.from(
|
||||
(function* () {
|
||||
switch (d) {
|
||||
case 'ArrowUp':
|
||||
case 'ArrowDown':
|
||||
case Directions.UP:
|
||||
case Directions.DOWN:
|
||||
for (let x = 0; x < width.value; x++) {
|
||||
yield x;
|
||||
}
|
||||
break;
|
||||
case 'ArrowLeft':
|
||||
case 'ArrowRight':
|
||||
case Directions.LEFT:
|
||||
case Directions.RIGHT:
|
||||
for (let y = 0; y < height.value; y++) {
|
||||
yield y;
|
||||
}
|
||||
@ -596,23 +595,23 @@ async function mergeTiles(direction: Directions) {
|
||||
return Array.from(
|
||||
(function* () {
|
||||
switch (d) {
|
||||
case 'ArrowUp':
|
||||
case Directions.UP:
|
||||
for (let y = height.value - 1; y >= 0; y--) {
|
||||
yield y;
|
||||
}
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
case Directions.DOWN:
|
||||
for (let y = 0; y < height.value; y++) {
|
||||
yield y;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'ArrowLeft':
|
||||
case Directions.LEFT:
|
||||
for (let x = width.value - 1; x >= 0; x--) {
|
||||
yield x;
|
||||
}
|
||||
break;
|
||||
case 'ArrowRight':
|
||||
case Directions.RIGHT:
|
||||
for (let x = 0; x < width.value; x++) {
|
||||
yield x;
|
||||
}
|
||||
@ -693,12 +692,11 @@ function onTileTransitionComplete(event: TransitionEvent) {
|
||||
const tileId = getElementTileId(event.currentTarget as HTMLDivElement);
|
||||
tileTransitionFutureMap.resolve(tileId);
|
||||
}
|
||||
|
||||
useEventListener(document, 'keydown', async (e: KeyboardEvent) => {
|
||||
async function move(key: string) {
|
||||
if (locked.value || gameStatus.value !== 'playing') {
|
||||
return;
|
||||
}
|
||||
switch (e.key) {
|
||||
switch (key) {
|
||||
case Directions.UP:
|
||||
case Directions.DOWN:
|
||||
case Directions.LEFT:
|
||||
@ -716,7 +714,7 @@ useEventListener(document, 'keydown', async (e: KeyboardEvent) => {
|
||||
locked.value = false;
|
||||
}
|
||||
isTileTransitioning.value = true;
|
||||
if (!(await mergeTiles(e.key)) && gameStatus.value === 'playing') {
|
||||
if (!(await mergeTiles(key)) && gameStatus.value === 'playing') {
|
||||
gameStatus.value = 'failed';
|
||||
}
|
||||
if (gameStatus.value !== 'playing') {
|
||||
@ -728,6 +726,11 @@ useEventListener(document, 'keydown', async (e: KeyboardEvent) => {
|
||||
isTileTransitioning.value = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const emitter = inject(swipeEmitterKey)!;
|
||||
useEmitterEventListener(emitter, 'swipe', move);
|
||||
useEventListener(document, 'keydown', async (e) => {
|
||||
move(e.key);
|
||||
});
|
||||
onMounted(async () => {
|
||||
await gameReadyFuture.promise;
|
||||
|
11
src/main.ts
11
src/main.ts
@ -1,11 +1,10 @@
|
||||
import 'virtual:uno.css';
|
||||
import '@/assets/global.scss';
|
||||
import 'element-plus/theme-chalk/index.css';
|
||||
import 'element-plus/theme-chalk/display.css';
|
||||
import App from '@/App.vue';
|
||||
import '@/assets/global.scss';
|
||||
import router from '@/router';
|
||||
import 'element-plus/dist/index.css';
|
||||
import { createPinia } from 'pinia';
|
||||
import 'virtual:uno.css';
|
||||
import { createApp } from 'vue';
|
||||
|
||||
import Vue3TouchEvents, { type Vue3TouchEventsOptions } from 'vue3-touch-events';
|
||||
const app = createApp(App);
|
||||
app.use(createPinia()).use(router).mount('#app');
|
||||
app.use(createPinia()).use(router).use<Vue3TouchEventsOptions>(Vue3TouchEvents, {}).mount('#app');
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
function createResponseSchema<T extends z.ZodTypeAny>(data: T) {
|
||||
function createRespSchema<T extends z.ZodTypeAny>(data: T) {
|
||||
return z.union([
|
||||
z
|
||||
.object({
|
||||
@ -28,11 +28,11 @@ function createResponseSchema<T extends z.ZodTypeAny>(data: T) {
|
||||
]);
|
||||
}
|
||||
|
||||
export type SucceedResponseOf<T> = Extract<T, { type: 'success' }>;
|
||||
export type ErrorResponseOf<T> = Exclude<SucceedResponseOf<T>, T>;
|
||||
export const ordinarySchema = createResponseSchema(z.literal(true));
|
||||
export const loginResponseSchema = ordinarySchema;
|
||||
export const registerResponseSchema = ordinarySchema;
|
||||
export type SucceedRespOf<T> = Extract<T, { type: 'success' }>;
|
||||
export type ErrorRespOf<T> = Exclude<SucceedRespOf<T>, T>;
|
||||
export const ordinarySchema = createRespSchema(z.literal(true));
|
||||
export const loginRespSchema = ordinarySchema;
|
||||
export const registerRespSchema = ordinarySchema;
|
||||
export const idAndNameSchema = z.object({
|
||||
id: z.number(),
|
||||
name: z.string(),
|
||||
@ -41,21 +41,22 @@ export const idAndNameSchema = z.object({
|
||||
const authSchema = idAndNameSchema.extend({
|
||||
permissions: idAndNameSchema.array(),
|
||||
});
|
||||
export const userInfoResponseSchema = createResponseSchema(
|
||||
idAndNameSchema.extend({
|
||||
avatar: z.nullable(z.string()),
|
||||
auth: authSchema,
|
||||
club: z.nullable(
|
||||
idAndNameSchema.extend({
|
||||
commit: z.string(),
|
||||
auth: authSchema,
|
||||
}),
|
||||
),
|
||||
}),
|
||||
);
|
||||
export type SucceedUserInfoResponse = SucceedResponseOf<z.infer<typeof userInfoResponseSchema>>;
|
||||
export type UserInfo = SucceedUserInfoResponse['data'];
|
||||
export const verifyResponseSchema = createResponseSchema(
|
||||
const userInfoDataSchema = idAndNameSchema.extend({
|
||||
avatar: z.nullable(z.string()),
|
||||
auth: authSchema,
|
||||
club: z.nullable(
|
||||
idAndNameSchema.extend({
|
||||
commit: z.string(),
|
||||
auth: authSchema,
|
||||
}),
|
||||
),
|
||||
});
|
||||
export const userInfoRespSchema = createRespSchema(userInfoDataSchema);
|
||||
export const userInfoRespSchemaNullable = createRespSchema(userInfoDataSchema.nullable());
|
||||
export type SucceedUserInfoResp = SucceedRespOf<z.infer<typeof userInfoRespSchema>>;
|
||||
export type SucceedUserInfoRespNullable = SucceedRespOf<z.infer<typeof userInfoRespSchemaNullable>>;
|
||||
export type UserInfo = SucceedUserInfoResp['data'];
|
||||
export const verifyRespSchema = createRespSchema(
|
||||
z
|
||||
.object({
|
||||
img: z.string(),
|
||||
|
23
src/utils/emitter.ts
Normal file
23
src/utils/emitter.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import type { Emitter, EventType } from 'mitt';
|
||||
import mitt from 'mitt';
|
||||
import { onUnmounted, provide, type InjectionKey } from 'vue';
|
||||
export function useEmitter<M extends Record<EventType, unknown>>(
|
||||
key?: InjectionKey<Emitter<M>>,
|
||||
): Emitter<M> {
|
||||
const emitter = mitt<M>();
|
||||
if (key) provide(key, emitter);
|
||||
onUnmounted(() => {
|
||||
emitter.all.clear();
|
||||
});
|
||||
return emitter;
|
||||
}
|
||||
export function useEmitterEventListener<M extends Record<EventType, unknown>, T extends keyof M>(
|
||||
emitter: Emitter<M>,
|
||||
type: T,
|
||||
listener: (event: M[T]) => void,
|
||||
) {
|
||||
emitter.on(type, listener);
|
||||
onUnmounted(() => {
|
||||
emitter.off(type, listener);
|
||||
});
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-main class="game-2048-page-wrapper !flex justify-center">
|
||||
<el-main v-touch:swipe="onSwipe" class="game-2048-page-wrapper !flex justify-center">
|
||||
<div class="game-2048-page">
|
||||
<div class="game-header">
|
||||
<div class="game-title">
|
||||
@ -65,20 +65,54 @@
|
||||
width: auto;
|
||||
}
|
||||
</style>
|
||||
<script lang="ts">
|
||||
/**
|
||||
* 方向键代码.
|
||||
*/
|
||||
export enum Directions {
|
||||
UP = 'ArrowUp',
|
||||
DOWN = 'ArrowDown',
|
||||
LEFT = 'ArrowLeft',
|
||||
RIGHT = 'ArrowRight',
|
||||
}
|
||||
export type SwipeEventMap = {
|
||||
swipe: Directions;
|
||||
};
|
||||
const swipeDirectionMap = {
|
||||
top: Directions.UP,
|
||||
bottom: Directions.DOWN,
|
||||
left: Directions.LEFT,
|
||||
right: Directions.RIGHT,
|
||||
};
|
||||
export const swipeEmitterKey = Symbol() as InjectionKey<Emitter<SwipeEventMap>>;
|
||||
</script>
|
||||
<script lang="ts" setup>
|
||||
import Game2048 from '@/components/game2048/Game2048.vue';
|
||||
import Game2048Button from '@/components/game2048/Game2048Button.vue';
|
||||
import Game2048Score from '@/components/game2048/Game2048Score.vue';
|
||||
import { useGame2048Store } from '@/stores/2048';
|
||||
import { useMediaStore } from '@/stores/media';
|
||||
import { useEmitter } from '@/utils/emitter';
|
||||
import { useEventListener } from '@vueuse/core';
|
||||
import type { Emitter } from 'mitt';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { computed } from 'vue';
|
||||
|
||||
import { computed, type InjectionKey } from 'vue';
|
||||
const emitter = useEmitter<SwipeEventMap>(swipeEmitterKey);
|
||||
function onSwipe(d: keyof typeof swipeDirectionMap) {
|
||||
emitter.emit('swipe', swipeDirectionMap[d]);
|
||||
}
|
||||
const game2048Store = useGame2048Store();
|
||||
const { smLess } = storeToRefs(useMediaStore());
|
||||
const zoomCSS = computed(() => {
|
||||
return smLess.value ? 0.75 : 1;
|
||||
});
|
||||
useEventListener(
|
||||
'touchmove',
|
||||
(e) => {
|
||||
e.preventDefault();
|
||||
},
|
||||
{ passive: false },
|
||||
);
|
||||
function click() {
|
||||
game2048Store.$reset();
|
||||
console.log(game2048Store.gameKey);
|
||||
|
@ -46,17 +46,33 @@ import { getUserInfo } from '@/api';
|
||||
import { type UserInfo } from '@/schemas';
|
||||
import { useMediaStore } from '@/stores/media';
|
||||
import { useUserStore } from '@/stores/user';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
const { lgLess, lgOnly } = storeToRefs(useMediaStore());
|
||||
const route = useRoute();
|
||||
const userStore = useUserStore();
|
||||
const loading = ref(true);
|
||||
const userInfo = ref<UserInfo>();
|
||||
async function loadUserInfo() {
|
||||
loading.value = true;
|
||||
const id = Number(route.params.id as string);
|
||||
try {
|
||||
const resp = await getUserInfo(true);
|
||||
if (isNaN(id)) {
|
||||
ElMessage.error('参数错误');
|
||||
return;
|
||||
}
|
||||
if (id === -1) {
|
||||
ElMessage.error('用户不存在');
|
||||
return;
|
||||
}
|
||||
const resp = await getUserInfo(true, id);
|
||||
if (!resp) return;
|
||||
if (!resp.data) {
|
||||
ElMessage.error('用户不存在');
|
||||
return;
|
||||
}
|
||||
userInfo.value = resp.data;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
|
@ -10,6 +10,7 @@
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
},
|
||||
"noEmit": true,
|
||||
"types": ["unplugin-icons/types/vue"],
|
||||
"jsx": "preserve",
|
||||
"jsxImportSource": "vue"
|
||||
|
@ -10,14 +10,10 @@ import Components from 'unplugin-vue-components/vite';
|
||||
import { defineConfig } from 'vite';
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
build: {
|
||||
target: 'es2015',
|
||||
},
|
||||
plugins: [
|
||||
legacy({
|
||||
targets: ['defaults', 'Chrome >= 100', 'Edge >= 100', 'FireFox >= 110'],
|
||||
polyfills: ['es.promise.with-resolvers'],
|
||||
modernPolyfills: ['es.promise.with-resolvers'],
|
||||
modernPolyfills: true,
|
||||
}),
|
||||
vue(),
|
||||
Components({
|
||||
@ -30,10 +26,10 @@ export default defineConfig({
|
||||
}),
|
||||
],
|
||||
globs: [
|
||||
'!src/components/*.vue',
|
||||
'!src/components/**/*.vue',
|
||||
'!src/views/*.vue',
|
||||
'!src/views/**/*.vue',
|
||||
'!./src/components/*.vue',
|
||||
'!./src/components/**/*.vue',
|
||||
'!./src/views/*.vue',
|
||||
'!./src/views/**/*.vue',
|
||||
],
|
||||
}),
|
||||
Icons({
|
||||
@ -47,7 +43,6 @@ export default defineConfig({
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': resolve('./src'),
|
||||
// vue: 'vue/dist/vue.esm-bundler.js'
|
||||
},
|
||||
},
|
||||
server: {
|
||||
|
Loading…
x
Reference in New Issue
Block a user