<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Joe Sweeney</title>
    <description>The latest articles on Forem by Joe Sweeney (@jcs224).</description>
    <link>https://forem.com/jcs224</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F97818%2Fc5c106e3-6344-4c9a-8939-097d94af93d3.jpeg</url>
      <title>Forem: Joe Sweeney</title>
      <link>https://forem.com/jcs224</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jcs224"/>
    <language>en</language>
    <item>
      <title>Deploying a Jigsaw static site to GitHub Pages using GitHub Actions</title>
      <dc:creator>Joe Sweeney</dc:creator>
      <pubDate>Fri, 23 Oct 2020 03:28:03 +0000</pubDate>
      <link>https://forem.com/jcs224/deploying-a-jigsaw-static-site-to-github-pages-using-github-actions-2ejd</link>
      <guid>https://forem.com/jcs224/deploying-a-jigsaw-static-site-to-github-pages-using-github-actions-2ejd</guid>
      <description>&lt;p&gt;There are a couple of articles on how to do this already, so I'll put them at the end of this article in case this method doesn't work out for you (and I give them credit as they gave me a starting point and I used some of their code in this article). In the meantime, I want to show you what I believe to be the best and easiest way to deploy your &lt;a href="https://jigsaw.tighten.co/"&gt;Jigsaw&lt;/a&gt; site to GitHub Pages using GitHub Actions after a bit of my own trial and error.&lt;/p&gt;

&lt;p&gt;This method assumes that you want to publish one of your personal GitHub projects, or a "project" site. This will probably need to be tweaked for a "user" site, which I don't have any experience with (at least not in GitHub).&lt;/p&gt;

&lt;p&gt;It also assumes you've gotten a Jigsaw site that builds properly at least in a local dev environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;In your repo's GitHub settings, turn on GitHub Pages, using &lt;code&gt;gh-pages&lt;/code&gt; as the branch to build from, and &lt;code&gt;/&lt;/code&gt; (root) as the folder to build from.&lt;/p&gt;

&lt;p&gt;Then, from your repo's root directory, create a new workflow under &lt;code&gt;.github/workflows/main.yml&lt;/code&gt; with the following contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build &amp;amp; Publish&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build-site&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Composer Dependencies&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;composer install --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install NPM Dependencies&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Site&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run production&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Stage Files&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;git add -f build_production&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Commit files&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;git config --local user.email "actions@github.com"&lt;/span&gt;
        &lt;span class="s"&gt;git config --local user.name "GitHub Actions"&lt;/span&gt;
        &lt;span class="s"&gt;git commit -m "Build for deploy"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Publish&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;git subtree split --prefix build_production -b gh-pages&lt;/span&gt;
        &lt;span class="s"&gt;git push -f origin gh-pages:gh-pages&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should literally be everything you need to do. You can test this by manually running the action from the GitHub Action tab, or just commit new code to the &lt;code&gt;master&lt;/code&gt; or &lt;code&gt;main&lt;/code&gt; branch of your project. &lt;/p&gt;

&lt;p&gt;If you're using &lt;code&gt;main&lt;/code&gt;, which is possible as GitHub is making it the default for new repos, you'll just need to change anywhere &lt;code&gt;master&lt;/code&gt; is referenced to &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks to James Brooks and Max Kostinevich for your helpful articles getting me even started on the right path and saving me tons of time:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://james.brooks.page/blog/jigsaw-github-actions/"&gt;https://james.brooks.page/blog/jigsaw-github-actions/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://maxkostinevich.com/blog/deploy-jigsaw-using-github-actions/"&gt;https://maxkostinevich.com/blog/deploy-jigsaw-using-github-actions/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Laravel task scheduling without cron jobs for local development</title>
      <dc:creator>Joe Sweeney</dc:creator>
      <pubDate>Thu, 11 Jun 2020 21:23:46 +0000</pubDate>
      <link>https://forem.com/jcs224/laravel-task-scheduling-without-cron-jobs-for-local-development-4i84</link>
      <guid>https://forem.com/jcs224/laravel-task-scheduling-without-cron-jobs-for-local-development-4i84</guid>
      <description>&lt;p&gt;&lt;em&gt;Since publishing this article, it seems Laravel now has an official way of running the scheduler locally, which is described here: &lt;br&gt;
&lt;a href="https://laravel.com/docs/8.x/scheduling#running-the-scheduler-locally"&gt;https://laravel.com/docs/8.x/scheduling#running-the-scheduler-locally&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It's very easy to create scheduled tasks in Laravel. They're also pretty easy to run in Linux or MacOS with cron jobs. However, I've been doing a lot of development on Windows lately, and Windows does &lt;em&gt;not&lt;/em&gt; have UNIX-style cron jobs. And, there is no mention in Laravel's docs on how to do this properly in Windows. I found &lt;a href="https://quantizd.com/how-to-use-laravel-task-scheduler-on-windows-10/"&gt;this helpful article&lt;/a&gt; going over how to do this in Windows using the Task Scheduler, but this felt way too cumbersome. Crawling around arcane Windows settings is not my idea of a good time, and just feels wrong since this is a project-level, not system-level, concern.&lt;/p&gt;

&lt;p&gt;So, I found a simple workaround that helps me not only avoid dealing with the Windows Task Scheduler, but also the crontab in macOS and Linux as well! If I were to switch dev computers tomorrow, or bring other people into my project, I have completely cross-platform method of handling scheduled jobs without digging into the guts of my operating system; a NodeJS library.&lt;/p&gt;
&lt;h2&gt;
  
  
  Using &lt;code&gt;node-schedule&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;So, I'm not sure if this makes me a bad Laravel dev since I'm not building this tool as an Artisan command (or even in PHP), but it's the most effective and reliable solution available right now without doing a bunch of extra work. Since most Laravel devs are using some sort of front-end tooling (such as &lt;a href="https://laravel.com/docs/7.x/mix"&gt;Laravel Mix&lt;/a&gt; or Webpack), we already have Node (and maybe Yarn) installed on our dev machines, making this less of a burden.&lt;/p&gt;
&lt;h3&gt;
  
  
  Add &lt;code&gt;node-schedule&lt;/code&gt; to your project
&lt;/h3&gt;

&lt;p&gt;Make sure you're &lt;code&gt;cd&lt;/code&gt;'d into your Laravel project root and run either the NPM or Yarn command below, depending on what you've got going.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# NPM
npm install node-schedule --save-dev

# Yarn
yarn add --dev node-schedule
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create JavaScript file for schedule code
&lt;/h3&gt;

&lt;p&gt;Still in your root directory, create a file called &lt;code&gt;dev-scheduler.js&lt;/code&gt;, then put the following in that file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;schedule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node-schedule&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;exec&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;child_process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scheduleJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;* * * * *&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;php artisan schedule:run&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run the schuduler
&lt;/h3&gt;

&lt;p&gt;Run the new file with Node.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node dev-scheduler.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And…that's it. Keep in mind this is &lt;strong&gt;not&lt;/strong&gt; for production. Use cron jobs for that.&lt;/p&gt;

&lt;p&gt;Enjoy this time-saver!&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>productivity</category>
      <category>windows</category>
      <category>localdev</category>
    </item>
    <item>
      <title>Twilio Hackathon — Connecting the elderly to more people in their local community</title>
      <dc:creator>Joe Sweeney</dc:creator>
      <pubDate>Fri, 01 May 2020 01:09:23 +0000</pubDate>
      <link>https://forem.com/jcs224/twilio-hackathon-connecting-the-elderly-to-more-people-in-their-local-community-262d</link>
      <guid>https://forem.com/jcs224/twilio-hackathon-connecting-the-elderly-to-more-people-in-their-local-community-262d</guid>
      <description>&lt;p&gt;I have a neighbor whom I've worried about on occasion, but much more so now that COVID-19 is upon us. She is 80 years old and, while still very independent and able to do most everything she wants, is quite vulnerable to this pandemic. I also found out she doesn't have the Internet, or even a computer. Or a smart phone. Or a phone that can text! She just has a landline phone. &lt;/p&gt;

&lt;p&gt;It made me realize that there are probably a lot of people out there who need help, but don't have the ability to reach out and ask for help as easily. Of course, hopefully most of those folks can call on family or other trusted people nearby, but if not, they need some other way to ask for help that isn't an immediate emergency, but are very much needed nonetheless (getting groceries or prescriptions, having something delivered across town, etc.).&lt;/p&gt;

&lt;p&gt;After seeing the announcement for this hackathon, I dug through the Twilio APIs looking for some inspiration and came up with this idea after looking through the Voice documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;The project is called "I Need Help", and it is a Node-powered web app that allows people to simply make a phone call to a number, and a bot asks them what they need help with. It only asks for the person to introduce themselves and state their needs, it doesn't ask for any other personal details. The caller's request is recorded, then published on the "I Need Help" website (with their direct consent, of course. If they don't agree to the terms, the call will end and the interaction isn't recorded).&lt;/p&gt;

&lt;p&gt;Once the recording is on the website, a registered and logged-in user can assign that need to themselves. This user, which I've been calling a "helper", can call the person in need via an anonymous number (to protect the person-in-need's phone number), and the person in need can also reach out to the helper with their own anonymous number. They can call each other with those same numbers as long as the task is in progress (similar to an Uber driver/rider interaction).&lt;/p&gt;

&lt;p&gt;When a task is in progress, a helper can either mark the task as complete if they successfully helped the person or they can put it back in the queue to allow someone else to help. Also, I made the design decision to only allow one task to be worked on at a time, for both technical reasons and to help the helpers avoid taking on more than they can handle. Each person who needs help should get their undivided attention. Also, the person who calls in a request can only request one thing at a time per number, until that task is resolved.&lt;/p&gt;

&lt;p&gt;There is a very basic stats page that the signed-in user can look at to see how needs they have fulfilled, so that they are more motivated to continue.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I built it
&lt;/h2&gt;

&lt;p&gt;I started building the app on April 8th. I didn't formally plan it too much, I just started writing code and playing with Twilio's API immediately. I'm organizing my work just using Github's issue tracker with the project repo. As of right now, the app seems pretty stable but could probably use more features. As you'll see if you look at the commit history, I worked on it pretty heavily for 10 days then took a break before cleaning it up for final submission.&lt;/p&gt;

&lt;p&gt;The app is built using &lt;a href="https://adonisjs.com/"&gt;Adonis&lt;/a&gt; (a NodeJS framework), MySQL (or any relational database compatible with &lt;a href="http://knexjs.org/"&gt;Knex.js&lt;/a&gt;), &lt;a href="https://mithril.js.org/"&gt;Mithril&lt;/a&gt;, and &lt;a href="https://getbootstrap.com/"&gt;Bootstrap&lt;/a&gt;. There are even some websockets in there! I wanted to stick with a stack I'm comfortable with, since I've never used Twilio's API before and didn't want to spend too much time learning too many different things at once. I also didn't want to spend much time fussing with front-end build tools, so all the scripts, assets, and other dependencies are just CDN'd onto the pages.&lt;/p&gt;

&lt;p&gt;The websockets are used to update the front-page in real-time with the most up-to-date tasks so that users don't have to constantly refresh the page to see new tasks they can help with. And, when tasks are marked as in-progress or completed, they're removed from that page so no one else can accidentally claim the task.&lt;/p&gt;

&lt;p&gt;I'm using two features of Twilio right now; the Programmable Voice API to handle the initial phone call and recording, and the Proxy service to make phone numbers anonymous.&lt;/p&gt;

&lt;h2&gt;
  
  
  Video demo
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/bOW6Dz88fdU"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Link to code
&lt;/h2&gt;

&lt;p&gt;You can find the repository here, with setup instructions so you can host your own instance:&lt;br&gt;
&lt;a href="https://github.com/jcs224/ineedhelp"&gt;https://github.com/jcs224/ineedhelp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, I'm looking at other people's submissions and am very impressed. There are a lot of brilliant, creative devs out there. Great job!&lt;/p&gt;

</description>
      <category>twiliohackathon</category>
      <category>covid19</category>
    </item>
    <item>
      <title>Introducing Podrain, a web-based, offline-capable podcast app</title>
      <dc:creator>Joe Sweeney</dc:creator>
      <pubDate>Sat, 14 Mar 2020 01:41:09 +0000</pubDate>
      <link>https://forem.com/jcs224/introducing-podrain-a-web-based-offline-capable-podcast-app-2hlm</link>
      <guid>https://forem.com/jcs224/introducing-podrain-a-web-based-offline-capable-podcast-app-2hlm</guid>
      <description>&lt;p&gt;I've been a fairly avid listener of podcasts since 2005, which is around when Apple introduced them to iTunes. I was pretty embedded in the Apple ecosystem back then, so I didn't really care that there wasn't a good way of listening to podcasts on non-Apple devices. &lt;/p&gt;

&lt;p&gt;Over the years, however, I have been distancing myself from Apple more and more, to the point where I now only use Apple devices when I need to build and deploy iOS projects. I've been developing an allergy to monopolistic lock-in and censorship of which apps can run where. I've embraced the web as much as possible, as both a user and a software developer, because it is the most device-agnostic standard out there today. If your device has a screen, and a web browser, the chances of a web-based app working on it are actually pretty high.&lt;/p&gt;

&lt;p&gt;But, as far as podcasts were concerned, I found it really tough to find a non-Apple app that had everything I wanted. Ease of use, offline listening, ability to back up and sync with other devices, and run on any device. I'm an Android user now, so I've been using Podcast Addict, which is a great app. But, it's exclusive to Android. I wanted to give Pocket Casts a go, but the reliability was so-so according to reviews, and I need something I can trust. I tried Stitcher, but it was just too hard to listen to podcasts without being distracted by all the advertising and non-podcast-related stuff. I use Spotify for music, but their interface just isn't well-suited for podcasts, and besides, I want to support podcasts as an open web standard that no big entity seeks to control, which even Apple respects (in regards to podcasts).&lt;/p&gt;

&lt;p&gt;So, I decided to scratch my own itch and take a crack at this problem myself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Podrain
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/podrain/podrain"&gt;Podrain&lt;/a&gt; is a web-based podcasting app with some very basic features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Offline listening&lt;/li&gt;
&lt;li&gt;Episode queue that spans across podcasts&lt;/li&gt;
&lt;li&gt;Pure focus on audio podcasts (no radio, video podcasts, news, etc.)&lt;/li&gt;
&lt;li&gt;Sync backup to a cloud server&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  App structure
&lt;/h2&gt;

&lt;p&gt;The app was built with my "trusty tools", &lt;a href="https://parceljs.org/"&gt;Parcel&lt;/a&gt;, &lt;a href="https://mithril.js.org/"&gt;Mithril&lt;/a&gt; and &lt;a href="https://tailwindcss.com/"&gt;Tailwind&lt;/a&gt;. I've been using this stack lately for almost every new project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges
&lt;/h2&gt;

&lt;p&gt;It took me about three weeks of part-time effort to build this app, which I open-sourced yesterday. It's still pretty rough around the edges and needs more documentation, but it works well enough and I've replaced my current podcast app with it! Besides regular web development woes, here are some of the challenges I faced and how I overcame them.&lt;/p&gt;

&lt;h3&gt;
  
  
  The offline problem
&lt;/h3&gt;

&lt;p&gt;I've actually tried to build this app before, but as a web app that &lt;em&gt;completely relied&lt;/em&gt; on having a really good internet connection the entire time. This obviously doesn't work for someone who spends much of his time in one of the most rural areas of the United States. So, I had to take a different approach and ensure that this app could work in a way that didn't need &lt;em&gt;any&lt;/em&gt; Internet connection after the initial app was loaded. After all, I listen to podcasts quite often while driving in areas with not so much as a 3G cell signal. To solve that, I used &lt;a href="https://pouchdb.com/"&gt;PouchDB&lt;/a&gt; which made it really easy to store all the needed podcast metadata in browser storage, and have it persist even when the app web page is closed.&lt;/p&gt;

&lt;p&gt;In addition, I needed the actual audio files to be saved to the device, rather than streamed. This is very important for both maintaining an uninterrupted listening experience as well as to avoid risking extra charges for excessive cell data usage. I used &lt;a href="https://localforage.github.io/localForage/"&gt;localForage&lt;/a&gt; to give the user the option to store the audio files in their browser's IndexedDB storage system as binary &lt;code&gt;Blob&lt;/code&gt;s.&lt;/p&gt;

&lt;p&gt;Unfortunately, the audio file download feature won't work well on iOS because they only allow 50-megabyte files for domain, when a single MP3 file for a podcast episode could easily be twice that. Will probably have to disable the feature for iOS browsers unless Apple has a change of heart.&lt;/p&gt;

&lt;h3&gt;
  
  
  CORS for podcast feeds and media
&lt;/h3&gt;

&lt;p&gt;This was actually a very tough problem to solve that seemed to have only bad options. The easiest way was to disable CORS in my browser (using a browser plugin), but that's very unsafe as I would be quite vulnerable to XSS and other nasty attacks if I visit other websites. The other option is to use a proxy, but downloading hundreds of megs data using a public proxy would easily overwhelm many of these proxy sites and I might even have my IP address banned. &lt;/p&gt;

&lt;p&gt;However, there is a Node server called &lt;a href="https://github.com/Rob--W/cors-anywhere/"&gt;CORS Anywhere&lt;/a&gt; that can take all requests to a domain, and forward them with different CORS headers that allow the browser to accept content from different domains via XHR. It turns out there is an excellent &lt;a href="https://elements.heroku.com/buttons/puzzleboss/cors-anywhere"&gt;pre-configured Heroku dyno&lt;/a&gt; anyone can spin up and run their own proxy, likely for free! So that's what I did. Then, in the app, I put the URL to this proxy and I'm off to the races. I may find a better way of setting that up more automatically down the road, but once it was set up, I'm able to start adding podcasts and listening to episodes!&lt;/p&gt;

&lt;h2&gt;
  
  
  Future
&lt;/h2&gt;

&lt;p&gt;The app has some real rough edges, but they will be worked out over time. Eventually, I want to add service workers and a web app manifest file to make it a true PWA. Also, the interface needs to be optimized for tablet/desktop, since it was built mobile-first for the smallest screen (where I use it the most).&lt;/p&gt;

&lt;p&gt;Hopefully, this app can help serve as one of many examples of just how far you can take pure web technologies if you give them a chance.&lt;/p&gt;

</description>
      <category>mithriljs</category>
      <category>tailwindcss</category>
      <category>showdev</category>
      <category>offlinefirst</category>
    </item>
    <item>
      <title>Switching back to a monolith</title>
      <dc:creator>Joe Sweeney</dc:creator>
      <pubDate>Thu, 30 Jan 2020 21:52:56 +0000</pubDate>
      <link>https://forem.com/jcs224/switching-back-to-a-monolith-29io</link>
      <guid>https://forem.com/jcs224/switching-back-to-a-monolith-29io</guid>
      <description>&lt;p&gt;A couple of years ago, I finally decided to dive head-first into some of the newer JavaScript technologies that I've been putting off for a while, such as Webpack, Vue, and NodeJS.&lt;/p&gt;

&lt;p&gt;Before I was "enlightened", when I wanted to include JS or CSS in my regular ol' web app (built with &lt;a href="https://laravel.com/"&gt;Laravel&lt;/a&gt;), I would just include it in a &lt;code&gt;script&lt;/code&gt; or &lt;code&gt;link&lt;/code&gt; tag in my HTML. Pretty simple. And, I was perfectly content doing this. I even used Gulp a little bit, mostly for minifying my own JS and compiling Sass stylesheets. But, it was becoming clear that there was this huge ecosystem of things happening in JS-land and I was feeling at risk of falling behind if I didn't at least try to learn some of it.&lt;/p&gt;

&lt;p&gt;So, I incorporated some Vue into my existing project, without Webpack or build tools of any kind. I really enjoyed how Vue handled reactivity and DOM updates. Compared to jQuery, it was like magic. I was able to throw away so much spaghetti jQuery on a page and basically create a full-blown mini-app with just a simple Vue instance.&lt;/p&gt;

&lt;p&gt;After that great experience, I started looking into how Vue is used out in the wild. While my particular use-case as a simple add-in to a traditional server-rendered web app was actually pretty common, it became evident that Vue is really built with single-page apps in mind. This led me down a rabbit hole of Webpack, Node, single-page app architecture, NPM, new authentication schemes, new data-fetching schemes (REST, GraphQL)…&lt;/p&gt;

&lt;p&gt;Despite having to learn all these new things, I decided to do a rewrite of my Laravel side project in pure JavaScript using &lt;a href="https://adonisjs.com/"&gt;AdonisJS&lt;/a&gt; and &lt;a href="https://mithril.js.org/"&gt;Mithril&lt;/a&gt; after playing around with them a bit. And, I learned a great deal from that experience. I built a front-end single-page app in Mithril, backed by an Adonis API. This allowed me to create a really interactive experience in the front-end, and made the app feel more like an "app" rather than a "website". It did, however, present a lot of new challenges.&lt;/p&gt;

&lt;h2&gt;
  
  
  Secure authentication
&lt;/h2&gt;

&lt;p&gt;Authentication is actually not very straightforward to implement, if I truly separate my API from the user-facing app. I have to be very careful how I store and use auth tokens (such as with OAuth and JWT), and I have to be conscious of more threats than with session-based backends protected by CSRF. In other words, there are a lot of ways to mess it up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Efficiently fetching data
&lt;/h2&gt;

&lt;p&gt;With a single-page app, usually it would fetch data from an API, or multiple APIs. However, I have to be careful to only grab the data I need, when I need it. I would often grab too much and have more data than I need, or, I would grab too little and have to make multiple, inefficient requests. Solutions like GraphQL are meant to address this, but it adds another layer of concern to both the front and back-end.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decoupled architecture
&lt;/h2&gt;

&lt;p&gt;While this can be very beneficial if I want to offer a suite of end-user products (web, mobile, desktop, toaster, etc.), it does make it more expensive early in the project to basically have to build a minimum of two products in order to get to release. This makes distribution a bit more complicated, and can be a bottleneck early on when I really want to be moving as fast as possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;I've only recently really embraced test-driven development when building my own web apps, but now I have to write tests for &lt;em&gt;two&lt;/em&gt; apps (single-page app, API) instead of just one. End-to-end tests are easy on the API, but I have to always make sure the test mocks on the front-end match my API, assuming I want to test the SPA and API independently. A change in one of the apps usually means I have to change the other one as well.&lt;/p&gt;

&lt;p&gt;With a "traditional" web app, all the unit and end-to-end tests can be included in the same test suite.&lt;/p&gt;

&lt;h1&gt;
  
  
  Final thoughts
&lt;/h1&gt;

&lt;p&gt;While I did learn a ton creating an API/single-page app architecture (and likely will again in the near future), I've decided to go back to doing things "old school", but with some "new school" sprinkled in for my current project. I'm doing a V3 rewrite as a Laravel app again, without an API. You could say I've embraced the &lt;a href="https://m.signalvnoise.com/the-majestic-monolith/"&gt;Majestic Monolith&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, the templates for the app will actually be a single-page app thanks to &lt;a href="https://inertiajs.com/"&gt;InertiaJS&lt;/a&gt;, an innovative library that allows me to write my templates in Vue, React, or Svelte without having to use an API. I'm literally getting the best of both worlds; the stability and simplicity of a traditional Laravel app, combined with the cutting-edge, interactive UI of a single-page app. Perhaps I'll write more in-depth about Inertia in the future, but in the meantime, you should check it out!&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>webdev</category>
      <category>laravel</category>
      <category>inertiajs</category>
    </item>
    <item>
      <title>Benefits of contributing code to your favorite open source project(s)</title>
      <dc:creator>Joe Sweeney</dc:creator>
      <pubDate>Sun, 10 Nov 2019 22:30:49 +0000</pubDate>
      <link>https://forem.com/jcs224/benefits-of-contributing-code-to-your-favorite-open-source-project-s-56pi</link>
      <guid>https://forem.com/jcs224/benefits-of-contributing-code-to-your-favorite-open-source-project-s-56pi</guid>
      <description>&lt;p&gt;Open-source software is extremely pervasive. Many of you reading this probably benefit directly from it to help you do your jobs. End users experience the benefits when they surf the web or use a free alternative to prohibitively-priced software (such as &lt;a href="https://godotengine.org/"&gt;Godot game engine&lt;/a&gt; or &lt;a href="https://www.gimp.org/"&gt;GIMP&lt;/a&gt;). Also, many of us simply like to examine the source code of our favorite projects to learn a bit more about how they work.&lt;/p&gt;

&lt;p&gt;These are all great reasons to use open-source. However, the real power lies in not just consuming all of this great work, but actually contributing something back. Events like &lt;a href="https://hacktoberfest.digitalocean.com/"&gt;Hacktoberfest&lt;/a&gt; help incentivize us to actually try doing that, but personally I get far more out of it than a free t-shirt. &lt;/p&gt;

&lt;p&gt;There are also many other ways to contribute to open source (documentation, evangelizing the project, etc.) but in this article I want to focus on code contributions specifically.&lt;/p&gt;

&lt;p&gt;Here are some of the benefits that I've personally experienced.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting a better in-depth understanding of the project
&lt;/h2&gt;

&lt;p&gt;As you can imagine, you'll learn a lot about the project codebase if you're trying to fix a bug or add a feature. Even if you don't ultimately succeed in figuring it out and making the change, you will undoubtedly learn a lot from the experience. &lt;/p&gt;

&lt;p&gt;If you do get stuck, don't be afraid to ask for help by raising an issue on Github, or whatever communication channels are preferred by the project.&lt;/p&gt;

&lt;p&gt;Also, don't feel like you need to be an expert in the project. Most of my changes are about &lt;a href="https://github.com/godotengine/godot/pull/33096/files"&gt;two lines of code&lt;/a&gt;. Sometimes that's the difference between code that works and code that doesn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feeling of empowerment
&lt;/h2&gt;

&lt;p&gt;If the project is on Github, you'll probably notice that there are far more stars (people who show some tangential interest in the project) than contributors (people who actually have committed code). If you become a contributor, however small your contribution, you become a member of an elite club. Someone who cares and takes action, and doesn't just sit on the sidelines waiting for others to improve the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a stronger connection with the project community
&lt;/h2&gt;

&lt;p&gt;When you pay for a proprietary software product with dollars, you want to see a return on your investment in terms of more dollars than you put in (usually). When you make a change or add a fix to your favorite open-source project, you're making an investment with your time, but it's more personally enriching as it helps you learn and brings you closer to people who work on this project purely out of the joy they get from working on it. If you end up making multiple contributions to the project over time, you'll likely be interacting with the same people on a regular basis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Valuable experience in collaboration and communication
&lt;/h2&gt;

&lt;p&gt;With remote work on the rise, especially in the tech industry, the ability to communicate effectively and collaborate with others will be of utmost importance. When you participate in an open-source project, whether with Github issues, the project's Slack/Discord channel, or even a mailing list, your ability to interact with people of vastly different backgrounds and situations will become paramount. The better you are at this, the more desirable you will be by potential employers and customers/clients. What better way to practice this than by helping improve a project you care about?&lt;/p&gt;

&lt;p&gt;Also, if there are contribution guidelines (often in the form of a &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; file in the project repo) you will be able to demonstrate that you're able to properly follow instructions and care about doing things right.&lt;/p&gt;

&lt;h2&gt;
  
  
  Résumé builder
&lt;/h2&gt;

&lt;p&gt;If you're on Github, a large portion of the things you do on that platform are public. Use this to your advantage by always putting your best foot forward when you're making pull requests and communicating with fellow contributors. As software devs, we are fortunate to have this avenue to demonstrate our work, so make the most of it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;There are so many ways to benefit from contributing to open source, that I wished I started doing it sooner. I hope that you can find some time to participate in improving one of your favorite projects and experience at least some of the same benefits.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>career</category>
      <category>beginners</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to actually make your life easier with Docker</title>
      <dc:creator>Joe Sweeney</dc:creator>
      <pubDate>Thu, 31 Oct 2019 22:21:12 +0000</pubDate>
      <link>https://forem.com/jcs224/how-to-actually-make-your-life-easier-with-docker-hjo</link>
      <guid>https://forem.com/jcs224/how-to-actually-make-your-life-easier-with-docker-hjo</guid>
      <description>&lt;p&gt;When Docker came out in 2013, the benefits being touted were pretty clear. "Full isolation from host machine and other apps", "perfectly-reproducible environments", and the "works on my machine" chant finally a thing of the past. Considering that most of my time troubleshooting issues was getting my code that works perfectly in development to run in production properly, Docker seemed like a great antidote.&lt;/p&gt;

&lt;p&gt;However, what held me back from adopting it for another, like, 5 years, was that it was just too difficult to understand. I don't like working with tech stacks that I don't understand, because that's just another issue I'd have to troubleshoot down the road when things don't go totally perfectly. Despite having to do a little more work to configure the server where my code would ultimately live and run, and sometimes deal with some painful config issues, at least I had encountered many of those issues previously and knew how to fix them.&lt;/p&gt;

&lt;p&gt;Today, Docker is so pervasive that it's actually become quite difficult to avoid. It seems like just about every project on Github has a &lt;code&gt;Dockerfile&lt;/code&gt; and instructions in the &lt;code&gt;readme&lt;/code&gt; on how to use it. Fortunately, it has, in my opinion, started to live up to its promise of actually making our lives as devs easier. I still haven't quite gone "all-in" with Docker, but there are areas where it has genuinely improved my happiness and productivity. &lt;/p&gt;

&lt;h2&gt;
  
  
  My sweet spot with Docker
&lt;/h2&gt;

&lt;p&gt;There are certain stacks that I find a &lt;em&gt;huge&lt;/em&gt; pain to set up again and again, when switching computers for example. These tend to be things like relational database (MySQL and Postgres) and any type of app that normally has a really crazy setup procedure (like self-hosted Gitlab).&lt;/p&gt;

&lt;p&gt;How many times have you run into issues setting up MySQL on your computer? Especially on Linux? I always seem to struggle with that one. Adding the right package repository in Ubuntu, getting through the CLI installation unscathed, and booting it up. All of the different configuration possibilities allow a lot of things to get messed up on that initial install and bootup.&lt;/p&gt;

&lt;p&gt;Or, I can just do this, and have a fully-working MySQL server ready to go!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run --name mysql-5 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:5
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;From there, I just use my favorite MySQL editor (Sequel Pro, HeidiSQL, etc.) and I can connect any service on my machine that needs MySQL, Docker or not, to use it as needed. And, I can boot up as many as I want (or as many as my hardware would allow) and just change the exposed port on those new instances (like 3307, 3308, etc.) so there isn't any conflict.&lt;/p&gt;

&lt;p&gt;Also, I like to test emails on my local machine without relying on en external service to handle it. Instead, I can just throw in a quick SMTP trapping service called &lt;a href="https://github.com/mailhog/MailHog"&gt;Mailhog&lt;/a&gt; that allows me to actually see the output of my locally-tested email!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run --name my-mailhog -p 1025:1025 -p 8025:8025 -d mailhog/mailhog
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This command is even simpler. Just provide a name of your choosing to identify the container, the ports you want exposed (in this case, 1025 for the SMTP port and 8025 for the web portal to see the trapped emails), and the name of the image in Docker Hub (&lt;code&gt;mailhog/mailhog&lt;/code&gt;). This command will boot up the server and allow you to see your trapped emails. It's incredibly easy.&lt;/p&gt;

&lt;p&gt;So, I could use Docker with my main app codebase, but I just continue to use NodeJS without even worrying about Docker-izing it. Also, these examples aren't necessarily helpful for deploying to production (which Docker can certainly help with, with the right knowledge), they were just to help demonstrate setting up a nice development environment with less fuss.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;If you're finding it difficult to get into and understand Docker, or feeling left behind by the hype train, don't worry. You can make Docker work for you, without feeling like you need to ditch your VMs and anything not totally containerized. I have found a middle-ground that is working very well for me at the moment. As time goes on, I'm sure I'll adopt more and more pieces as it makes sense. I hope you can do the same as well.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>productivity</category>
      <category>localdev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The Five-Minute Rule</title>
      <dc:creator>Joe Sweeney</dc:creator>
      <pubDate>Mon, 28 Oct 2019 04:11:35 +0000</pubDate>
      <link>https://forem.com/jcs224/the-five-minute-rule-11l0</link>
      <guid>https://forem.com/jcs224/the-five-minute-rule-11l0</guid>
      <description>&lt;p&gt;In the world of web development (or any kind of dev for that matter), there are &lt;em&gt;so&lt;/em&gt; many stacks and tools to choose from to accomplish our tasks. But, the paradox of choice can paralyze us. Usually, the choice comes down to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What we have experience with already&lt;/li&gt;
&lt;li&gt;If a certain tool/language/stack/whatever is best suited to the task&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, if we're beginners, trying to tackle a brand-new problem, or are simply curious about trying other things out, we can really get bogged down by all the options.&lt;/p&gt;

&lt;p&gt;I've reflected on this recently, as I come up with new ideas for apps sometimes, and I wonder how I should go about building them. I usually like to take this opportunity to experiment with other tools without investing too heavily. If I find a bunch of different options that I think might fit my requirements and development style, I try to give them all a chance.&lt;/p&gt;

&lt;p&gt;After doing this for a while, I've come up with an interesting formula that has actually sort of worked for me (when I practice it). I call it the "Five-Minute Rule".&lt;/p&gt;

&lt;p&gt;How does it work?&lt;/p&gt;

&lt;p&gt;Well, I try to install the stack on my computer. While the timer hasn't technically started yet, I do judge on how easy it is to set up. It has to have great documentation and/or a super-easy, streamlined install process that doesn't require me to reconfigure my machine very much.&lt;/p&gt;

&lt;p&gt;Once I have it set up, I try to run a typical "hello world" scenario. At this point, my judging criteria is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How quickly I could create a working example, however small&lt;/li&gt;
&lt;li&gt;See if I can do something slightly more sophisticated and get the expected result&lt;/li&gt;
&lt;li&gt;Determine if it fits my "philosophy" of how to further build upon this starting point&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's a little nebulous, but my favorite tools over the years have been determined by this method. It really allows me to try a bunch of stacks without investing too much into any one of them.&lt;/p&gt;

&lt;p&gt;Here are some examples of great tools I've discovered through this method, and they span disciplines:&lt;/p&gt;

&lt;h3&gt;
  
  
  Back-end
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://laravel.com/"&gt;Laravel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://adonisjs.com/"&gt;AdonisJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rust-lang.org/"&gt;Rust&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  CSS
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://getbootstrap.com/"&gt;Bootstrap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tailwindcss.com/"&gt;Tailwind&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  JS (front-end)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://vuejs.org/"&gt;Vue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mithril.js.org/"&gt;Mithril&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Build tools
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://parceljs.org/"&gt;Parcel&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Game dev
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://godotengine.org/"&gt;Godot&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One thing all of these tools have in common is that they have great documentation, very easy setup, or both. Also, these are all fully open-source tools, making this exercise much easier. Other factors include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Community/popularity&lt;/li&gt;
&lt;li&gt;Aesthetics

&lt;ul&gt;
&lt;li&gt;Does it "feel good"?&lt;/li&gt;
&lt;li&gt;Attention to detail&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;What has been built with it already&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, my advice is to simply try a few technologies that you're trying to decide between, and not commit immediately. If you find one that feels right and you are impressed with it, do some further due diligence to make sure it can meet your future needs. Then, commit to success and start working on your project.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>dx</category>
      <category>beginners</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Why I choose Mithril.js</title>
      <dc:creator>Joe Sweeney</dc:creator>
      <pubDate>Sun, 06 Oct 2019 19:41:24 +0000</pubDate>
      <link>https://forem.com/jcs224/why-i-choose-mithril-js-55l9</link>
      <guid>https://forem.com/jcs224/why-i-choose-mithril-js-55l9</guid>
      <description>&lt;p&gt;These days, it's really difficult to choose a JavaScript framework to begin a new project. It would seem that React is the front-runner, but what about this revolutionary Vue thing? Should I use Angular because Google supports it, making it more appealing to large companies? But it's so much different from the original AngularJS... What about mobile development capabilities with React Native, or NativeScript? Would if React's license changes again? Should I switch?&lt;/p&gt;

&lt;p&gt;Honestly, I find this decision-making pretty exhausting, but I also don't want to make the "wrong" choice. However, as I've learned with most things in life, I feel best when I make decisions based on my own values rather than what others purport to be the "correct" or "popular" choice. I've always felt like a little bit of a rebel, but it's only because I have specific requirements that the popular options don't fulfill. In the case of front-end frameworks, it can be quite difficult to objectively field whether a certain framework is best for my project or development style, simply because of the incredible marketing hyperbole behind each of these frameworks.&lt;/p&gt;

&lt;p&gt;So, what would an ideal JavaScript framework look like to me?&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple API
&lt;/h3&gt;

&lt;p&gt;The fewer concepts I have to learn, the less guilty I feel about not knowing all the cool features I'm missing out on that probably aren't relevant to me anyway. &lt;/p&gt;

&lt;h3&gt;
  
  
  Great out-of-the-box performance
&lt;/h3&gt;

&lt;p&gt;Nobody likes a slow site. And, as a developer, I don't want to have to work unreasonably hard to make a site performant. This should just be the default to start, while perhaps requiring a bit more care as the project grows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fast initial load
&lt;/h3&gt;

&lt;p&gt;Less code in the library means saving precious bandwidth when loading it on a web page. This is especially important on mobile.&lt;/p&gt;

&lt;h3&gt;
  
  
  Doesn't require a build step
&lt;/h3&gt;

&lt;p&gt;Many web pages on the web today are not single-page apps built with Webpack. Sometimes, I just want to throw some JS on a regular ol' web page to add a little bit of dynamic behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  Community support
&lt;/h3&gt;

&lt;p&gt;It shouldn't be difficult to find help when I run into problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Encourages vanilla JavaScript
&lt;/h3&gt;

&lt;p&gt;I don't believe we need to "apologize" for JavaScript by covering it up with a bunch of duplicate functionality that bloats the code and adds more overhead to our learning. I'd rather spend more time in the wonderful &lt;a href="https://developer.mozilla.org/en-US/"&gt;MDN docs&lt;/a&gt; learning proper JavaScript.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interacts with other libraries easily
&lt;/h3&gt;

&lt;p&gt;There is an extremely rich ecosystem of JavaScript libraries out there to help with all kinds of stuff. We shouldn't be afraid to use them if they don't have a framework-specific implementation.&lt;/p&gt;

&lt;h4&gt;
  
  
  So, is there a framework that satisfies all of these requirements, and more?
&lt;/h4&gt;

&lt;p&gt;Well, yes, I believe there is! This would be a pretty unsatisfying article otherwise, wouldn't it?&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter Mithril
&lt;/h2&gt;

&lt;p&gt;For the last two years or so, I've quietly (or, sometimes not-so-quietly) been using Mithril in my day jobs where I had complete autonomy over the project at hand. I've used it to build tiny, internal company tools as well as a heavily-visited digital campus map for a university. I've used it both in the context of an existing PHP-rendered application without any sort of build chain, as well as a full-on single-page app with routing, ES6, hot-module reloading, and all that good stuff. It excels wonderfully in both scenarios, and it doesn't pressure anyone into a particular way of doing things.&lt;/p&gt;

&lt;p&gt;Okay, enough soliloquy. Let's dive into some code.&lt;/p&gt;

&lt;p&gt;This is basically the "Hello World" of Mithril:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"X-UA-Compatible"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"ie=edge"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdnjs.cloudflare.com/ajax/libs/mithril/2.0.4/mithril.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Hello, Dev!&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;h1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello, Dev!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;While this example may not be very flashy, it is impressive how little code is needed to instantiate Mithril and render something.&lt;/p&gt;

&lt;p&gt;Okay, let's try something a little bit more involved, if not quite common. Here is a todo list app, built with Mithril and Bulma. I'll attempt to demonstrate a complete implementation with as little code as possible:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/jcs224/embed/oNNvyYK?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;There is a bit of code for a simple todo list, but the implementation of Mithril-specific stuff is quite low, in my opinion. There are a couple of functions for generating random IDs and finding the index of an object in an array by ID. There is also a data model for storing the todos, as well as logic for adding, deleting, completing, and uncompleting the todos. The only Mithril-specific code involves the layout and rendering of the component, which constructs a virtual DOM that outputs to HTML (similar to most of the other current major frameworks).&lt;/p&gt;

&lt;p&gt;If you want to see an example of a Mithril app that I've built that's currently in production, check out the &lt;a href="https://www.montana.edu/campusmap/#!/"&gt;Montana State University digital campus map&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To sum it up, if you're happy with your existing front-end setup, just keep using that. No point switching from something you're comfortable with. But, if you are craving something a bit simpler, without giving up too many productivity benefits, I'll think you'll be quite delighted with it!&lt;/p&gt;

&lt;p&gt;In future posts, I'll go over some of the more advanced and nitty-gritty features of Mithril. And, if any of you have more questions about the framework, comment here or in the excellent &lt;a href="https://gitter.im/mithriljs/mithril.js"&gt;Mithril Gitter chatroom&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>mithril</category>
      <category>mithriljs</category>
    </item>
  </channel>
</rss>
