Sunday, June 13, 2021

Deploying Swift/Vapor Apps to Cloudhost

My Swift/Vapor deploying adventure with lots of words, because I stand in solidarity with the Recipe People. But no pictures, because I never think of that.

I thought it would be pretty straightforward. I’ve got Linux hosting at Cloudhost (not its real name) so I can just log in and install Swift and Vapor and build my app and run it, right?

Ha ha, good one.

But my hosting is modest - 1 GB of memory is plenty for my typical needs, which is usually limited to hosting an HTML site - Apache on Ubuntu 16.04.

So try and build a Vapor site? Nope, try and try and fail and fail - fatalError kind of stuff. Try adding -v to the build and re-run just that last command directly in Swift and all of a sudden I see the real problem: I’m running out of memory.

Well hell, of course I am!

So all I need to do is build my app off-site and copy the Run file, right? *Hey, don’t get ahead of me, this is my adventure.

Oh, I almost forgot this part. I’ve got a Linux system, and in fact I’ve already built my app there. Just copy the Run file, right? No, because this is Ubuntu 20.04 and so it depends on libraries and such that are four years newer than what’s running at Cloudhost.

But I’ve got this other PC and it’s got a bunch of memory. It might even ben running Linux already, who knows. Scrounge a keyboard and mouse and monitor. Plug it in. Beep beep beep. Won’t even POST.

No problem, pull the drive and drop it into yet another PC. Boot it up and wouldn’t you know, it’s actually running Ubuntu 16.04. In fact, there are ancient Swift directories from November 2016 when I thought I’d have time to play with the compiler. I didn’t. So get a network hooked up, get Swift installed, and…

$ swift -version

blah blah (I didn’t bother saving all the output)

Illegal Instruction

Oh yeah, if you are thinking about running Swift on Linux on an older PC, do this first:

$ cat /proc/cpuinfo | grep ssse3

because if it comes up blank, you’re going to have a bad time.

So no problem, that Ubuntu 20.04 PC is willing to sacrifice itself temporarily (and I know already it’s got ssse3) so unplug its drive and drop in the Ubuntu 16.04 drive.

Now here’s something I’m not 100% sure I needed to do, but I made sure that I installed Swift in the exact same place on both Ubuntu 16.04 systems - the one on my PC and the one at Cloudhost. In both cases, I have /opt/swift-5.4.1-RELEASE-ubuntu16.04. So if there are libraries that would cause a freakout because of different locations, that’s not going to happen.

And finally I see what I’ve been hoping for:

$ export PATH=/opt/swift-5.4.1-RELEASE-ubuntu16.04/usr/bin:"${PATH}"

$ swift -version

Swift version 5.4.1 (swift-5.4.1-RELEASE)

Target: x86_64-unknown-linux-gnu

So get Vapor installed, pull down my app, and (sudden thunder clap drum roll)

It works!!

*Oh wait… connect from the browser, no it doesn’t!! And this is something I didn’t realize about Vapor, you need to have the Resources/Views directory and all its .leaf (or .html) files. And, it turns out, your Public directory. No problem, so I did a clone of my whole app to get whatever files it needs. As they change, I can pull to refresh them. Then I re-copied the Run file, but this time dropped it in the same x86_64-linux-whatever location as where it came from. This way git doesn’t think I have any untracked files.

Now run it again, and it looks like it works, then hit it from the browser, and it actually does!!

So here are the takeaways:

  • Here are the links for installing swift and vapor
  • You'll have much better luck with your build system separate from your hosting
  • `cat /proc/cpuinfo | grep ssse3` # to make sure your build system is up to running Swift
  • Make sure you have enough memory on your build system (not sure how much that is tbh)
  • Make sure your hosting and build systems have the same exact Ubuntu version (major.minor is probably enough, but…???)
  • Install Swift to the same location on both build and hosting (not 100% sure you need to do this, but I think you do and it can’t hurt, right?)
  • `git clone` your whole app, even though you don’t need the Sources, you do need Resources and Public folders
  • scp .build/x86_64-linux-whatever/debug/Run from your build system to the same spot, so it’s ignored by git

I think that’s it. I hope this helps somebody!

Wednesday, June 02, 2021

Vapor/Leaf #ifdef(sortof)

The Swift/Vapor site I'm working on has one index.leaf to rule them all. (index.html, actually, because I thought I might want to look at my templates in a browser, but tbh I never have - but I digress)

And I find it really handy sometimes to throw in an error message just wherever, like this:

<div class="container">
    #ifdef(error):
    <p class="text-danger">#(error)</p>
    #endif
    #bodyBlock()
</div>

Of course there's no such thing as #ifdef. And I searched and I searched and even thought about implementing #ifdef

And then just when I was about to ask on Discord (and I hate doing that)... I don't even know what made me think of this, but here's what works:

<div class="container">
    #if(error??false):
    <p class="text-danger">#(error)</p>
    #endif
    #bodyBlock()
</div>

And tbh I don't know why it works, because if error doesn't exist, why should ?? even help? But it does. And it does!

So if "error" is in my render context, I'll get a nice red dangerous error message. Sweet!