2
0
mirror of https://github.com/ad1217/PrinterStatus synced 2024-11-21 15:03:48 -05:00

Switch to Vite bundler, upgrade to Vue3, and split server into subfolder

This commit is contained in:
Adam Goldsmith 2021-10-11 21:28:12 -04:00
parent 20b4e5ac8b
commit 0b2919abf5
16 changed files with 5607 additions and 14937 deletions

5
.gitignore vendored
View File

@ -1,5 +1,6 @@
/.cache/ /.cache/
/dist/ /dist/
/node_modules/ node_modules/
/src/*.js /src/*.js
/config.yaml /server/config.yaml
/.log/

4
index.html Normal file
View File

@ -0,0 +1,4 @@
<body>
<div id="app"></div>
<script type="module" src="/src/index.ts"></script>
</body>

16978
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,36 +1,20 @@
{ {
"name": "printer_status",
"version": "0.0.0",
"devDependencies": { "devDependencies": {
"@babel/plugin-proposal-class-properties": "^7.10.4", "@vitejs/plugin-vue": "^1.9.3",
"@types/express": "^4.17.8", "sass": "^1.42.1",
"@types/express-ws": "^3.0.0", "typescript": "^4.4.3",
"@types/http-proxy": "^1.17.4", "vite": "^2.6.4",
"@types/js-yaml": "^3.12.5", "vue-tsc": "^0.3.0"
"@types/node": "^14.6.4",
"@types/node-fetch": "^2.5.7",
"@types/parcel-bundler": "^1.12.1",
"@types/ws": "^7.2.6",
"@vue/component-compiler-utils": "^3.2.0",
"sass": "^1.26.10",
"typescript": "^4.0.2",
"vue-template-compiler": "^2.6.12"
}, },
"dependencies": { "dependencies": {
"express": "^4.17.1",
"express-ws": "^4.0.0",
"http-proxy": "^1.18.1",
"js-yaml": "^4.1.0",
"node-fetch": "^2.6.1",
"node-gyp": "^7.1.0",
"parcel-bundler": "^1.12.4",
"pretty-ms": "^7.0.1", "pretty-ms": "^7.0.1",
"ts-node": "^9.0.0", "vue": "^3.2.0"
"vue": "^2.6.12",
"vue-class-component": "^7.2.5",
"vue-hot-reload-api": "^2.3.3",
"vue-property-decorator": "^9.0.0",
"ws": "^7.3.1"
}, },
"scripts": { "scripts": {
"start": "ts-node src/server.ts" "dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"serve": "vite preview"
} }
} }

3373
server/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

26
server/package.json Normal file
View File

@ -0,0 +1,26 @@
{
"devDependencies": {
"@types/express": "^4.17.8",
"@types/express-ws": "^3.0.0",
"@types/http-proxy": "^1.17.4",
"@types/js-yaml": "^4.0.3",
"@types/node": "^16.10.3",
"@types/node-fetch": "^2.5.12",
"@types/ws": "^8.2.0",
"typescript": "^4.4.3"
},
"dependencies": {
"express": "^4.17.1",
"express-ws": "^5.0.2",
"http-proxy": "^1.18.1",
"js-yaml": "^4.1.0",
"node-fetch": "^2.6.5",
"node-gyp": "^8.2.0",
"pretty-ms": "^7.0.1",
"ts-node": "^10.3.0",
"ws": "^8.2.3"
},
"scripts": {
"start": "ts-node ./server.ts"
}
}

View File

@ -1,5 +1,4 @@
import * as fs from 'fs'; import * as fs from 'fs';
import * as url from 'url';
import * as path from 'path'; import * as path from 'path';
import * as express from 'express'; import * as express from 'express';
@ -7,11 +6,10 @@ import fetch from 'node-fetch';
import * as httpProxy from 'http-proxy'; import * as httpProxy from 'http-proxy';
import * as WebSocket from 'ws'; import * as WebSocket from 'ws';
import * as yaml from 'js-yaml'; import * as yaml from 'js-yaml';
import * as Bundler from 'parcel-bundler';
import * as expressWs from 'express-ws'; import * as expressWs from 'express-ws';
import * as messages from './messages'; import * as messages from '../types/messages';
import * as octoprint from './octoprint'; import * as octoprint from '../types/octoprint';
const PORT = process.env.PORT || 1234; const PORT = process.env.PORT || 1234;
@ -58,9 +56,6 @@ app.get('/webcam/:printer', (req, res) => {
} else res.status(404).send('Not Found: Printer not known or has no webcam.'); } else res.status(404).send('Not Found: Printer not known or has no webcam.');
}); });
let bundler = new Bundler(path.join(__dirname, 'index.html'));
app.use(bundler.middleware());
app.listen(PORT); app.listen(PORT);
class PrinterStatus { class PrinterStatus {

9
server/tsconfig.json Normal file
View File

@ -0,0 +1,9 @@
{
"compilerOptions": {
"target": "es5",
"strict": true,
"module": "commonjs",
"moduleResolution": "node",
"experimentalDecorators": true
}
}

View File

@ -1,61 +1,59 @@
<template> <template>
<div> <div>
<div class="loading" v-show="Object.keys(printers).length === 0"> <div v-if="!hasPrinters">
<div class="loading-spinner"></div> <div class="loading-spinner"></div>
</div> </div>
<PrinterCard <PrinterCard
v-else
v-for="(status, name) in printers" v-for="(status, name) in printers"
:key="name" :key="name"
:name="name" :name="name as string"
:status="status" :status="status"
> >
</PrinterCard> </PrinterCard>
</div> </div>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { Vue, Component, Prop } from 'vue-property-decorator'; import { computed, ref, Ref } from 'vue';
import * as messages from './messages'; import * as messages from '../types/messages';
import * as octoprint from './octoprint'; import * as octoprint from '../types/octoprint';
import PrinterCard from './PrinterCard.vue'; import PrinterCard from './PrinterCard.vue';
@Component({ components: { PrinterCard } }) const printers: Ref<{
export default class App extends Vue {
websocket!: WebSocket;
printers: {
[key: string]: octoprint.CurrentOrHistoryPayload | null; [key: string]: octoprint.CurrentOrHistoryPayload | null;
} = {}; }> = ref({});
const hasPrinters = computed(() => Object.keys(printers.value).length > 0);
mounted() { let websocket!: WebSocket;
this.connectWebsocket();
}
connectWebsocket() { function connectWebsocket() {
let loc = window.location; let loc = window.location;
const ws_uri: string = const ws_uri: string =
(loc.protocol === 'https:' ? 'wss://' : 'ws://') + loc.host + '/ws'; (loc.protocol === 'https:' ? 'wss://' : 'ws://') + loc.host + '/ws';
this.websocket = new WebSocket(ws_uri); websocket = new WebSocket(ws_uri);
this.websocket.addEventListener('message', (ev: MessageEvent) => { websocket.addEventListener('message', (ev: MessageEvent) => {
const event: messages.ExtendedMessage = JSON.parse(ev.data as string); const event: messages.ExtendedMessage = JSON.parse(ev.data as string);
console.log(event); console.log(event);
if ('init' in event) { if ('init' in event) {
this.$set(this.printers, event.printer, null); printers.value[event.printer] = null;
} else if ('current' in event) { } else if ('current' in event) {
this.$set(this.printers, event.printer, event.current); printers.value[event.printer] = event.current!;
} else if ('history' in event) { } else if ('history' in event) {
this.$set(this.printers, event.printer, event.history); printers.value[event.printer] = event.history!;
} else if ('remote_ws_status' in event) { } else if ('remote_ws_status' in event) {
} }
}); });
this.websocket.addEventListener('close', () => { websocket.addEventListener('close', () => {
console.log('Lost connection to server reconnecting in 5 sec'); console.log('Lost connection to server reconnecting in 5 sec');
window.setTimeout(this.connectWebsocket, 5000); window.setTimeout(connectWebsocket, 5000);
}); });
}
} }
connectWebsocket();
</script> </script>
<style> <style>

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="card"> <div class="card">
<div class="card-header">{{ name || 'Unknown' }}</div> <div class="card-header">{{ name || 'Unknown' }}</div>
<img v-if="name" class="webcam" :src="'/webcam/' + name" /> <img class="webcam" :src="'/webcam/' + name" />
<div v-if="status"> <div v-if="status">
<div>{{ status.state.text }}</div> <div>{{ status.state.text }}</div>
<div>Job File Name: {{ status.job.file.name || 'None' }}</div> <div>Job File Name: {{ status.job.file.name || 'None' }}</div>
@ -21,20 +21,18 @@
</div> </div>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { Vue, Component, Prop } from 'vue-property-decorator';
import prettyMilliseconds from 'pretty-ms'; import prettyMilliseconds from 'pretty-ms';
import * as octoprint from './octoprint'; import * as octoprint from '../types/octoprint';
@Component defineProps<{
export default class PrinterCard extends Vue { name: string;
@Prop(String) readonly name!: string; status: octoprint.CurrentOrHistoryPayload | null;
@Prop(Object) readonly status?: octoprint.CurrentOrHistoryPayload; }>();
formatDuration(seconds: number): string { function formatDuration(seconds: number): string {
return prettyMilliseconds(seconds * 1000); return prettyMilliseconds(seconds * 1000);
}
} }
</script> </script>

View File

@ -1,4 +0,0 @@
<body>
<div id="app"></div>
<script src="index.ts"></script>
</body>

View File

@ -1,7 +1,6 @@
import Vue from 'vue'; import * as Vue from 'vue';
import App from './App'; import App from './App.vue';
let app = new Vue({ const app = Vue.createApp(App)
render: (h) => h(App), .mount('#app');
}).$mount('#app');

View File

@ -1,8 +1,15 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "es5", "target": "esnext",
"useDefineForClassFields": true,
"module": "esnext",
"moduleResolution": "node",
"strict": true, "strict": true,
"module": "commonjs", "jsx": "preserve",
"moduleResolution": "node" "sourceMap": true,
} "resolveJsonModule": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"]
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
} }

18
vite.config.ts Normal file
View File

@ -0,0 +1,18 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
server: {
proxy: {
'/ws': {
target: "ws://localhost:1234",
ws: true,
},
"/webcam": {
target: "http://localhost:1234",
}
}
}
})