added vue3-sfc-loader

This commit is contained in:
Marvin Zhang
2021-08-23 11:09:34 +08:00
parent c6ce602b3b
commit 047dcca4a3
17 changed files with 18006 additions and 117 deletions

View File

@@ -1,5 +1,5 @@
{
"name": "crawlab-frontend",
"name": "@crawlab/frontend",
"version": "0.6.0-beta.20210715",
"private": false,
"scripts": {
@@ -48,6 +48,7 @@
"vue-i18n": "^9.0.0-beta.11",
"vue-router": "^4.0.0-0",
"vue3-dropzone": "^0.0.7",
"vue3-sfc-loader": "^0.8.4",
"vuex": "^4.0.0-0"
},
"devDependencies": {

View File

@@ -7,6 +7,8 @@
<link href="<%= BASE_URL %>favicon.ico" rel="icon">
<link href="font-awesome.min.css" rel="stylesheet">
<title><%= htmlWebpackPlugin.options.title %></title>
<script src="/js/vue.global.js"></script>
<script src="/js/vue3-sfc-loader.js"></script>
<style>
#loading-placeholder {
position: fixed;

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,19 @@
<template>
App
<hello-world/>
</template>
<script lang="ts">
import {defineComponent} from 'vue';
import HelloWorld from './HelloWorld.vue';
export default defineComponent({
name: 'App',
components: {
HelloWorld,
},
setup() {
return {};
},
});
</script>

View File

@@ -0,0 +1,12 @@
<template>
Hello World
</template>
<script lang="ts">
export default {
name: 'HelloWorld',
setup() {
return {};
},
};
</script>

View File

@@ -23,7 +23,7 @@ import {computed, defineComponent, PropType} from 'vue';
import MenuItemIcon from '@/components/icon/MenuItemIcon.vue';
import {useStore} from 'vuex';
import {getPrimaryPath} from '@/utils/path';
import {useI18n} from 'vue-i18n';
// import {useI18n} from 'vue-i18n';
import {useRouter} from 'vue-router';
import Icon from '@/components/icon/Icon.vue';
@@ -57,7 +57,7 @@ export default defineComponent({
'click',
],
setup(props: TabProps, {emit}) {
const {tm} = useI18n();
// const {tm} = useI18n();
const router = useRouter();
const storeNamespace = 'layout';
const store = useStore();
@@ -77,7 +77,8 @@ export default defineComponent({
const title = computed(() => {
// TODO: detailed title
return item.value?.title || tm('No Title');
// return item.value?.title || tm('No Title');
return item.value?.title;
});
const active = computed(() => {

View File

@@ -1,5 +1,11 @@
interface Window {
initCanvas?: Function;
resetCanvas?: Function;
_hmt?: Array;
import Vue from 'vue';
declare global {
interface Window {
initCanvas?: Function;
resetCanvas?: Function;
_hmt?: Array;
'vue3-sfc-loader': { loadModule };
Vue: Vue;
}
}

View File

@@ -1,12 +1,12 @@
<template>
<span :class="sidebarCollapsed ? 'collapsed' : ''" class="sidebar-toggle" @click="toggleSidebar">
<font-awesome-icon v-if="!sidebarCollapsed" :icon="['fas', 'outdent']"/>
<font-awesome-icon v-else :icon="['fas', 'indent']"/>
<font-awesome-icon v-if="!sidebarCollapsed" :icon="['fas', 'outdent']" />
<font-awesome-icon v-else :icon="['fas', 'indent']" />
</span>
<el-aside :class="sidebarCollapsed ? 'collapsed' : ''" class="sidebar" width="inherit">
<div class="logo-container">
<div class="logo">
<img :src="logo" alt="logo" className="logo-img"/>
<img :src="logo" alt="logo" className="logo-img" />
<span class="logo-title">Crawlab</span>
<span class="logo-sub-title">
<div class="logo-sub-title-block">
@@ -32,14 +32,16 @@
:index="item.path"
@click="onMenuItemClick(item)"
>
<MenuItemIcon :item="item" size="normal"/>
<MenuItemIcon :item="item" size="normal" />
<template #title>
<span class="menu-item-title">{{ item.title }}</span>
</template>
</el-menu-item>
<div class="plugin-anchor" />
</el-menu>
</div>
</el-aside>
<div class="script-anchor" />
</template>
<script lang="ts">

View File

@@ -3,7 +3,7 @@ import ElementPlus from 'element-plus';
import App from '@/App.vue';
import router from '@/router';
import store from '@/store';
import i18n from '@/i18n';
// import i18n from '@/i18n';
import {FontAwesomeIcon} from '@fortawesome/vue-fontawesome';
import {library} from '@fortawesome/fontawesome-svg-core';
import {fab} from '@fortawesome/free-brands-svg-icons';
@@ -23,10 +23,11 @@ initBaiduTonji();
// remove loading placeholder
document.querySelector('#loading-placeholder')?.remove();
createApp(App)
const app = createApp(App);
app
.use(store)
.use(router)
.use(ElementPlus)
.use(i18n)
// .use(i18n)
.component('font-awesome-icon', FontAwesomeIcon)
.mount('#app');

View File

@@ -9,6 +9,7 @@ import schedule from '@/router/schedule';
import user from '@/router/user';
import tag from '@/router/tag';
import token from '@/router/token';
import plugin from '@/router/plugin';
import {initRouterAuth} from '@/router/auth';
import {sendPv} from '@/utils/admin';
@@ -28,6 +29,7 @@ export const routes: Array<RouteRecordRaw> = [
...user,
...tag,
...token,
...plugin,
],
},
];
@@ -42,6 +44,7 @@ export const menuItems: MenuItem[] = [
{path: '/users', title: 'Users', icon: ['fa', 'users']},
{path: '/tags', title: 'Tags', icon: ['fa', 'tag']},
{path: '/tokens', title: 'Tokens', icon: ['fa', 'key']},
{path: '/plugins', title: 'Plugins', icon: ['fa', 'plug']},
];
const router = createRouter({

View File

@@ -0,0 +1,13 @@
import {defineAsyncComponent} from 'vue';
import {RouteRecordRaw} from 'vue-router';
import {getLoadModuleOptions, loadModule} from '@/utils/sfc';
const endpoint = 'plugins';
export default [
{
path: endpoint,
// component: defineAsyncComponent(() => loadModule('/vue/HelloWorld.vue', getLoadModuleOptions())),
component: defineAsyncComponent(() => loadModule('/vue/App.vue', getLoadModuleOptions())),
},
] as Array<RouteRecordRaw>;

39
frontend/src/utils/sfc.ts Normal file
View File

@@ -0,0 +1,39 @@
const vue = window['Vue'];
const {loadModule: sfcLoadModule} = window['vue3-sfc-loader'];
export const getLoadModuleOptions = () => {
return {
moduleCache: {
vue,
},
pathResolve({ refPath, relPath }: {refPath?: string; relPath?: string}) {
// self
if ( relPath === '.' ) {
return refPath;
}
// relPath is a module name ?
if ( relPath?.[0] !== '.' && relPath?.[0] !== '/' ) {
return relPath;
}
return String(new URL(relPath, refPath === undefined ? window.location.toString() : refPath));
},
async getFile(url: string) {
const res = await fetch(url);
if (!res.ok) {
throw Object.assign(new Error(res.statusText + ' ' + url), {res});
}
return {
getContentData: (asBinary: boolean) => asBinary ? res.arrayBuffer() : res.text(),
};
},
addStyle(textContent: string) {
const style = Object.assign(document.createElement('style'), {textContent});
const ref = document.head.getElementsByTagName('style')[0] || null;
document.head.insertBefore(style, ref);
},
};
};
export const loadModule = sfcLoadModule;

View File

@@ -117,7 +117,6 @@
<script lang="ts">
import {computed, defineComponent, onMounted, onUnmounted, ref} from 'vue';
import {isValidUsername} from '@/utils/validate';
import {useI18n} from 'vue-i18n';
import {useRoute, useRouter} from 'vue-router';
import logo from '@/assets/logo.svg';
import {ElForm, ElMessage} from 'element-plus';

View File

@@ -9868,6 +9868,11 @@ vue3-dropzone@^0.0.7:
attr-accept "^2.2.2"
file-selector "^0.2.4"
vue3-sfc-loader@^0.8.4:
version "0.8.4"
resolved "https://registry.nlark.com/vue3-sfc-loader/download/vue3-sfc-loader-0.8.4.tgz#b13309c2a466a4a9139ece4a42047e157ad8e21b"
integrity sha1-sTMJwqRmpKkTns5KQgR+FXrY4hs=
vue@^3.0.4:
version "3.0.11"
resolved "https://registry.npm.taobao.org/vue/download/vue-3.0.11.tgz#c82f9594cbf4dcc869241d4c8dd3e08d9a8f4b5f"