perf(vite): chunk webcams, locales and large libraries (#1578)

This commit is contained in:
Pieter Willekens 2023-10-07 23:00:35 +02:00 committed by GitHub
parent 817efba0d8
commit 32122348b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
60 changed files with 875 additions and 784 deletions

1284
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -34,8 +34,6 @@
"@jaames/iro": "^5.5.2", "@jaames/iro": "^5.5.2",
"@lezer/highlight": "^1.0.0", "@lezer/highlight": "^1.0.0",
"@sindarius/gcodeviewer": "^3.2.2", "@sindarius/gcodeviewer": "^3.2.2",
"@types/node": "^18.0.0",
"@types/overlayscrollbars": "^1.12.1",
"@uiw/codemirror-theme-vscode": "^4.19.11", "@uiw/codemirror-theme-vscode": "^4.19.11",
"axios": "^0.27.0", "axios": "^0.27.0",
"codemirror": "^6.0.1", "codemirror": "^6.0.1",
@ -45,12 +43,12 @@
"echarts-gl": "^2.0.8", "echarts-gl": "^2.0.8",
"hls.js": "^1.3.3", "hls.js": "^1.3.3",
"jmuxer": "^2.0.5", "jmuxer": "^2.0.5",
"js-sha256": "^0.9.0", "js-sha256": "^0.10.0",
"lodash.kebabcase": "^4.1.1", "lodash.kebabcase": "^4.1.1",
"lodash.throttle": "^4.1.1", "lodash.throttle": "^4.1.1",
"overlayscrollbars": "^1.13.1", "overlayscrollbars": "^1.13.1",
"overlayscrollbars-vue": "^0.2.2", "overlayscrollbars-vue": "^0.2.2",
"regenerator-runtime": "^0.13.9", "regenerator-runtime": "^0.14.0",
"resize-observer-polyfill": "^1.5.1", "resize-observer-polyfill": "^1.5.1",
"semver": "^7.5.2", "semver": "^7.5.2",
"typed_janus_js": "^1.0.14", "typed_janus_js": "^1.0.14",
@ -76,8 +74,10 @@
"@types/jmuxer": "^2.0.3", "@types/jmuxer": "^2.0.3",
"@types/lodash.kebabcase": "^4.1.6", "@types/lodash.kebabcase": "^4.1.6",
"@types/lodash.throttle": "^4.1.6", "@types/lodash.throttle": "^4.1.6",
"@types/node": "^20.0.0",
"@types/overlayscrollbars": "^1.12.1",
"@types/semver": "^7.3.8", "@types/semver": "^7.3.8",
"@types/uuid": "^8.3.1", "@types/uuid": "^9.0.0",
"@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0", "@typescript-eslint/parser": "^6.0.0",
"@vue/eslint-config-typescript": "^12.0.0", "@vue/eslint-config-typescript": "^12.0.0",
@ -87,13 +87,15 @@
"eslint-config-prettier": "^9.0.0", "eslint-config-prettier": "^9.0.0",
"eslint-plugin-jsonc": "^2.2.1", "eslint-plugin-jsonc": "^2.2.1",
"eslint-plugin-vue": "^9.0.0", "eslint-plugin-vue": "^9.0.0",
"postcss": "^8.4.31",
"postcss-nesting": "^12.0.1",
"prettier": "^3.0.0", "prettier": "^3.0.0",
"sass": "~1.32", "sass": "~1.32",
"start-server-and-test": "^1.14.0", "start-server-and-test": "^2.0.0",
"typescript": "^4.5.5", "typescript": "^4.5.5",
"unplugin-vue-components": "^0.22.12", "unplugin-vue-components": "^0.22.12",
"vite": "^3.2.7", "vite": "^4.4.9",
"vite-plugin-checker": "^0.5.0", "vite-plugin-checker": "^0.6.0",
"vite-plugin-package-version": "^1.0.2", "vite-plugin-package-version": "^1.0.2",
"vite-plugin-pwa": "^0.16.4", "vite-plugin-pwa": "^0.16.4",
"vite-plugin-vue2": "^2.0.1", "vite-plugin-vue2": "^2.0.1",

View File

@ -40,6 +40,7 @@ import TheUploadSnackbar from '@/components/TheUploadSnackbar.vue'
import TheManualProbeDialog from '@/components/dialogs/TheManualProbeDialog.vue' import TheManualProbeDialog from '@/components/dialogs/TheManualProbeDialog.vue'
import TheBedScrewsDialog from '@/components/dialogs/TheBedScrewsDialog.vue' import TheBedScrewsDialog from '@/components/dialogs/TheBedScrewsDialog.vue'
import TheScrewsTiltAdjustDialog from '@/components/dialogs/TheScrewsTiltAdjustDialog.vue' import TheScrewsTiltAdjustDialog from '@/components/dialogs/TheScrewsTiltAdjustDialog.vue'
import { setAndLoadLocale } from './plugins/i18n'
Component.registerHooks(['metaInfo']) Component.registerHooks(['metaInfo'])
@ -162,8 +163,8 @@ export default class App extends Mixins(BaseMixin) {
} }
@Watch('language') @Watch('language')
languageChanged(newVal: string): void { async languageChanged(newVal: string): Promise<void> {
this.$i18n.locale = newVal await setAndLoadLocale(newVal)
} }
@Watch('customStylesheet') @Watch('customStylesheet')
@ -310,10 +311,10 @@ export default class App extends Mixins(BaseMixin) {
<style> <style>
@import './assets/styles/fonts.css'; @import './assets/styles/fonts.css';
@import './assets/styles/toastr.css'; @import './assets/styles/toastr.css';
@import './assets/styles/page.scss'; @import './assets/styles/page.css';
@import './assets/styles/sidebar.scss'; @import './assets/styles/sidebar.css';
@import './assets/styles/utils.scss'; @import './assets/styles/utils.css';
@import './assets/styles/updateManager.scss'; @import './assets/styles/updateManager.css';
:root { :root {
--app-height: 100%; --app-height: 100%;

View File

@ -1,12 +1,3 @@
@mixin no-select {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.user-select-none { .user-select-none {
-webkit-touch-callout: none; -webkit-touch-callout: none;
-webkit-user-select: none; -webkit-user-select: none;

View File

@ -124,7 +124,7 @@ export default class CommandHelpModal extends Mixins(BaseMixin) {
} }
</script> </script>
<style lang="scss" scoped> <style scoped>
.command-help-content { .command-help-content {
overflow-x: hidden; overflow-x: hidden;

View File

@ -341,7 +341,7 @@ export default class TheEditor extends Mixins(BaseMixin) {
} }
} }
</script> </script>
<style lang="scss" scoped> <style scoped>
::v-deep .ͼ1 .cm-panel.cm-search *:focus:not(.focus-visible) { ::v-deep .ͼ1 .cm-panel.cm-search *:focus:not(.focus-visible) {
outline: none; outline: none;
} }

View File

@ -1,4 +1,4 @@
<style scoped lang="scss"></style> <style scoped></style>
<template> <template>
<div :class="'consoleTable ' + (isMini ? 'mini' : '')"> <div :class="'consoleTable ' + (isMini ? 'mini' : '')">

View File

@ -1,4 +1,4 @@
<style scoped lang="scss"> <style scoped>
.consoleTableRow { .consoleTableRow {
font-family: 'Roboto Mono', monospace; font-family: 'Roboto Mono', monospace;
font-size: 0.95em; font-size: 0.95em;

View File

@ -173,4 +173,4 @@ export default class TheBedScrewsDialog extends Mixins(BaseMixin, ControlMixin)
} }
</script> </script>
<style lang="scss" scoped></style> <style scoped></style>

View File

@ -181,7 +181,7 @@ export default class TheManualProbeDialog extends Mixins(BaseMixin) {
} }
</script> </script>
<style lang="scss" scoped> <style scoped>
.v-btn-toggle { .v-btn-toggle {
width: 100%; width: 100%;
} }

View File

@ -274,7 +274,7 @@ export default class ExtruderControlPanel extends Mixins(BaseMixin, ExtruderMixi
} }
</script> </script>
<style lang="scss" scoped> <style scoped>
._btn-group { ._btn-group {
border-radius: 4px; border-radius: 4px;
display: inline-flex; display: inline-flex;

View File

@ -49,14 +49,13 @@ export default class ExtruderControlPanel extends Mixins(BaseMixin, ControlMixin
} }
</script> </script>
<style lang="scss" scoped> <style scoped>
._btn-group { ._btn-group {
border-radius: 4px; border-radius: 4px;
display: inline-flex; display: inline-flex;
flex-wrap: nowrap; flex-wrap: nowrap;
max-width: 100%; max-width: 100%;
min-width: 100%; min-width: 100%;
width: 100%;
.v-btn { .v-btn {
border-radius: 0; border-radius: 0;

View File

@ -116,7 +116,7 @@ export default class GitCommitsList extends Mixins(BaseMixin) {
} }
</script> </script>
<style lang="scss" scoped> <style scoped>
.groupedCommits { .groupedCommits {
padding-top: 0; padding-top: 0;
} }

View File

@ -99,7 +99,7 @@ export default class GitCommitsListDayCommit extends Mixins(BaseMixin) {
} }
</script> </script>
<style lang="scss" scoped> <style scoped>
li.commit { li.commit {
border-color: rgb(48, 54, 61); border-color: rgb(48, 54, 61);
border-style: solid; border-style: solid;

View File

@ -1,4 +1,4 @@
<style lang="scss" scoped></style> <style scoped></style>
<template> <template>
<panel <panel

View File

@ -1,4 +1,4 @@
<style lang="scss" scoped></style> <style scoped></style>
<template> <template>
<div v-if="['printing', 'paused'].includes(printer_state) && printing_objects.length"> <div v-if="['printing', 'paused'].includes(printer_state) && printing_objects.length">

View File

@ -1,4 +1,4 @@
<style lang="scss" scoped></style> <style scoped></style>
<template> <template>
<div> <div>

View File

@ -1,4 +1,4 @@
<style lang="scss" scoped></style> <style scoped></style>
<template> <template>
<div> <div>

View File

@ -1,6 +1,5 @@
<style lang="scss" scoped> <style scoped>
svg { svg {
//background: rgba(200, 200, 200);
border: 2px solid #888; border: 2px solid #888;
} }

View File

@ -156,7 +156,7 @@ export default class StatusPanelJobqueue extends Mixins(BaseMixin) {
} }
</script> </script>
<style lang="scss" scoped> <style scoped>
.filesJobqueue { .filesJobqueue {
position: relative; position: relative;
} }

View File

@ -275,7 +275,7 @@ export default class StatusPanelJobqueueEntry extends Mixins(BaseMixin) {
} }
</script> </script>
<style lang="scss" scoped> <style scoped>
.filesJobqueue { .filesJobqueue {
position: relative; position: relative;
} }

View File

@ -1,4 +1,4 @@
<style lang="scss" scoped></style> <style scoped></style>
<template> <template>
<div> <div>

View File

@ -1,4 +1,4 @@
<style lang="scss" scoped></style> <style scoped></style>
<template> <template>
<div> <div>

View File

@ -1,4 +1,4 @@
<style lang="scss" scoped></style> <style scoped></style>
<template> <template>
<v-card-text class="pa-0"> <v-card-text class="pa-0">

View File

@ -1,4 +1,4 @@
<style lang="scss" scoped></style> <style scoped></style>
<template> <template>
<v-card-text class="pa-0"> <v-card-text class="pa-0">

View File

@ -223,7 +223,7 @@ export default class StatusPanelPrintstatusThumbnail extends Mixins(BaseMixin) {
} }
</script> </script>
<style lang="scss" scoped> <style scoped>
.statusPanel-big-thumbnail { .statusPanel-big-thumbnail {
transition: height 0.25s ease-out; transition: height 0.25s ease-out;
} }

View File

@ -397,7 +397,7 @@ export default class StatusPanel extends Mixins(BaseMixin) {
} }
</script> </script>
<style lang="scss" scoped> <style scoped>
._border-radius { ._border-radius {
border-bottom-left-radius: inherit; border-bottom-left-radius: inherit;
border-bottom-right-radius: inherit; border-bottom-right-radius: inherit;

View File

@ -155,7 +155,7 @@ export default class TemperaturePanelList extends Mixins(BaseMixin) {
} }
</script> </script>
<style lang="scss" scoped> <style scoped>
.temperature-panel-table th, .temperature-panel-table th,
.temperature-panel-table ::v-deep td { .temperature-panel-table ::v-deep td {
padding-top: 5px !important; padding-top: 5px !important;

View File

@ -273,7 +273,7 @@ export default class TemperaturePanelListItem extends Mixins(BaseMixin) {
} }
</script> </script>
<style lang="scss" scoped> <style scoped>
::v-deep .v-icon._no-focus-style:focus::after { ::v-deep .v-icon._no-focus-style:focus::after {
opacity: 0 !important; opacity: 0 !important;
} }

View File

@ -99,7 +99,7 @@ export default class TemperaturePanelListItemNevermore extends Mixins(BaseMixin)
} }
</script> </script>
<style lang="scss" scoped> <style scoped>
::v-deep .v-icon._no-focus-style:focus::after { ::v-deep .v-icon._no-focus-style:focus::after {
opacity: 0 !important; opacity: 0 !important;
} }

View File

@ -107,7 +107,7 @@ export default class TemperaturePanelPresets extends Mixins(BaseMixin) {
} }
</script> </script>
<style lang="scss" scoped> <style scoped>
._preset-title { ._preset-title {
font-size: 0.8125rem; font-size: 0.8125rem;
font-weight: 500; font-weight: 500;

View File

@ -1,4 +1,4 @@
<style lang="scss" scoped> <style scoped>
.btnHomeAxis { .btnHomeAxis {
width: 36px; width: 36px;
min-width: 36px !important; min-width: 36px !important;

View File

@ -706,7 +706,7 @@ export default class CircleControl extends Mixins(BaseMixin, ControlMixin) {
} }
</script> </script>
<style lang="scss" scoped> <style scoped>
svg { svg {
max-height: 350px; max-height: 350px;
min-height: 275px; min-height: 275px;

View File

@ -1,4 +1,4 @@
<style lang="scss" scoped> <style scoped>
.btnMinWidthAuto { .btnMinWidthAuto {
min-width: auto !important; min-width: auto !important;
} }

View File

@ -267,7 +267,7 @@ export default class ZoffsetControl extends Mixins(BaseMixin) {
} }
</script> </script>
<style lang="scss" scoped> <style scoped>
.v-btn-toggle { .v-btn-toggle {
width: 100%; width: 100%;
} }

View File

@ -82,6 +82,25 @@ export default class SettingsGeneralTab extends Mixins(BaseMixin, SettingsGenera
mdiHelpCircle = mdiHelpCircle mdiHelpCircle = mdiHelpCircle
mdiCloseThick = mdiCloseThick mdiCloseThick = mdiCloseThick
availableLanguages: { text: string; value: string }[] = []
async created() {
const locales = import.meta.glob<string>('../../locales/*.json', { import: 'title' })
const languages: { text: string; value: string }[] = []
for (const file in locales) {
const langKey = file.slice(file.lastIndexOf('.') - 2, file.lastIndexOf('.'))
const title = await locales[file]()
languages.push({
text: title,
value: langKey,
})
}
this.availableLanguages = languages
}
get printerName() { get printerName() {
return this.$store.state.gui.general.printername return this.$store.state.gui.general.printername
} }
@ -98,22 +117,6 @@ export default class SettingsGeneralTab extends Mixins(BaseMixin, SettingsGenera
this.$store.dispatch('gui/saveSetting', { name: 'general.language', value: newVal }) this.$store.dispatch('gui/saveSetting', { name: 'general.language', value: newVal })
} }
get availableLanguages() {
const locales = import.meta.glob('../../locales/*.json', { eager: true }) as { [key: string]: any }
const languages: { text: string; value: string }[] = []
Object.keys(locales).map((file: string) => {
const langKey = file.slice(file.lastIndexOf('.') - 2, file.lastIndexOf('.'))
languages.push({
text: locales[file].title,
value: langKey,
})
})
return languages
}
get dateFormat() { get dateFormat() {
return this.$store.state.gui.general.dateFormat return this.$store.state.gui.general.dateFormat
} }

View File

@ -78,4 +78,4 @@ export default class SettingsMiscellaneousTab extends Mixins(BaseMixin) {
} }
</script> </script>
<style lang="scss" scoped></style> <style scoped></style>

View File

@ -233,4 +233,4 @@ export default class SettingsMiscellaneousTabLightGroups extends Mixins(BaseMixi
} }
</script> </script>
<style lang="scss" scoped></style> <style scoped></style>

View File

@ -464,4 +464,4 @@ export default class SettingsMiscellaneousTabLightPresets extends Mixins(BaseMix
} }
</script> </script>
<style lang="scss" scoped></style> <style scoped></style>

View File

@ -322,7 +322,7 @@ export default class WebcamForm extends Mixins(BaseMixin, WebcamMixin) {
} }
</script> </script>
<style lang="scss" scoped> <style scoped>
::v-deep ._transition svg { ::v-deep ._transition svg {
transition: transform 500ms; transition: transform 500ms;
} }

View File

@ -70,4 +70,4 @@ export default class WebcamListEntry extends Mixins(BaseMixin, WebcamMixin) {
} }
</script> </script>
<style lang="scss" scoped></style> <style scoped></style>

View File

@ -83,7 +83,7 @@ export default class Panel extends Mixins(BaseMixin) {
} }
</script> </script>
<style lang="scss" scoped> <style scoped>
.expanded header.v-toolbar { .expanded header.v-toolbar {
border-bottom-left-radius: 4px; border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px; border-bottom-right-radius: 4px;
@ -107,7 +107,7 @@ export default class Panel extends Mixins(BaseMixin) {
} }
</style> </style>
<style lang="scss"> <style>
.v-card.panel .v-toolbar__content { .v-card.panel .v-toolbar__content {
padding-right: 0; padding-right: 0;
} }

View File

@ -1,4 +1,4 @@
<style lang="scss" scoped> <style scoped>
.btn-collapsible > * { .btn-collapsible > * {
will-change: transform; will-change: transform;
transition: transform 500ms; transition: transform 500ms;

View File

@ -1,31 +1,31 @@
<template> <template>
<div> <div>
<template v-if="service === 'mjpegstreamer'"> <template v-if="service === 'mjpegstreamer'">
<mjpegstreamer :cam-settings="webcam" :show-fps="showFps" :printer-url="printerUrl" /> <mjpegstreamer-async :cam-settings="webcam" :show-fps="showFps" :printer-url="printerUrl" />
</template> </template>
<template v-else-if="service === 'mjpegstreamer-adaptive'"> <template v-else-if="service === 'mjpegstreamer-adaptive'">
<mjpegstreamer-adaptive :cam-settings="webcam" :show-fps="showFps" :printer-url="printerUrl" /> <mjpegstreamer-adaptive-async :cam-settings="webcam" :show-fps="showFps" :printer-url="printerUrl" />
</template> </template>
<template v-else-if="service === 'uv4l-mjpeg'"> <template v-else-if="service === 'uv4l-mjpeg'">
<uv4l-mjpeg :cam-settings="webcam" :printer-url="printerUrl" /> <uv4l-mjpeg-async :cam-settings="webcam" :printer-url="printerUrl" />
</template> </template>
<template v-else-if="service === 'ipstream'"> <template v-else-if="service === 'ipstream'">
<ipstreamer :cam-settings="webcam" :printer-url="printerUrl" /> <ipstreamer-async :cam-settings="webcam" :printer-url="printerUrl" />
</template> </template>
<template v-else-if="service === 'hlsstream'"> <template v-else-if="service === 'hlsstream'">
<hlsstreamer :cam-settings="webcam" :printer-url="printerUrl" /> <hlsstreamer-async :cam-settings="webcam" :printer-url="printerUrl" />
</template> </template>
<template v-else-if="service === 'jmuxer-stream'"> <template v-else-if="service === 'jmuxer-stream'">
<j-muxer-stream :cam-settings="webcam" :printer-url="printerUrl" /> <j-muxer-stream-async :cam-settings="webcam" :printer-url="printerUrl" />
</template> </template>
<template v-else-if="service === 'webrtc-camerastreamer'"> <template v-else-if="service === 'webrtc-camerastreamer'">
<webrtc-camera-streamer :cam-settings="webcam" :printer-url="printerUrl" /> <webrtc-camera-streamer-async :cam-settings="webcam" :printer-url="printerUrl" />
</template> </template>
<template v-else-if="service === 'webrtc-janus'"> <template v-else-if="service === 'webrtc-janus'">
<janus-streamer :cam-settings="webcam" :printer-url="printerUrl" /> <janus-streamer-async :cam-settings="webcam" :printer-url="printerUrl" />
</template> </template>
<template v-else-if="service === 'webrtc-mediamtx'"> <template v-else-if="service === 'webrtc-mediamtx'">
<webrtc-media-m-t-x :cam-settings="webcam" :printer-url="printerUrl" /> <webrtc-media-m-t-x-async :cam-settings="webcam" :printer-url="printerUrl" />
</template> </template>
<template v-else> <template v-else>
<p class="text-center py-3 font-italic">{{ $t('Panels.WebcamPanel.UnknownWebcamService') }}</p> <p class="text-center py-3 font-italic">{{ $t('Panels.WebcamPanel.UnknownWebcamService') }}</p>
@ -38,18 +38,19 @@ import Component from 'vue-class-component'
import { Mixins, Prop } from 'vue-property-decorator' import { Mixins, Prop } from 'vue-property-decorator'
import BaseMixin from '@/components/mixins/base' import BaseMixin from '@/components/mixins/base'
import { GuiWebcamStateWebcam } from '@/store/gui/webcams/types' import { GuiWebcamStateWebcam } from '@/store/gui/webcams/types'
import { DynamicCamLoader } from '@/components/webcams/streamers/DynamicCamLoader'
@Component({ @Component({
components: { components: {
Hlsstreamer: () => import('@/components/webcams/Hlsstreamer.vue'), HlsstreamerAsync: DynamicCamLoader('Hlsstreamer'),
Ipstreamer: () => import('@/components/webcams/Ipstreamer.vue'), IpstreamerAsync: DynamicCamLoader('Ipstreamer'),
JanusStreamer: () => import('@/components/webcams/JanusStreamer.vue'), JanusStreamerAsync: DynamicCamLoader('JanusStreamer'),
JMuxerStream: () => import('@/components/webcams/JMuxerStream.vue'), JMuxerStreamAsync: DynamicCamLoader('JMuxerStream'),
Mjpegstreamer: () => import('@/components/webcams/Mjpegstreamer.vue'), MjpegstreamerAsync: DynamicCamLoader('Mjpegstreamer'),
MjpegstreamerAdaptive: () => import('@/components/webcams/MjpegstreamerAdaptive.vue'), MjpegstreamerAdaptiveAsync: DynamicCamLoader('MjpegstreamerAdaptive'),
Uv4lMjpeg: () => import('@/components/webcams/Uv4lMjpeg.vue'), Uv4lMjpegAsync: DynamicCamLoader('Uv4lMjpeg'),
WebrtcCameraStreamer: () => import('@/components/webcams/WebrtcCameraStreamer.vue'), WebrtcCameraStreamerAsync: DynamicCamLoader('WebrtcCameraStreamer'),
WebrtcMediaMTX: () => import('@/components/webcams/WebrtcMediaMTX.vue'), WebrtcMediaMTXAsync: DynamicCamLoader('WebrtcMediaMTX'),
}, },
}) })
export default class WebcamWrapperItem extends Mixins(BaseMixin) { export default class WebcamWrapperItem extends Mixins(BaseMixin) {

View File

@ -0,0 +1,39 @@
import Vue from 'vue'
type StreamerTypes =
| 'Hlsstreamer'
| 'Ipstreamer'
| 'JanusStreamer'
| 'JMuxerStream'
| 'Mjpegstreamer'
| 'MjpegstreamerAdaptive'
| 'Uv4lMjpeg'
| 'WebrtcCameraStreamer'
| 'WebrtcMediaMTX'
function getDynamicCamImport(componentName: StreamerTypes) {
// split each webcam streamer into its own chunk
switch (componentName) {
case 'Hlsstreamer':
return () => import('@/components/webcams/streamers/Hlsstreamer.vue')
case 'Ipstreamer':
return () => import('@/components/webcams/streamers/Ipstreamer.vue')
case 'JanusStreamer':
return () => import('@/components/webcams/streamers/JanusStreamer.vue')
case 'JMuxerStream':
return () => import('@/components/webcams/streamers/JMuxerStream.vue')
case 'Mjpegstreamer':
return () => import('@/components/webcams/streamers/Mjpegstreamer.vue')
case 'MjpegstreamerAdaptive':
return () => import('@/components/webcams/streamers/MjpegstreamerAdaptive.vue')
case 'Uv4lMjpeg':
return () => import('@/components/webcams/streamers/Uv4lMjpeg.vue')
case 'WebrtcCameraStreamer':
return () => import('@/components/webcams/streamers/WebrtcCameraStreamer.vue')
case 'WebrtcMediaMTX':
return () => import('@/components/webcams/streamers/WebrtcMediaMTX.vue')
}
}
export const DynamicCamLoader = (componentName: StreamerTypes) =>
Vue.component(componentName, getDynamicCamImport(componentName))

View File

@ -1,41 +1,53 @@
import 'core-js/stable' // polyfills for older browsers
import 'regenerator-runtime' // async polyfill used by the gcodeviewer import 'regenerator-runtime' // async polyfill used by the gcodeviewer
import 'resize-observer-polyfill' // polyfill needed by the responsive class detection import 'resize-observer-polyfill' // polyfill needed by the responsive class detection
import Vue from 'vue' import Vue from 'vue'
import App from '@/App.vue' import App from '@/App.vue'
import vuetify from '@/plugins/vuetify' import vuetify from '@/plugins/vuetify'
import i18n from '@/plugins/i18n' import i18n, { setAndLoadLocale } from '@/plugins/i18n'
import store from '@/store' import store from '@/store'
import router from '@/plugins/router' import router from '@/plugins/router'
import { WebSocketPlugin } from '@/plugins/webSocketClient' import { WebSocketPlugin } from '@/plugins/webSocketClient'
Vue.config.productionTip = false
// vue-observe-visibility // vue-observe-visibility
import { ObserveVisibility } from 'vue-observe-visibility' import { ObserveVisibility } from 'vue-observe-visibility'
Vue.directive('observe-visibility', ObserveVisibility)
//vue-meta //vue-meta
import VueMeta from 'vue-meta' import VueMeta from 'vue-meta'
Vue.use(VueMeta)
//vue-load-image //vue-load-image
import VueLoadImage from 'vue-load-image' import VueLoadImage from 'vue-load-image'
Vue.component('VueLoadImage', VueLoadImage)
//vue-toast-notifications //vue-toast-notifications
import VueToast from 'vue-toast-notification' import VueToast from 'vue-toast-notification'
import 'vue-toast-notification/dist/theme-sugar.css' import 'vue-toast-notification/dist/theme-sugar.css'
//overlayerscrollbars-vue
import { OverlayScrollbarsPlugin } from 'overlayscrollbars-vue'
import 'overlayscrollbars/css/OverlayScrollbars.css'
// Directives
import './directives/longpress'
import './directives/responsive-class'
// Echarts
import ECharts from 'vue-echarts'
import { use } from 'echarts/core'
// import ECharts modules manually to reduce bundle size
import { SVGRenderer } from 'echarts/renderers'
import { BarChart, LineChart, PieChart } from 'echarts/charts'
import { DatasetComponent, GridComponent, LegendComponent, TooltipComponent } from 'echarts/components'
// vue-resize
import 'vue-resize/dist/vue-resize.css'
// @ts-ignore
import VueResize from 'vue-resize'
Vue.config.productionTip = false
Vue.directive('observe-visibility', ObserveVisibility)
Vue.use(VueMeta)
Vue.component('VueLoadImage', VueLoadImage)
Vue.use(VueToast, { Vue.use(VueToast, {
duration: 3000, duration: 3000,
}) })
//overlayerscrollbars-vue
import { OverlayScrollbarsPlugin } from 'overlayscrollbars-vue'
import 'overlayscrollbars/css/OverlayScrollbars.css'
const isSafari = navigator.userAgent.includes('Safari') && navigator.userAgent.search('Chrome') === -1 const isSafari = navigator.userAgent.includes('Safari') && navigator.userAgent.search('Chrome') === -1
const isTouch = 'ontouchstart' in window || (navigator.maxTouchPoints > 0 && navigator.maxTouchPoints !== 256) const isTouch = 'ontouchstart' in window || (navigator.maxTouchPoints > 0 && navigator.maxTouchPoints !== 256)
Vue.use(OverlayScrollbarsPlugin, { Vue.use(OverlayScrollbarsPlugin, {
@ -46,41 +58,27 @@ Vue.use(OverlayScrollbarsPlugin, {
}, },
}) })
// Directives
import './directives/longpress'
import './directives/responsive-class'
// Echarts
import ECharts from 'vue-echarts'
import { use } from 'echarts/core'
// import ECharts modules manually to reduce bundle size
import { SVGRenderer } from 'echarts/renderers'
import { LineChart, BarChart, PieChart } from 'echarts/charts'
import { GridComponent, LegendComponent, TooltipComponent, DatasetComponent } from 'echarts/components'
use([SVGRenderer, LineChart, BarChart, LegendComponent, PieChart, DatasetComponent, GridComponent, TooltipComponent]) use([SVGRenderer, LineChart, BarChart, LegendComponent, PieChart, DatasetComponent, GridComponent, TooltipComponent])
Vue.component('EChart', ECharts) Vue.component('EChart', ECharts)
// vue-resize
import 'vue-resize/dist/vue-resize.css'
// @ts-ignore
import VueResize from 'vue-resize'
Vue.use(VueResize) Vue.use(VueResize)
const initLoad = async () => { const initLoad = async () => {
//load config.json try {
await fetch('/config.json') //load config.json
.then((res) => res.json()) const res = await fetch('/config.json')
.then(async (file) => { const file = (await res.json()) as Record<string, unknown>
window.console.debug('Loaded config.json')
await store.dispatch('importConfigJson', file) window.console.debug('Loaded config.json')
if ('defaultLocale' in file) i18n.locale = file.defaultLocale
}) await store.dispatch('importConfigJson', file)
.catch(() => { if ('defaultLocale' in file) {
window.console.error('config.json not found or cannot be decoded!') await setAndLoadLocale(file.defaultLocale as string)
}) }
} catch (e) {
window.console.error('Failed to load config.json')
window.console.error(e)
}
const url = store.getters['socket/getWebsocketUrl'] const url = store.getters['socket/getWebsocketUrl']
Vue.use(WebSocketPlugin, { url, store }) Vue.use(WebSocketPlugin, { url, store })

View File

@ -2,23 +2,21 @@ import Vue from 'vue'
import VueI18n from 'vue-i18n' import VueI18n from 'vue-i18n'
Vue.use(VueI18n) Vue.use(VueI18n)
function loadLocaleMessages() { import defaultLocale from '../locales/en.json'
const locales = import.meta.globEager('../locales/*.json')
const messages: any = {}
for (const file in locales) { const locale = (import.meta.env.VUE_APP_I18N_LOCALE as string) || 'en'
const langKey = file.slice(file.lastIndexOf('.') - 2, file.lastIndexOf('.'))
if (langKey && langKey.length > 1) { const i18n = new VueI18n({
messages[langKey] = JSON.parse(JSON.stringify(locales[file])) locale,
}
}
return messages
}
export default new VueI18n({
locale: (import.meta.env.VUE_APP_I18N_LOCALE as string) || 'en',
fallbackLocale: (import.meta.env.VUE_APP_I18N_FALLBACK_LOCALE as string) || 'en', fallbackLocale: (import.meta.env.VUE_APP_I18N_FALLBACK_LOCALE as string) || 'en',
messages: loadLocaleMessages(), messages: { en: defaultLocale },
}) })
export default i18n
export async function setAndLoadLocale(lang: string) {
const locales = await import(`../locales/${lang}.json`)
i18n.setLocaleMessage(lang, locales)
i18n.locale = lang
return locales
}

View File

@ -76,17 +76,35 @@ export default defineConfig({
resolvers: [VuetifyResolver()], resolvers: [VuetifyResolver()],
}), }),
], ],
css: { css: {
preprocessorOptions: { postcss: {
css: { charset: false }, plugins: [require('postcss-nesting')()],
scss: {
quietDeps: true,
},
}, },
}, },
build: { build: {
target: 'safari12', target: 'safari12',
rollupOptions: {
output: {
manualChunks: (id: string) => {
if (id.includes('node_modules')) {
// split codemirror into its own chunk
if (id.includes('/codemirror/') || id.includes('/@codemirror/')) {
return 'codemirror'
}
// split these libs into their own chunks
const chunkedLibs = ['vuetify', 'echarts', 'overlayscrollbars']
for (const lib of chunkedLibs) {
if (id.includes(`/node_modules/${lib}/`)) {
return lib.replace('.js', '')
}
}
}
},
},
},
}, },
envPrefix: 'VUE_', envPrefix: 'VUE_',