Tokamak icon indicating copy to clipboard operation
Tokamak copied to clipboard

How do I host and launch TokamakUI apps from a Docker image / container? Can I do that using carton?

Open curveddesign opened this issue 3 years ago ā€¢ 14 comments

I am new to the swiftwasm World! Say for Ubuntu, how do I host and launch TokamakUI ( SwiftUI) apps from a Docker image / container? Can I do that using carton?

It looks like carton makes and runs a web server on http://127.0.0.1:8080/

How do we have that server run from inside a container?

Is there a docker compose / Dockerfile that exists? I do not see this documented anywhere?

curveddesign avatar Sep 20 '20 12:09 curveddesign

Hi @curveddesign, thank you for checking it out. Tokamak apps in their basic form require only static assets, which you can host with any server that supports hosting static files from a directory, be it nginx or anything else. I'd personally recommend using a CDN, such as GitHub Pages or Netlify, but you also use any other CDN in front of your server to make static assets load faster.

You can check out an example of a very primitive todo-list app hosted on GitHub Pages. The files to host were generated with a carton bundle command, which is not available in the latest stable version of carton, but will be released in the next few days. As soon as it's released, that will become the recommended way to get a bundle of assets generated, and the documentation will be updated accordingly. In the meantine if you're not willing to wait, you can create your own index.html file, and the source code for the bundle entrypoint is available in the carton repository. You can then copy the main.wasm file together with index.html and bundle.js to your static files server or a CDN.

Does that answer your question?

MaxDesiatov avatar Sep 20 '20 14:09 MaxDesiatov

To answer your specific question about Docker, I'd personally recommend the nginx image, check out the "Hosting some simple static content" section in their guide, and just copy the generated assets into the volume.

MaxDesiatov avatar Sep 20 '20 14:09 MaxDesiatov

Yes, that answers my question! I am really looking forward to the carton bundle command working, I am going to try your work around! I am still trying to wrap my head around SwiftWasm and WASM in general, your blog posts below really helped me to understand it!

How WebAssembly changes software distribution

The state of Swift for WebAssembly in 2020 (and earlier)

One more question!!! Can I do network calls from TokamakUI? I am almost afraid to try it! šŸ˜Š

Using SwiftWebUI I am able to make network calls using https://github.com/carson-katri/swift-request and I was surprised it actually worked! Since SwiftWasm is its own animal so to speak! Will this work in TokamakUI?

For example:

     Request {
        Url("http://ip-api.com/json/24.48.0.1")
            Method(.get)
            Header.Accept(.json)
        }
        .onJson { json in
            print("json.query.string")
            print(json.query.string)
        }
        .onError { error in
            print(error.localizedDescription)
        }
        .call()

curveddesign avatar Sep 20 '20 16:09 curveddesign

Thanks for checking out the blog posts, I really appreciate it!

I assume you've tried vanilla SwiftWebUI with swift-request, as there's also a WebAssembly fork of SwiftWebUI. Most probably it worked in vanilla, because SwiftWebUI executes all Swift code on the server, not in the WebAssembly environment in your browser.

With Tokamak you'll have to use the Fetch API, and there are no SwiftWasm bindings for it yet, as far as I'm aware. I guess we will have some in the near future as a part of the DOMKit library, but my understanding is that it's not there yet, and is not a part of WebIDL declarations included there, maybe @j-f1 could clarify? Also, bear in mind that fetch returns a Promise object, and the API for it is still being developed in https://github.com/swiftwasm/JavaScriptKit/pull/62. Closure-based APIs in SwiftWasm are not very trivial to work with, as you have to be aware of the lifetime of your closure instances and manually release them. This is an inherent problem caused by the differences in how JavaScript (garbage collection) and Swift (reference counting) allocate memory for closures and their context.

I guess in the future we'll have a simpler API (probably based on Combine publishers) for networking that hides all of this complexity from users if they don't need it. In the meantime you can check old code in the swift-web-github-example repository. It probably won't work with the latest JavaScriptKit 0.6.0, which strictly enforces closure lifetime. It may seem to work in JavaScriptKit 0.5.0, but lack of runtime checks for closure allocations can hide serious bugs.

Overall, if you don't want to dig deep into the technical details, I'd recommend waiting for a bit until the networking/promises part is more or less stable in future versions of JavaScriptKit and DOMKit. Sorry that it's not ready yet, there are many moving parts here that we're working on in parallel, and any help to the development efforts is very welcome.

MaxDesiatov avatar Sep 20 '20 16:09 MaxDesiatov

I started work on an abstraction over fetch that matches URLSession, and it could then be supported in swift-request. But it's not in a working state ATM.

carson-katri avatar Sep 20 '20 17:09 carson-katri

I guess we will have some in the near future as a part of the DOMKit library, but my understanding is that it's not there yet, and is not a part of WebIDL declarations included there, maybe @j-f1 could clarify?

Indeed ā€” fetch is a separate spec that would have to be integrated. Iā€™m not sure how the original maintainers got the .webidl files out of the specs, and I would like to follow the same process for fetch.

j-f1 avatar Sep 20 '20 17:09 j-f1

Yes, it would be great to know where the WebIDL specs come from, as I'd like many more APIs covered eventually, IndexedDB, WebGL (WebIDL for this one is maintained together with the human readable text spec apparently), Web Animations obviously, and whatever comes next that users would be interested in.

MaxDesiatov avatar Sep 20 '20 17:09 MaxDesiatov

Has there been any progress on getting "carton bundle' to work? If needed I could provide a simple docker-compose & Dockerfile for an NGINX ubuntu image. šŸ˜ƒ

curveddesign avatar Sep 26 '20 15:09 curveddesign

I found a regression in carton test, which was related to bugs in recent 5.3 toolchains. I just need to verify that it's fixed, and then maybe after I squeeze in a fix for https://github.com/swiftwasm/carton/issues/112, I'll tag a new release in a couple of days if all goes well. It will support carton bundle as one of the new things in that release.

MaxDesiatov avatar Sep 26 '20 16:09 MaxDesiatov

Great news, carton test works well now with wasm-5.3-SNAPSHOT-2020-09-25-a snapshot, so swiftwasm/carton#112 is the only release blocker left. Working on it now...

MaxDesiatov avatar Sep 26 '20 17:09 MaxDesiatov

carton 0.6.0 is now available on Homebrew, but you'll need to wait for https://github.com/TokamakUI/Tokamak/pull/281 to be merged. This new version of carton ships with new JavaScriptKit runtime, which isn't compatible with the old version we use in Tokamak 0.3.0 or in the main branch.

MaxDesiatov avatar Sep 28 '20 21:09 MaxDesiatov

@MaxDesiatov Thanks for your hard work! There does not seem to be a lot of documentation for JavaScriptKit or maybe I am not looking in the right place? Can you give some hints on how one would do a JavaScript fetch Request?

curveddesign avatar Sep 29 '20 08:09 curveddesign

Thanks for pointing it out, we've put some effort into improving documentation recently, but I admit there's a lot of work remaining on that front. JavaScriptKit doesn't provide bindings for fetch, but I'm preparing an example that I hope will clarify things. Will post it here as soon as it's ready.

MaxDesiatov avatar Sep 29 '20 10:09 MaxDesiatov

@curveddesign You can see an example of fetch usage in this PR to our new OpenCombineJS library. It fetches https://httpbin.org/uuid URL every 2 seconds and displays the result with current time on the page.

Until that PR is merged and the first version of OpenCombineJS is tagged, just feel free to copy the JSPromise and JSError extensions from that PR into your project.

Please let me know how that works for you. šŸ™‚

MaxDesiatov avatar Sep 29 '20 17:09 MaxDesiatov