<?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>DEV Community: Matthias</title>
    <description>The latest articles on DEV Community by Matthias (@matthri).</description>
    <link>https://dev.to/matthri</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%2F110170%2Fc7c223d6-e7dd-4fc5-a303-889a8d770d0b.png</url>
      <title>DEV Community: Matthias</title>
      <link>https://dev.to/matthri</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/matthri"/>
    <language>en</language>
    <item>
      <title>Reduce the size of your NodeJS docker images by a multiple</title>
      <dc:creator>Matthias</dc:creator>
      <pubDate>Tue, 03 Aug 2021 17:42:10 +0000</pubDate>
      <link>https://dev.to/matthri/reduce-the-size-of-your-nodejs-docker-images-by-a-multiple-5a75</link>
      <guid>https://dev.to/matthri/reduce-the-size-of-your-nodejs-docker-images-by-a-multiple-5a75</guid>
      <description>&lt;p&gt;Cover image by &lt;a href="https://unsplash.com/@carrier_lost?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Ian Taylor&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/docker?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Docker is a great tool to quickly generate and deploy containers for your NodeJS application to different platforms. But if you have checked the size of your final container image, you may have noticed that the image can get pretty heavy. Several hundred MB up to over one GB are not uncommon.&lt;/p&gt;

&lt;p&gt;This memory size can lead to different problems. First of all, your docker images will consume a lot of disk space on your machine. The second problem is that downloading the image from a registry like docker hub can take quite some time, depending on your network connection. This problem gets even worse for uploading your image since your upload bandwidth is usually multiple times smaller than your upload bandwidth. &lt;br&gt;
As you can see, there are many reasons to keep your docker images as small as possible. In this article, I will show you how to reduce the size of your docker images using different techniques. &lt;/p&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;For this tutorial, you will need to have the following programs installed on your machine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/en/"&gt;NodeJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.docker.com"&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;We will use a basic &lt;a href="https://adonisjs.com"&gt;AdonisJS&lt;/a&gt; app for this article and package it inside a docker image.&lt;br&gt;
First of all, we create the AdonisJS app running the following command and answering the prompts. As for the project structure, we will select the &lt;code&gt;web&lt;/code&gt; project structure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init adonis-ts-app@latest hello-docker-world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we can go to the &lt;code&gt;hello-docker-world&lt;/code&gt; directory and test our new app by running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node ace serve &lt;span class="nt"&gt;--watch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, you can open &lt;code&gt;localhost:3333&lt;/code&gt; in your favorite browser and should see your new test application. &lt;/p&gt;

&lt;p&gt;Now we can start packaging our application into a docker image. Therefore, we first create a new file called &lt;code&gt;Dockerfile&lt;/code&gt; inside our project directory and paste the following snippet into the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:14&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /myapp&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; node ace build &lt;span class="nt"&gt;--production&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; node build/server.js&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will pull the node base image from the docker registry, change the working directory to &lt;code&gt;/myapp&lt;/code&gt;, and copies the content of your local project directory to the image working directory. After that, it will run &lt;code&gt;npm insall&lt;/code&gt; to install the project dependencies and build the app for production. When the container image gets executed, the &lt;code&gt;CMD&lt;/code&gt; command will be executed inside the container, starting our webserver. &lt;/p&gt;

&lt;p&gt;Now that we know what the Dockerfile does, it's time to build our image. Therefore we execute the following command inside our project directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; adonisjs:full &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will look up the instructions from the dockerfile in the project directory, build the image based on the instructions, and tag the resulting image as &lt;code&gt;adonisjs:full&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After that, you can list your images by executing&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker image &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and you will see your newly created image with its size. In my case, it was 1.13 GB which is quite heavy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;REPOSITORY    TAG           IMAGE ID       CREATED         SIZE
adonisjs      full          8c35e9442e40   2 minutes ago   1.13GB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is because the &lt;code&gt;node:14&lt;/code&gt; is based on Debian stretch whit a lot of packages, resulting in the given image size. &lt;/p&gt;

&lt;p&gt;One approach in reducing the size of our docker image is instead of using the node:14 stretch image using the node:14-alpine base image. This image is based on Alpine Linux, a minimal Linux and much smaller than other base images.&lt;/p&gt;

&lt;p&gt;To use the new base image, we update our &lt;code&gt;Dockerfile&lt;/code&gt; with the following snippet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:14-alpine&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /myapp&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; node ace build &lt;span class="nt"&gt;--production&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; node build/server.js&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, we run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; adonisjs:alpine &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which will again build an image from our project but this time based on the Alpine base image and tag it &lt;code&gt;adonisjs:alpine&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When you now list your docker images using &lt;code&gt;docker image ls&lt;/code&gt;, you will see your new image, which is much smaller than the first image. In my case, the new image has only 303MB, which is less than a third of the previous image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;REPOSITORY    TAG           IMAGE ID       CREATED         SIZE
adonisjs      full          8c35e9442e40   2 minutes ago   1.13GB
adonisjs      alpine        43e7a8874973   4 minutes ago   303MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But we can get the image even smaller and save more space with the following approach. &lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-stage builds
&lt;/h2&gt;

&lt;p&gt;At the moment, the entire content of your project folder is copied inside the image, and the project dependencies are installed. After that, your image contains all project related files, but not all of them are needed for production. For example, you won't need your source files, and also your dev-dependencies don't have to be included in your production image. &lt;/p&gt;

&lt;p&gt;To solve this problem, you can use multi-stage builds. First, we will again update our &lt;code&gt;Dockerfile&lt;/code&gt; using the following snippet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:14-alpine AS build&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /myapp&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; node ace build &lt;span class="nt"&gt;--production&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:14-alpine&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /myapp/build /build&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; node build/server.js&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, this will use the &lt;code&gt;node:14-alpine&lt;/code&gt; image as base image but name it as &lt;code&gt;build&lt;/code&gt;. As in the previous steps, we will copy and build our application but won't finish after these steps. As you can see, after building the application, we use a fresh base image and copy only the generated build directory from our previous &lt;code&gt;build&lt;/code&gt; image to the new image, which will become our new production image. &lt;/p&gt;

&lt;p&gt;Using this approach, we can have a full build environment with all necessary dependencies. Still, when it comes to shipping the production image, we can use a minimal base image and only the generated files we need for executing our application.&lt;/p&gt;

&lt;p&gt;Now you can again build and tag your image using the following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; adonisjs:multistage &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and list all your images by executing &lt;code&gt;docker image ls&lt;/code&gt;. &lt;br&gt;
You can see, the size of the resulting image decreased again, in my case, by almost a third to 117MB.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;REPOSITORY    TAG           IMAGE ID       CREATED         SIZE
adonisjs      full          8c35e9442e40   2 minutes ago   1.13GB
adonisjs      alpine        43e7a8874973   4 minutes ago   303MB
adonisjs      multistage    6f91568fbe8f   6 minutes ago   117MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, multi-stage builds helped us to decrease the size of our final docker image by almost ten times, which will save a lot of resources and time while storing or up-/ downloading the image.&lt;/p&gt;

&lt;p&gt;If you want to read more about multistage-builds, see the official docker documentation &lt;a href="https://docs.docker.com/develop/develop-images/multistage-build/"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope you enjoyed the article and happy coding 🧑‍💻&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>docker</category>
    </item>
    <item>
      <title>Create your own iOS widget with JavaScript</title>
      <dc:creator>Matthias</dc:creator>
      <pubDate>Tue, 26 Jan 2021 15:58:28 +0000</pubDate>
      <link>https://dev.to/matthri/create-your-own-ios-widget-with-javascript-5a11</link>
      <guid>https://dev.to/matthri/create-your-own-ios-widget-with-javascript-5a11</guid>
      <description>&lt;h1&gt;
  
  
  What we will build
&lt;/h1&gt;

&lt;p&gt;We will create our own iOS widget with pure JavaScript. To achieve this, we will use a great app called Scriptable. With Scriptable, you can create JavaScript scripts and run them on your iOS device. You can use these scripts to automate different things on your device and also display the script in an iOS home screen widget.&lt;br&gt;
The main goal of this tutorial is to provide a starting guide for creating Scriptable widgets. Therefore we will build a simple widget to learn the basics and some useful tricks for building Scriptable widgets. The created widget will display the next scheduled launch date of SpaceX, as shown in the image below.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6wclinxt7echdgg93fp3.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6wclinxt7echdgg93fp3.jpeg" alt="iOS home screen with widget"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Prerequisites
&lt;/h1&gt;

&lt;p&gt;Some basic knowledge of JavaScript will be helpful but is not necessary. As previously mentioned, we use the &lt;a href="https://scriptable.app" rel="noopener noreferrer"&gt;Scriptable&lt;/a&gt; app for creating our widget, so you have to install it on your device.&lt;br&gt;
For easier development and testing on macOS, I recommend the &lt;a href="https://scriptable.app/mac-beta/" rel="noopener noreferrer"&gt;Scriptable desktop app&lt;/a&gt; (beta).&lt;br&gt;
An alternative is syncing your scripts using iCloud and edit the Scripts inside the iCloud folder on your desktop, which should also work on other operating systems. This allows you to edit the script in your favorite text editor and test it on your iOS device. &lt;/p&gt;
&lt;h1&gt;
  
  
  Creating the widget
&lt;/h1&gt;

&lt;p&gt;Now we are all set up to start creating our widget.&lt;br&gt;
First of all, create a new empty script and add the following snippet.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createWidget&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Create new empty ListWidget instance&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;listwidget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ListWidget&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Return the created widget&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;listwidget&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;widget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createWidget&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Check where the script is running&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;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runsInWidget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Runs inside a widget so add it to the homescreen widget&lt;/span&gt;
  &lt;span class="nx"&gt;Script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Show the medium widget inside the app&lt;/span&gt;
  &lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;presentMedium&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;Script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;


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

&lt;/div&gt;
&lt;p&gt;This snippet adds a new function for creating and returning a new widget instance. In the next step, the widget will be created and set if the script is executed inside a home screen widget. If the script runs inside the Scriptable app, it will display a preview of the widget.&lt;br&gt;
The preview is handy because the widgets don't refresh immediately. In contrast, the preview is always up to date when you run the script.&lt;br&gt;
If you run the script inside the app, you should now see an empty white square. 🎉🎉&lt;/p&gt;
&lt;h1&gt;
  
  
  Adding Content
&lt;/h1&gt;

&lt;p&gt;Now that we can run a basic widget, let's add some content. The widget layout is based on stacks that hold the different displayed elements. The stacks can be nested into each other. By default, a ListWidget stacks its content vertically, which can be changed if you want it. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip #1&lt;/strong&gt;&lt;br&gt;
When you want to debug more complex layouts, add a colored border to your elements so you can easily detect its size and position. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First we will set the background color and after that we add some heading to our widget and give it some styling. Therefore paste the following snippet inside the &lt;code&gt;createWidget()&lt;/code&gt; method after the &lt;code&gt;new ListWidget();&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

  &lt;span class="c1"&gt;// Set new background color&lt;/span&gt;
  &lt;span class="nx"&gt;listwidget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;backgroundColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Add widget heading&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;heading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;listwidget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🚀Next🚀&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;centerAlignText&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;font&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Font&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lightSystemFont&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#ffffff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Spacer between heading and launch date&lt;/span&gt;
  &lt;span class="nx"&gt;listwidget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addSpacer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


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

&lt;/div&gt;
&lt;p&gt;To set the background color, we set the &lt;code&gt;backgroundColor&lt;/code&gt; property of the created list widget instance. We assign a new color with the hex value &lt;code&gt;#000000&lt;/code&gt;, which will give us a black background.&lt;br&gt;
After that, we add a new text to our widget and save it in the heading variable. Using the variable, we can now access the added text and give it some styling. In our case, we will align the text center, change the default font and give it a white text color. If you are interested in the different options for the text and the other supported fonts, please visit the &lt;a href="https://docs.scriptable.app/widgettext/" rel="noopener noreferrer"&gt;WidgetText&lt;/a&gt; and the &lt;a href="https://docs.scriptable.app/font/" rel="noopener noreferrer"&gt;Font&lt;/a&gt; documentation of scriptable. &lt;br&gt;
Lastly, we add some spacing between our created heading and the next element, which will be our launch date. &lt;/p&gt;
&lt;h1&gt;
  
  
  Getting the data
&lt;/h1&gt;

&lt;p&gt;To display the next scheduled launch date, we have to fetch our data from the API. Therefore we will use the following API &lt;a href="https://github.com/r-spacex/SpaceX-API/blob/master/docs/v4/README.md" rel="noopener noreferrer"&gt;Documentation spacexdata.com API&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Sidenote&lt;/strong&gt; ⚠️&lt;br&gt;
If you use an API that requires an API key or secret, never share your script with the key inside.  Every other person could use the API with your access if the key gets public, e.g. on GitHub. Always store the key in a variable at the beginning of your script to easily find and remove it before sharing. Even better, don't hard code the key and instead pass it as an &lt;a href="https://docs.scriptable.app/args/" rel="noopener noreferrer"&gt;argument&lt;/a&gt; to your script.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To fetch the data from the api we will add the following two new functions to our script. &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getNextLaunch&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Query url&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.spacexdata.com/v4/launches/next&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Initialize new request&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Execute the request and parse the response as json&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadJSON&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Return the returned launch data&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getLaunchDateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;launchData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Parse launch date to new date object&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;launchDateTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;launchData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date_utc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;launchDateTime&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;p&gt;The first function sends a request to the specified URL and parses the response as JSON, which will then be returned. The second function is just a little helper that will extract the date string from the provided dataset and return it as a date object.&lt;br&gt;
Now we can call the previously defined functions inside &lt;code&gt;createWidtet()&lt;/code&gt; to fetch the data from the api and get the launch date. Therefore simply add the following lines inside the &lt;code&gt;createWidtet()&lt;/code&gt; function after the &lt;code&gt;listwidget.addSpacer()&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

  &lt;span class="c1"&gt;// Fetch next launch date&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;launch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getNextLaunch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;launchDateTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getLaunchDateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


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

&lt;/div&gt;
&lt;h1&gt;
  
  
  Displaying the fetched data
&lt;/h1&gt;

&lt;p&gt;Now that we have fetched our API data, we need to display it inside our widget. To achieve this, we create two new functions that will add our text to the widget and apply some basic formatting to it. &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;function&lt;/span&gt; &lt;span class="nf"&gt;addDateText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;dateText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;dateText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;centerAlignText&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;dateText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;font&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Font&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;semiboldSystemFont&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;dateText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#ffffff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;displayLaunchDateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;launchDateTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;precision&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Check if next launch date is precise enough and display different details based on the precision&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;precision&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hour&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Add launch date&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dateOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;year&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;numeric&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;month&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2-digit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;day&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2-digit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;datestring&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;launchDateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleDateString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dateOptions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;addDateText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;datestring&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Add launch time&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timeOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;numeric&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;minute&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;numeric&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;timestring&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;launchDateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleTimeString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;timeOptions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;addDateText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;timestring&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;precision&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;day&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Add launch date&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dateOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;year&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;numeric&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;month&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2-digit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;day&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2-digit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;datestring&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;launchDateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleDateString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dateOptions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;addDateText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;datestring&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;addDateText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No day for next launch given&lt;/span&gt;&lt;span class="dl"&gt;"&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;p&gt;The &lt;code&gt;addDateText()&lt;/code&gt; function gets an instance to which the function should add the text and a string that holds the text which should be displayed. After that, the function adds the given text to the given stack and applies some styling to the element.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip #2&lt;/strong&gt;&lt;br&gt;
If you want to display some text with a variable length, you can add a &lt;code&gt;minimumScaleFactor()&lt;/code&gt; between 0 and 1 to the text. This specifies the amount the text will scale down to fit inside the widget.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;displayLaunchDateTime()&lt;/code&gt; function is a bit more complex. It gets the instance to which the text should be added, the DateTime instance which should be displayed, and a precision parameter. The precision is sent with the API response of the next launch. It determines how precisely the launch time is known, which we will use to decide if we only display the day or also the time of the launch.&lt;br&gt;
Inside the &lt;code&gt;displayLaunchTime()&lt;/code&gt; function, we check the given precision. Based on that, we apply the correct format to our Date instance and add it to the stack by calling &lt;code&gt;addDateText()&lt;/code&gt;. If the next launch date is not known precisely enough, we display a message that the next launch day isn't known yet. &lt;/p&gt;

&lt;p&gt;Now inside our &lt;code&gt;createWidget()&lt;/code&gt; function we can call the &lt;code&gt;displayLaunchDateTime()&lt;/code&gt; function and pass our listwidget instance, the created date and the precision from the API response to display the data. The final &lt;code&gt;createWidget&lt;/code&gt; function is shown below.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createWidget&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Create new empty ListWidget instance&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;listwidget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ListWidget&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Set new background color&lt;/span&gt;
  &lt;span class="nx"&gt;listwidget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;backgroundColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#000000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Add widget heading&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;heading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;listwidget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🚀Next🚀&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;centerAlignText&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;font&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Font&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lightSystemFont&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#ffffff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Spacer between heading and launch date&lt;/span&gt;
  &lt;span class="nx"&gt;listwidget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addSpacer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Fetch next launch date&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;launch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getNextLaunch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;launchDateTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getLaunchDateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Add the launch time to the widget&lt;/span&gt;
  &lt;span class="nf"&gt;displayLaunchDateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;listwidget&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;launchDateTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date_precision&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Return the created widget&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;listwidget&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;h1&gt;
  
  
  Add it to your home screen
&lt;/h1&gt;

&lt;p&gt;To display the widget on your home screen, you need to create the script inside the Scriptable app (you can find the final script in the Gist below). After that, add a new small Scriptable widget to your home screen, which should give you an empty widget. Now you can long-press the widget, edit the widget and select your created script in the widget configuration. &lt;br&gt;
That's it you should now see your created widget on your screen. 🚀🚀&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this little tutorial. Feel free to write to me if you encounter any issues or want to suggest some additional topics about which I should make a tutorial.&lt;/p&gt;

&lt;p&gt;Happy coding 👨🏼‍💻 &lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


</description>
      <category>javascript</category>
      <category>showdev</category>
      <category>ios</category>
    </item>
    <item>
      <title>Unofficial dev.to iOS widget</title>
      <dc:creator>Matthias</dc:creator>
      <pubDate>Sun, 27 Dec 2020 18:49:46 +0000</pubDate>
      <link>https://dev.to/matthri/unofficial-dev-to-ios-widget-4cpo</link>
      <guid>https://dev.to/matthri/unofficial-dev-to-ios-widget-4cpo</guid>
      <description>&lt;p&gt;Since version 14 iOS supports different home screen widgets which can display different useful information for your installed apps. &lt;br&gt;
Wouldn't it be cool if you can create your own widgets to display some custom information? Good news, with the great &lt;a href="https://scriptable.app" rel="noopener noreferrer"&gt;Scriptable&lt;/a&gt; iOS app you can create your own scripts and widgets for iOS using pure javascript. &lt;/p&gt;
&lt;h1&gt;
  
  
  The widget 📱
&lt;/h1&gt;

&lt;p&gt;Reading some dev.to articles are an integral part of my daily routine, so I thought wouldn't it be cool if I get a random article directly on my home screen. &lt;/p&gt;

&lt;p&gt;So I made a little script which fetches a random article out of the top ten articles of the day on dev.to based on the tags I have subscribed to.&lt;br&gt;
After that, the article details like title, author, profile image and tags are displayed in a medium-sized widget. You can see the final widget in the following image.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Facn7a8kbcyvc24s5nlm1.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Facn7a8kbcyvc24s5nlm1.jpeg" alt="unofficial dev.to widget"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Get the widget 🚀
&lt;/h1&gt;

&lt;p&gt;If you want the widget on your home screen you will need to download the &lt;a href="https://scriptable.app" rel="noopener noreferrer"&gt;Scriptable&lt;/a&gt; iOS on your device. After that, you can create a new script inside the app and copy and paste the code from the following gist into your created script. &lt;/p&gt;

&lt;p&gt;To fetch the dev.to articles you need to generate an API key in your dev.to settings and paste it at the beginning of the created script.&lt;br&gt;
Now you can preview the widget by starting the script inside the Scriptable app. &lt;/p&gt;

&lt;p&gt;Finally, you can add the widget to your home screen by adding a medium-sized Scriptable widget, after that you can configure the widget by long-pressing the empty widget and then choose the newly created script in the widget configuration.&lt;/p&gt;

&lt;p&gt;I hope you like my widget, feel free to write to me if you encounter any issues or want to suggest some improvements.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


</description>
      <category>showdev</category>
      <category>javascript</category>
      <category>ios</category>
    </item>
  </channel>
</rss>
