webui-dev / webui

Use any web browser or WebView as GUI, with your preferred language in the backend and modern web technologies in the frontend, all in a lightweight portable library.
https://webui.me
MIT License
2.95k stars 172 forks source link

Deno's example should update #347

Open jinzhongjia opened 5 months ago

jinzhongjia commented 5 months ago

The current deno example is somewhat outdated and will output some warning messages.

sensiblearts commented 3 months ago

I'm exploring Deno (vs Zig), and just got an example to compile to exe.

I had problems with using an express wrapper on CouchDb, so I'm testing ways to link PouchDb into the Deno directly, and call it from the front end JS. This is a test project.

If I go this route (Deno, instead of Zig or Rust or..), I could prepare a series of examples of increasing complexity.

But I'm not sure about a number of things. I don't know if dynamic loading is the way to do it, but I could not think of another way to have my (compiled) SvelteKit SPA call functions that are defined in the Deno project but not yet defined (until runtime) in the Svelte code.

So, for example, here is a main.ts file of a Deno project:

import { WebUI } from "https://deno.land/x/webui/mod.ts";

import express, { Express, Request, Response } from "npm:express";
import cors from "npm:cors"

// To make this an Exe:
// deno compile --allow-read --allow-env --unstable-ffi --allow-ffi --allow-net main.ts

// FRONT END:
const file_content =
`
<html lang="en">
    <head>
        ...
        <script src="webui.js"></script>
    </head>
    <body>
        <div>
           <button OnClick="couch_doit()">Do it</button>
                </div>
        <script>
            function loadJS(FILE_URL, async = true) {
                let scriptEle = document.createElement("script");
                scriptEle.setAttribute("src", FILE_URL);
                scriptEle.setAttribute("type", "text/javascript");
                scriptEle.setAttribute("async", async);
                document.body.appendChild(scriptEle);
                scriptEle.addEventListener("load", () => {
                    console.log("File loaded")
                });
                scriptEle.addEventListener("error", (ev) => {
                    console.log("Error on loading file", ev);
                });
            }

            loadJS("couch_api.js", true);
          </script>
    </body>
</html>
 `;

const path = "./ui/build";
const nwin = new WebUI();
nwin.setRootFolder(path);

nwin.bind("doSomething", do_something); // see couch_api.js

nwin.show(file_content);

// BACK-END:

async function do_something(e: WebUI.Event) {
    const a = e.arg.string(0); // First argument
    const b = e.arg.string(1); // Second argument
    let obj = JSON.parse(b);
    console.log("1", a);  // to backend console
    console.log("2", obj.name)
    console.log("2", obj.last)
    return `Received: ${a} , ${b}`; // to browser console
}

const port = 3000;
const app: Express = express();
app.use(cors())
app.use(express.json({ limit: '50mb' }))
app.use(express.urlencoded({extended : true}))

const expressServer = app.listen(port, () => {
    console.log(`[server]: Server is running at http://localhost:${port}`);
});

WebUI.wait().then(() => {
    console.log("shutting down...");
    expressServer.close(() => {
        console.log('Express closed.');
    });     
})

Then in a separate couch_api.js file (which can be imported dynamically by the Svelte app, too), is the OnClick handler function:

function couch_doit() {
    let obj = {name: "David", last: "Alm"};
    let j = JSON.stringify(obj);
    doSomething('Message from JSON', j).then((response) => {
        console.log(response); // "Message from C
    });
}

The exe runs fine with the dynamic JS loading.