mirror of
https://github.com/WeBankFinTech/fes.js.git
synced 2025-10-13 18:22:13 +08:00
refactor(plugin-model): 使用@vueuse/core实现模型状态共享
重构模型插件,利用@vueuse/core的createSharedComposable实现模型状态共享 移除默认容器模板,改为使用JSX实现的getRootContainer组件 优化路由初始化逻辑,将beforeRender处理移至根容器组件
This commit is contained in:
parent
c1fa59fcf8
commit
6db74bfbbc
@ -30,6 +30,7 @@
|
|||||||
"@fesjs/plugin-sass": "workspace:*",
|
"@fesjs/plugin-sass": "workspace:*",
|
||||||
"@fesjs/plugin-swc": "workspace:*",
|
"@fesjs/plugin-swc": "workspace:*",
|
||||||
"@fesjs/plugin-watermark": "workspace:*",
|
"@fesjs/plugin-watermark": "workspace:*",
|
||||||
|
"@vueuse/core": "13.9.0",
|
||||||
"core-js": "^3.45.1",
|
"core-js": "^3.45.1",
|
||||||
"pinia": "^3.0.3",
|
"pinia": "^3.0.3",
|
||||||
"vue": "^3.5.21"
|
"vue": "^3.5.21"
|
||||||
|
@ -3,6 +3,6 @@ import { ref } from 'vue';
|
|||||||
export default function user() {
|
export default function user() {
|
||||||
const count = ref(1);
|
const count = ref(1);
|
||||||
return {
|
return {
|
||||||
count
|
count,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,8 @@
|
|||||||
</config>
|
</config>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { onMounted, ref } from 'vue';
|
|
||||||
import { MonacoEditor, useLayout } from '@fesjs/fes';
|
import { MonacoEditor, useLayout } from '@fesjs/fes';
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { defineRouteMeta, useRouter } from '@fesjs/fes';
|
import { defineRouteMeta, useModel, useRouter } from '@fesjs/fes';
|
||||||
import { FButton } from '@fesjs/fes-design';
|
import { FButton } from '@fesjs/fes-design';
|
||||||
|
|
||||||
defineRouteMeta({
|
defineRouteMeta({
|
||||||
@ -16,7 +16,9 @@ defineRouteMeta({
|
|||||||
title: '$test.test',
|
title: '$test.test',
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('123123'.replaceAll('123', '234'));
|
const initialState = useModel('@@initialState');
|
||||||
|
|
||||||
|
console.log(initialState);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
function go() {
|
function go() {
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@fesjs/fes": "^3.1.12",
|
"@fesjs/fes": "^3.1.12",
|
||||||
|
"@vueuse/core": "^13.0.0",
|
||||||
"vue": "^3.5.21"
|
"vue": "^3.5.21"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
|
|
||||||
|
import { createSharedComposable } from '@vueuse/core';
|
||||||
|
|
||||||
{{{userImports}}}
|
{{{userImports}}}
|
||||||
{{{extraImports}}}
|
{{{extraImports}}}
|
||||||
|
|
||||||
@ -12,18 +14,40 @@ export const models = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const cache = new Map();
|
/**
|
||||||
|
* 使用createSharedComposable包装后的共享模型对象
|
||||||
|
* 每个模型都会被包装成可共享的组合式函数
|
||||||
|
*/
|
||||||
|
const sharedModels = {}
|
||||||
|
|
||||||
export const useModel = (name) => {
|
// 为每个模型创建共享的组合式函数
|
||||||
const modelFunc = models[name];
|
Object.keys(models).forEach(key => {
|
||||||
if (modelFunc === undefined) {
|
/**
|
||||||
throw new Error('[plugin-model]: useModel, name is undefined.');
|
* 使用createSharedComposable包装模型
|
||||||
|
* key作为唯一标识符,确保同一模型在不同组件间共享状态
|
||||||
|
*/
|
||||||
|
sharedModels[key] = createSharedComposable(models[key], `model:${key}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用模型的Hook函数
|
||||||
|
* 提供统一的模型访问接口,支持状态共享和生命周期管理
|
||||||
|
* @param {string} name - 模型名称,必须是已注册的模型
|
||||||
|
* @returns {any} 共享的模型实例,多个组件调用同一模型时返回相同的状态实例
|
||||||
|
*/
|
||||||
|
export function useModel(name) {
|
||||||
|
// 检查模型是否存在于注册列表中
|
||||||
|
if (!(name in sharedModels)) {
|
||||||
|
// 提供详细的错误信息,帮助开发者调试
|
||||||
|
const availableModels = Object.keys(sharedModels).join(', ')
|
||||||
|
throw new Error(
|
||||||
|
`模型 "${name}" 不存在。\n` +
|
||||||
|
`可用的模型有: ${availableModels}\n` +
|
||||||
|
`请检查模型名称是否正确,或确认模型文件是否已正确导出。`
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if (typeof modelFunc !== 'function') {
|
|
||||||
throw new Error('[plugin-model]: useModel is not a function.');
|
// 返回共享的模型实例
|
||||||
|
// createSharedComposable确保同一模型在不同组件间共享状态
|
||||||
|
return sharedModels[name]()
|
||||||
}
|
}
|
||||||
if (!cache.has(name)) {
|
|
||||||
cache.set(name, modelFunc());
|
|
||||||
}
|
|
||||||
return cache.get(name);
|
|
||||||
};
|
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
<template>
|
|
||||||
<router-view></router-view>
|
|
||||||
</template>
|
|
@ -6,7 +6,7 @@ import { plugin } from './core/plugin';
|
|||||||
import './core/pluginRegister';
|
import './core/pluginRegister';
|
||||||
import { ApplyPluginsType } from '{{{ runtimePath }}}';
|
import { ApplyPluginsType } from '{{{ runtimePath }}}';
|
||||||
import { getRoutes } from './core/routes/routes';
|
import { getRoutes } from './core/routes/routes';
|
||||||
import DefaultContainer from './defaultContainer.vue';
|
import getRootContainer from './getRootContainer';
|
||||||
|
|
||||||
{{{ imports }}}
|
{{{ imports }}}
|
||||||
|
|
||||||
@ -16,17 +16,8 @@ import DefaultContainer from './defaultContainer.vue';
|
|||||||
|
|
||||||
const renderClient = (opts = {}) => {
|
const renderClient = (opts = {}) => {
|
||||||
const { plugin, routes, rootElement } = opts;
|
const { plugin, routes, rootElement } = opts;
|
||||||
const rootContainer = plugin.applyPlugins({
|
|
||||||
type: ApplyPluginsType.modify,
|
|
||||||
key: 'rootContainer',
|
|
||||||
initialValue: DefaultContainer,
|
|
||||||
args: {
|
|
||||||
routes: routes,
|
|
||||||
plugin: plugin
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const app = createApp(rootContainer);
|
const app = createApp(getRootContainer(routes, plugin));
|
||||||
|
|
||||||
plugin.applyPlugins({
|
plugin.applyPlugins({
|
||||||
key: 'onAppCreated',
|
key: 'onAppCreated',
|
||||||
|
@ -0,0 +1,82 @@
|
|||||||
|
import { defineComponent, onBeforeMount, ref, provide, } from 'vue'
|
||||||
|
import { useRouter, RouterView } from 'vue-router'
|
||||||
|
import { plugin } from './core/plugin';
|
||||||
|
import { updateInitialState } from './initialState';
|
||||||
|
import { ApplyPluginsType } from '{{{ runtimePath }}}';
|
||||||
|
|
||||||
|
export const DefaultContainer = defineComponent({
|
||||||
|
name: 'DefaultContainer',
|
||||||
|
setup() {
|
||||||
|
return () => {
|
||||||
|
return <RouterView></RouterView>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export default function getRootContainer(_routes, _plugin) {
|
||||||
|
return defineComponent({
|
||||||
|
name: 'RootContainer',
|
||||||
|
setup(props) {
|
||||||
|
const RootContainer = plugin.applyPlugins({
|
||||||
|
type: ApplyPluginsType.modify,
|
||||||
|
key: 'rootContainer',
|
||||||
|
initialValue: DefaultContainer,
|
||||||
|
args: {
|
||||||
|
routes: _routes,
|
||||||
|
plugin: _plugin
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const beforeRenderConfig = plugin.applyPlugins({
|
||||||
|
key: "beforeRender",
|
||||||
|
type: ApplyPluginsType.modify,
|
||||||
|
initialValue: {
|
||||||
|
loading: null,
|
||||||
|
action: null
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (typeof beforeRenderConfig.action !== "function") {
|
||||||
|
return () => <RootContainer {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const isLoading = ref(false);
|
||||||
|
|
||||||
|
onBeforeMount(async () => {
|
||||||
|
let isInit = false
|
||||||
|
router.beforeEach(async (to, from, next) => {
|
||||||
|
if (isInit) {
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
isInit = true
|
||||||
|
isLoading.value = true;
|
||||||
|
const _initialState = await beforeRenderConfig.action({ router });
|
||||||
|
updateInitialState(_initialState);
|
||||||
|
next();
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`[fes] beforeRender执行出现异常:`);
|
||||||
|
console.error(e);
|
||||||
|
next(false);
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
plugin.applyPlugins({
|
||||||
|
key: 'onRouterCreated',
|
||||||
|
type: ApplyPluginsType.event,
|
||||||
|
args: { router },
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (isLoading.value) {
|
||||||
|
return <beforeRenderConfig.loading {...props} />
|
||||||
|
}
|
||||||
|
return <RootContainer {...props} />
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
@ -73,15 +73,14 @@ export default function (api) {
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const defaultContainerName = 'defaultContainer';
|
|
||||||
api.writeTmpFile({
|
|
||||||
path: `${defaultContainerName}.vue`,
|
|
||||||
content: readFileSync(join(__dirname, `./${defaultContainerName}.tpl`), 'utf-8'),
|
|
||||||
});
|
|
||||||
|
|
||||||
api.writeTmpFile({
|
api.writeTmpFile({
|
||||||
path: `initialState.js`,
|
path: `initialState.js`,
|
||||||
content: Mustache.render(readFileSync(join(__dirname, `./initialState.tpl`), 'utf-8')),
|
content: Mustache.render(readFileSync(join(__dirname, `./initialState.tpl`), 'utf-8')),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
api.writeTmpFile({
|
||||||
|
path: `getRootContainer.jsx`,
|
||||||
|
content: Mustache.render(readFileSync(join(__dirname, `./getRootContainer.jsx.tpl`), 'utf-8'), { runtimePath }),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import { createApp } from 'vue';
|
|
||||||
import { createRouter as createVueRouter, {{{ CREATE_HISTORY }}}, ApplyPluginsType } from '{{{ runtimePath }}}';
|
import { createRouter as createVueRouter, {{{ CREATE_HISTORY }}}, ApplyPluginsType } from '{{{ runtimePath }}}';
|
||||||
import { plugin } from '../plugin';
|
import { plugin } from '../plugin';
|
||||||
import { updateInitialState } from '../../initialState';
|
|
||||||
|
|
||||||
const ROUTER_BASE = '{{{ routerBase }}}';
|
const ROUTER_BASE = '{{{ routerBase }}}';
|
||||||
let router = null;
|
let router = null;
|
||||||
@ -37,47 +35,6 @@ export const createRouter = (routes) => {
|
|||||||
routes: route.routes
|
routes: route.routes
|
||||||
});
|
});
|
||||||
|
|
||||||
let isInit = false
|
|
||||||
router.beforeEach(async (to, from, next) => {
|
|
||||||
if(isInit){
|
|
||||||
return next()
|
|
||||||
}
|
|
||||||
isInit = true
|
|
||||||
const beforeRenderConfig = plugin.applyPlugins({
|
|
||||||
key: "beforeRender",
|
|
||||||
type: ApplyPluginsType.modify,
|
|
||||||
initialValue: {
|
|
||||||
loading: null,
|
|
||||||
action: null
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (typeof beforeRenderConfig.action !== "function") {
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
const rootElement = document.createElement('div');
|
|
||||||
document.body.appendChild(rootElement)
|
|
||||||
const app = createApp(beforeRenderConfig.loading);
|
|
||||||
app.mount(rootElement);
|
|
||||||
try {
|
|
||||||
const initialState = await beforeRenderConfig.action({router, history});
|
|
||||||
updateInitialState(initialState || {})
|
|
||||||
next();
|
|
||||||
} catch(e){
|
|
||||||
next(false);
|
|
||||||
console.error(`[fes] beforeRender执行出现异常:`);
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
app.unmount();
|
|
||||||
app._container.innerHTML = '';
|
|
||||||
document.body.removeChild(rootElement);
|
|
||||||
})
|
|
||||||
|
|
||||||
plugin.applyPlugins({
|
|
||||||
key: 'onRouterCreated',
|
|
||||||
type: ApplyPluginsType.event,
|
|
||||||
args: { router, history },
|
|
||||||
});
|
|
||||||
|
|
||||||
return router;
|
return router;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
37
pnpm-lock.yaml
generated
37
pnpm-lock.yaml
generated
@ -423,6 +423,9 @@ importers:
|
|||||||
'@fesjs/plugin-watermark':
|
'@fesjs/plugin-watermark':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../plugin-watermark
|
version: link:../plugin-watermark
|
||||||
|
'@vueuse/core':
|
||||||
|
specifier: 13.9.0
|
||||||
|
version: 13.9.0(vue@3.5.21(typescript@5.9.2))
|
||||||
core-js:
|
core-js:
|
||||||
specifier: ^3.45.1
|
specifier: ^3.45.1
|
||||||
version: 3.45.1
|
version: 3.45.1
|
||||||
@ -633,6 +636,9 @@ importers:
|
|||||||
'@fesjs/utils':
|
'@fesjs/utils':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../utils
|
version: link:../utils
|
||||||
|
'@vueuse/core':
|
||||||
|
specifier: ^10.9.0
|
||||||
|
version: 10.11.1(vue@3.5.21(typescript@5.9.2))
|
||||||
vue:
|
vue:
|
||||||
specifier: ^3.5.21
|
specifier: ^3.5.21
|
||||||
version: 3.5.21(typescript@5.9.2)
|
version: 3.5.21(typescript@5.9.2)
|
||||||
@ -3165,6 +3171,9 @@ packages:
|
|||||||
'@types/web-bluetooth@0.0.20':
|
'@types/web-bluetooth@0.0.20':
|
||||||
resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==}
|
resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==}
|
||||||
|
|
||||||
|
'@types/web-bluetooth@0.0.21':
|
||||||
|
resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==}
|
||||||
|
|
||||||
'@types/ws@8.18.1':
|
'@types/ws@8.18.1':
|
||||||
resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
|
resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
|
||||||
|
|
||||||
@ -3339,18 +3348,31 @@ packages:
|
|||||||
'@vueuse/core@10.11.1':
|
'@vueuse/core@10.11.1':
|
||||||
resolution: {integrity: sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==}
|
resolution: {integrity: sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==}
|
||||||
|
|
||||||
|
'@vueuse/core@13.9.0':
|
||||||
|
resolution: {integrity: sha512-ts3regBQyURfCE2BcytLqzm8+MmLlo5Ln/KLoxDVcsZ2gzIwVNnQpQOL/UKV8alUqjSZOlpFZcRNsLRqj+OzyA==}
|
||||||
|
peerDependencies:
|
||||||
|
vue: ^3.5.0
|
||||||
|
|
||||||
'@vueuse/core@9.13.0':
|
'@vueuse/core@9.13.0':
|
||||||
resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==}
|
resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==}
|
||||||
|
|
||||||
'@vueuse/metadata@10.11.1':
|
'@vueuse/metadata@10.11.1':
|
||||||
resolution: {integrity: sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==}
|
resolution: {integrity: sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==}
|
||||||
|
|
||||||
|
'@vueuse/metadata@13.9.0':
|
||||||
|
resolution: {integrity: sha512-1AFRvuiGphfF7yWixZa0KwjYH8ulyjDCC0aFgrGRz8+P4kvDFSdXLVfTk5xAN9wEuD1J6z4/myMoYbnHoX07zg==}
|
||||||
|
|
||||||
'@vueuse/metadata@9.13.0':
|
'@vueuse/metadata@9.13.0':
|
||||||
resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==}
|
resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==}
|
||||||
|
|
||||||
'@vueuse/shared@10.11.1':
|
'@vueuse/shared@10.11.1':
|
||||||
resolution: {integrity: sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==}
|
resolution: {integrity: sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==}
|
||||||
|
|
||||||
|
'@vueuse/shared@13.9.0':
|
||||||
|
resolution: {integrity: sha512-e89uuTLMh0U5cZ9iDpEI2senqPGfbPRTHM/0AaQkcxnpqjkZqDYP8rpfm7edOz8s+pOCOROEy1PIveSW8+fL5g==}
|
||||||
|
peerDependencies:
|
||||||
|
vue: ^3.5.0
|
||||||
|
|
||||||
'@vueuse/shared@9.13.0':
|
'@vueuse/shared@9.13.0':
|
||||||
resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==}
|
resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==}
|
||||||
|
|
||||||
@ -10718,6 +10740,8 @@ snapshots:
|
|||||||
|
|
||||||
'@types/web-bluetooth@0.0.20': {}
|
'@types/web-bluetooth@0.0.20': {}
|
||||||
|
|
||||||
|
'@types/web-bluetooth@0.0.21': {}
|
||||||
|
|
||||||
'@types/ws@8.18.1':
|
'@types/ws@8.18.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 24.3.0
|
'@types/node': 24.3.0
|
||||||
@ -10990,6 +11014,13 @@ snapshots:
|
|||||||
- '@vue/composition-api'
|
- '@vue/composition-api'
|
||||||
- vue
|
- vue
|
||||||
|
|
||||||
|
'@vueuse/core@13.9.0(vue@3.5.21(typescript@5.9.2))':
|
||||||
|
dependencies:
|
||||||
|
'@types/web-bluetooth': 0.0.21
|
||||||
|
'@vueuse/metadata': 13.9.0
|
||||||
|
'@vueuse/shared': 13.9.0(vue@3.5.21(typescript@5.9.2))
|
||||||
|
vue: 3.5.21(typescript@5.9.2)
|
||||||
|
|
||||||
'@vueuse/core@9.13.0(vue@3.5.21(typescript@5.9.2))':
|
'@vueuse/core@9.13.0(vue@3.5.21(typescript@5.9.2))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/web-bluetooth': 0.0.16
|
'@types/web-bluetooth': 0.0.16
|
||||||
@ -11002,6 +11033,8 @@ snapshots:
|
|||||||
|
|
||||||
'@vueuse/metadata@10.11.1': {}
|
'@vueuse/metadata@10.11.1': {}
|
||||||
|
|
||||||
|
'@vueuse/metadata@13.9.0': {}
|
||||||
|
|
||||||
'@vueuse/metadata@9.13.0': {}
|
'@vueuse/metadata@9.13.0': {}
|
||||||
|
|
||||||
'@vueuse/shared@10.11.1(vue@3.5.21(typescript@5.9.2))':
|
'@vueuse/shared@10.11.1(vue@3.5.21(typescript@5.9.2))':
|
||||||
@ -11011,6 +11044,10 @@ snapshots:
|
|||||||
- '@vue/composition-api'
|
- '@vue/composition-api'
|
||||||
- vue
|
- vue
|
||||||
|
|
||||||
|
'@vueuse/shared@13.9.0(vue@3.5.21(typescript@5.9.2))':
|
||||||
|
dependencies:
|
||||||
|
vue: 3.5.21(typescript@5.9.2)
|
||||||
|
|
||||||
'@vueuse/shared@9.13.0(vue@3.5.21(typescript@5.9.2))':
|
'@vueuse/shared@9.13.0(vue@3.5.21(typescript@5.9.2))':
|
||||||
dependencies:
|
dependencies:
|
||||||
vue-demi: 0.14.10(vue@3.5.21(typescript@5.9.2))
|
vue-demi: 0.14.10(vue@3.5.21(typescript@5.9.2))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user