<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:polychrome="https://disusered.com/ns/polychrome"><channel><title>Carlos Antonio</title><description>Writing by Carlos Antonio</description><link>https://disusered.com/</link><item><title>Using TypeScript in Phoenix 1.7</title><link>https://disusered.com/blog/phoenix-with-typescript/</link><guid isPermaLink="true">https://disusered.com/blog/phoenix-with-typescript/</guid><description>My experience using TypeScript in Phoenix 1.7 using esbuild</description><pubDate>Wed, 27 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;table-of-contents&quot;&gt;Table of Contents&lt;a class=&quot;anchor-link&quot; href=&quot;#table-of-contents&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; fill=&quot;currentcolor&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span is:raw=&quot;&quot; class=&quot;sr-only&quot;&gt;Section titled Table of Contents&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#create-a-phoenix-17-project&quot;&gt;Create a Phoenix 1.7 project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#set-up-typescript&quot;&gt;Set up TypeScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#automatic-type-checking-with-watchers&quot;&gt;Automatic type checking with watchers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#fixing-typescript-errors&quot;&gt;Fixing TypeScript errors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#integrating-with-alpinejs&quot;&gt;Integrating with Alpine.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#typed-client-hooks&quot;&gt;Typed client hooks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#typed-client-server-communication&quot;&gt;Typed client-server communication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;a class=&quot;anchor-link&quot; href=&quot;#introduction&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; fill=&quot;currentcolor&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span is:raw=&quot;&quot; class=&quot;sr-only&quot;&gt;Section titled Introduction&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’ve been working with Phoenix 1.7 for a few months now using the default JavaScript setup, but as the complexity of the front-end has grown, I’ve been looking for ways to improve the developer experience. I’ve been using TypeScript for a few years now, and I’ve been very happy with it, so I decided to try to use TypeScript in my Phoenix project.&lt;/p&gt;
&lt;p&gt;Most of the information I found online was for older versions of Phoenix, so I decided to document my experience here. I will be using &lt;a href=&quot;https://esbuild.github.io/&quot;&gt;esbuild&lt;/a&gt; to transpile the TypeScript code to JavaScript and take advantage of the built-in tooling provided by the Phoenix Framework. I don’t want to radically change the build process, I only want add the developer ergonomics I am used to from years of front-end development.&lt;/p&gt;
&lt;p&gt;For this blog post, I will be starting with a fresh Phoenix 1.7 project. I also want to go beyond the typical “Hello World” example and show how to use TypeScript with &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html&quot;&gt;Phoenix LiveView&lt;/a&gt;. I will be using the &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/js-interop.html#phoenix_live_view_hooks&quot;&gt;Phoenix LiveView Hooks&lt;/a&gt; to add some interactivity to the page, as well as &lt;a href=&quot;https://alpinejs.dev/&quot;&gt;Alpine.js&lt;/a&gt; which is commonly used with Phoenix for client-side interactivity.&lt;/p&gt;
&lt;h2 id=&quot;create-a-phoenix-17-project&quot;&gt;Create a Phoenix 1.7 project&lt;a class=&quot;anchor-link&quot; href=&quot;#create-a-phoenix-17-project&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; fill=&quot;currentcolor&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span is:raw=&quot;&quot; class=&quot;sr-only&quot;&gt;Section titled Create a Phoenix 1.7 project&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To get started, let’s create a new Phoenix project by following Phoenix’s &lt;a href=&quot;https://hexdocs.pm/phoenix/up_and_running.html&quot;&gt;documentation for getting up and running&lt;/a&gt;. I will not cover installing Elixir, Node.js or the database, this assumes you have a fully capable environment.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; Upgrade Hex to latest version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;mix&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; local.hex&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; Install the Phoenix application generator&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;mix&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; archive.install&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; hex&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; phx_new&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; Bootstrap Phoenix&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;mix&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; phx.new&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; phoenix_typescript&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After accepting the defaults, we need to configure the database in &lt;code&gt;config/dev.exs&lt;/code&gt; and initialize the database. I will be using PostgreSQL, but you can use any database you want. I will be using Docker Compose to run PostgreSQL, but you can use any method you want. The following example will use the default values scaffolded by Phoenix, but you may want to change these values to match our environment.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; Go to the Phoenix directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EB6F92;font-style:italic&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; phoenix_typescript&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; Create a docker-compose file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;touch&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; docker-compose.yaml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can copy the following code into our &lt;code&gt;docker-compose.yaml&lt;/code&gt; file.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &quot;3.9&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;services&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;  db&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;    image&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; postgres:15.2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;    restart&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; always&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;    environment&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; POSTGRES_USER=postgres&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; POSTGRES_PASSWORD=postgres&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; POSTGRES_DB=phoenix_typescript_dev&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;    ports&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &quot;5432:5432&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;    volumes&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;      -&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; db:/var/lib/postgresql/data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;volumes&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;  db&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;    driver&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; local&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can start the database and run the creation and migration tasks.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; Start the database&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;docker-compose&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; up&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; Create the db and run the migrations&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;mix&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; ecto.create&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; Start the Phoenix server&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;mix&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; phx.server&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We now have a working Phoenix application! You can visit &lt;code&gt;http://localhost:4000&lt;/code&gt; from our browser to see the default Phoenix welcome page.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://disusered.com/assets/phoenix-with-typescript/phoenix-with-typescript-new-project.png&quot; alt=&quot;A screenshot of a new Phoenix project&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;set-up-typescript&quot;&gt;Set up TypeScript&lt;a class=&quot;anchor-link&quot; href=&quot;#set-up-typescript&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; fill=&quot;currentcolor&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span is:raw=&quot;&quot; class=&quot;sr-only&quot;&gt;Section titled Set up TypeScript&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now let’s take a look at the existing JavaScript setup. Phoenix uses &lt;a href=&quot;https://esbuild.github.io/&quot;&gt;esbuild&lt;/a&gt; to transpile and bundle the JavaScript code. The configuration is stored in &lt;code&gt;config/config.exs&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; Configure esbuild (the version is required)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;config &lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;esbuild&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;  version&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &quot;0.17.11&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;  default&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;    args&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;      ~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*)&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;    cd&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt; Path&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;expand&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;&quot;../assets&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt; __DIR__&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;    env&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; %&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;&quot;NODE_PATH&quot;&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt; Path&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;expand&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;&quot;../deps&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt; __DIR__&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;)}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can see that the bundler has certain options set, such as the target and output directory. All modern JavaScript syntax is supported by esbuild, but newer syntax might not be supported by certain browsers. By setting &lt;code&gt;--target=es2017&lt;/code&gt;, we tell esbuild to convert newer syntax to older syntax &lt;a href=&quot;https://esbuild.github.io/content-types/#javascript&quot;&gt;as appropriate&lt;/a&gt;. We can also see that the input file will be &lt;code&gt;app.js&lt;/code&gt;, when we migrate to TypeScript we will have to change this to &lt;code&gt;app.ts&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;esbuild supports TypeScript out of the box, so we don’t need to install any additional dependencies. We can rename &lt;code&gt;app.js&lt;/code&gt; to &lt;code&gt;app.ts&lt;/code&gt; and update the configuration to use &lt;code&gt;app.ts&lt;/code&gt; as the input file.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; Rename app.js to app.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;mv&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; assets/js/app.{js,ts}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;diff --git a/config/config.exs b/config/config.exs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;index 4eae6f7..aeffbb0 100644&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;--&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; a/config/config.exs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; b/config/config.exs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#C4A7E7&quot;&gt; -34,7 +34,7 &lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; config :esbuild,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;   version: &quot;0.17.11&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;   default: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;     args:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#EB6F92&quot;&gt;      ~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;      ~w(js/app.ts --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;     cd: Path.expand(&quot;../assets&quot;, __DIR__),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;     env: %{&quot;NODE_PATH&quot; =&gt; Path.expand(&quot;../deps&quot;, __DIR__)}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;   ]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Afterwards we can start the server and visit &lt;code&gt;http://localhost:4000&lt;/code&gt; to see the same welcome page as before. We can also see that the JavaScript code is still working as expected. This is because esbuild does handle TypeScript but &lt;a href=&quot;https://esbuild.github.io/content-types/#typescript&quot;&gt;does not handle any type checking itself&lt;/a&gt;, we still need to run &lt;code&gt;tsc --noEmit&lt;/code&gt; to handle type checking.&lt;/p&gt;
&lt;p&gt;In order to run &lt;code&gt;tsc&lt;/code&gt;, we need the TypesScript compiler. We can install it with &lt;code&gt;npm&lt;/code&gt; into our &lt;code&gt;assets&lt;/code&gt; directory. Before that, we want to initialize a &lt;code&gt;package.json&lt;/code&gt;. Then we want to save it as a development dependency &lt;code&gt;package.json&lt;/code&gt;. We can do this by running the following command:&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; Install TypeScript into our assets directory and save it as a dev dependency&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; --prefix&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; assets&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; typescript&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; --save-dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;package-lock.json&lt;/code&gt;file are created automatically, and we can see that &lt;code&gt;tsc&lt;/code&gt; is listed as a dev dependency.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;On&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; branch&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;Changes&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; be&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; committed:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &quot;git restore --staged &amp;#x3C;file&gt;...&quot;&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; unstage&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;        new&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; file:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;   assets/package-lock.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;        new&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; file:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;   assets/package.json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The content of the &lt;code&gt;package.json&lt;/code&gt; is very minimal, only listing our dev dependency.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;devDependencies&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;    &quot;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;typescript&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &quot;^5.2.2&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally we need to create a minimal TypeScript configuration file. esbuild does not require a &lt;code&gt;tsconfig.json&lt;/code&gt; file, but the TypeScript compiler does. We can create a minimal config file by running &lt;code&gt;npx --prefix assets tsc --init&lt;/code&gt; in our &lt;code&gt;assets&lt;/code&gt; directory.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; npx does not support the --prefix flag, so we need to cd into the assets directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EB6F92;font-style:italic&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; assets&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; Initialize a tsconfig.json file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;npx&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; tsc&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; --init&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; Return to the root directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EB6F92;font-style:italic&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; ..&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can leave all the values to their defaults except for the &lt;code&gt;target&lt;/code&gt; option. We want to set the &lt;code&gt;target&lt;/code&gt; to &lt;code&gt;es2017&lt;/code&gt; to match the target used by esbuild.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;diff --git a/assets/tsconfig.json b/assets/tsconfig.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;index e075f97..91776fc 100644&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;--&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; a/assets/tsconfig.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; b/assets/tsconfig.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#C4A7E7&quot;&gt; -11,7 +11,7 &lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;     // &quot;disableReferencedProjectLoad&quot;: true,             /* Reduce the number of projects loaded automatically by TypeScript. */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;     /* Language and Environment */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#EB6F92&quot;&gt;    &quot;target&quot;: &quot;es2016&quot;,                                  /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;    &quot;target&quot;: &quot;es2017&quot;,                                  /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;     // &quot;lib&quot;: [],                                        /* Specify a set of bundled library declaration files that describe the target runtime environment. */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;     // &quot;jsx&quot;: &quot;preserve&quot;,                                /* Specify what JSX code is generated. */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;     // &quot;experimentalDecorators&quot;: true,                   /* Enable experimental support for legacy experimental decorators. */&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Node.js, the &lt;code&gt;scripts&lt;/code&gt; section of the &lt;code&gt;package.json&lt;/code&gt; is &lt;a href=&quot;https://docs.npmjs.com/cli/v10/using-npm/scripts&quot;&gt;used to define scripts&lt;/a&gt; that can be run with &lt;code&gt;npm run &amp;#x3C;script&gt;&lt;/code&gt;. We can add a &lt;code&gt;typecheck&lt;/code&gt; script to run the TypeScript compiler.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;diff --git a/assets/package.json b/assets/package.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;index 04263dc..564a3fd 100644&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;--&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; a/assets/package.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; b/assets/package.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#C4A7E7&quot;&gt; -1,4 +1,7 &lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;  &quot;scripts&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;    &quot;typecheck&quot;: &quot;tsc --noEmit --pretty&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;   &quot;devDependencies&quot;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;     &quot;typescript&quot;: &quot;^5.2.2&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;   }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can run our &lt;code&gt;typecheck&lt;/code&gt; script to see the errors in our &lt;code&gt;app.ts&lt;/code&gt;. Remember to change the directory to the root Phoenix directory to run the following command, otherwise if we are in the &lt;code&gt;assets&lt;/code&gt; directory we can omit the &lt;code&gt;--prefix assets&lt;/code&gt; flag.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; Run the typecheck script&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; --prefix&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; assets&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; run&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; typecheck&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;automatic-type-checking-with-watchers&quot;&gt;Automatic type checking with watchers&lt;a class=&quot;anchor-link&quot; href=&quot;#automatic-type-checking-with-watchers&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; fill=&quot;currentcolor&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span is:raw=&quot;&quot; class=&quot;sr-only&quot;&gt;Section titled Automatic type checking with watchers&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We can add an alias to our Mix tasks to run the &lt;code&gt;typecheck&lt;/code&gt; script. This will allow us to run &lt;code&gt;mix assets.typecheck&lt;/code&gt; from our project root. We can add the following to our &lt;code&gt;mix.exs&lt;/code&gt; file under the &lt;code&gt;aliases&lt;/code&gt; function.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;diff --git a/mix.exs b/mix.exs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;index e7e6b2c..470decd 100644&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;--&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; a/mix.exs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; b/mix.exs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#C4A7E7&quot;&gt; -65,6 +65,7 &lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; defmodule PhoenixTypescript.MixProject do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;       &quot;ecto.setup&quot;: [&quot;ecto.create&quot;, &quot;ecto.migrate&quot;, &quot;run priv/repo/seeds.exs&quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;       &quot;ecto.reset&quot;: [&quot;ecto.drop&quot;, &quot;ecto.setup&quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;       test: [&quot;ecto.create --quiet&quot;, &quot;ecto.migrate --quiet&quot;, &quot;test&quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;      &quot;assets.typecheck&quot;: [&quot;cmd npm --prefix assets run typecheck&quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;       &quot;assets.setup&quot;: [&quot;tailwind.install --if-missing&quot;, &quot;esbuild.install --if-missing&quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;       &quot;assets.build&quot;: [&quot;tailwind default&quot;, &quot;esbuild default&quot;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;       &quot;assets.deploy&quot;: [&quot;tailwind default --minify&quot;, &quot;esbuild default --minify&quot;, &quot;phx.digest&quot;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This helps us run the type check manually, but we want to run the type check automatically when files are changed in the project. The only change we make to our &lt;code&gt;typecheck&lt;/code&gt; command is to pass the &lt;code&gt;--watch&lt;/code&gt; flag to &lt;code&gt;tsc&lt;/code&gt;. This will watch our files for changes and run the type check automatically. When passing arguments to a &lt;code&gt;package.json&lt;/code&gt; script, we need to prefix it with &lt;code&gt;--&lt;/code&gt; to separate the arguments for &lt;code&gt;npm&lt;/code&gt; and the arguments for the script.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; An example of running the typecheck script with the --watch flag&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; --prefix&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; assets&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; run&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; typecheck&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; --&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; --watch&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While that works, we want to run the type check automatically when we run &lt;code&gt;mix phx.server&lt;/code&gt;. We can do that by adding our typecheck watcher command to our &lt;code&gt;config/dev.exs&lt;/code&gt; file.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;diff --git a/config/dev.exs b/config/dev.exs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;index e702834..591530f 100644&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;--&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; a/config/dev.exs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; b/config/dev.exs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#C4A7E7&quot;&gt; -26,7 +26,8 &lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; config :phoenix_typescript, PhoenixTypescriptWeb.Endpoint,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;   secret_key_base: &quot;4s+TpGoGfPgA4CEogO+83S26CXea4zHcpcQCKY7mwytLB4W2OXidoDYSQeUUPEcD&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;   watchers: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;     esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#EB6F92&quot;&gt;    tailwind: {Tailwind, :install_and_run, [:default, ~w(--watch)]}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;    tailwind: {Tailwind, :install_and_run, [:default, ~w(--watch)]},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;    npm: [&quot;--prefix&quot;, &quot;assets&quot;, &quot;run&quot;, &quot;typecheck&quot;, &quot;--&quot;, &quot;--watch&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;   ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; # ## SSL Support&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now if we run &lt;code&gt;mix phx.server&lt;/code&gt; we can see that the type check is running in the background. If we make a change to &lt;code&gt;app.ts&lt;/code&gt; and save it, we can see that the type check runs automatically and the errors are displayed in the console. If we open the page in the browser, we can see that the JavaScript code is still working as expected. esbuild is not blocked by the type check, it will still bundle the JavaScript code and reload the page as expected.&lt;/p&gt;
&lt;h2 id=&quot;fixing-typescript-errors&quot;&gt;Fixing TypeScript errors&lt;a class=&quot;anchor-link&quot; href=&quot;#fixing-typescript-errors&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; fill=&quot;currentcolor&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span is:raw=&quot;&quot; class=&quot;sr-only&quot;&gt;Section titled Fixing TypeScript errors&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The first two errors we see in &lt;code&gt;app.ts&lt;/code&gt; are related to the type declarations for Phoenix and Phoenix Live View.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;js/app.ts:21:22&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; TS2307:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; Cannot&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; find&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; module&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &apos;phoenix&apos;&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; or&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; its&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; corresponding&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; declarations.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;21&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; import&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; {Socket}&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &quot;phoenix&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;                        ~~~~~~~~~&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;js/app.ts:22:26&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; TS2307:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; Cannot&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; find&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; module&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &apos;phoenix_live_view&apos;&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; or&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; its&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; corresponding&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; declarations.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;22&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; import&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; {LiveSocket}&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &quot;phoenix_live_view&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;                            ~~~~~~~~~~~~~~~~~~~&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since these libraries don’t ship their own type declarations, we need to look for them elsewhere. Fortunately, the &lt;a href=&quot;https://definitelytyped.github.io/&quot;&gt;DefinitelyTyped&lt;/a&gt; project has declarations for both of these libraries. We can install them with &lt;code&gt;npm&lt;/code&gt; as dev dependencies.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; Install type declarations to dev dependencies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; --prefix&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; assets&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; @types/phoenix&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; @types/phoenix_live_view&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; --save-dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this, the errors are gone. We can also see that our &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;package-lock.json&lt;/code&gt; have been updated with these dependencies. We can move on the the next error. We can see it is related to the &lt;code&gt;topbar&lt;/code&gt; library used to display a progress bar on the top of the screen.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;js/app.ts:14:20&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; TS7016:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; Could&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; not&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; find&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; a&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; declaration&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; file&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; module&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &apos;topbar&apos;.&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &apos;/Users/carlos/Development/landing/assets/node_modules/topbar/topbar.min.js&apos;&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; implicitly&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; has&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; an&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &apos;any&apos;&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; type.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;  Try&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; `&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;--save-dev&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; @types/topbar&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt; it&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; exists&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; or&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; a&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; declaration&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; (.d.ts) file containing &lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#EB6F92;font-style:italic&quot;&gt;declare&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; module &apos;topbar&apos;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;14&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; import&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; topbar&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &quot;topbar&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;                      ~~~~~~~~&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This library is loaded from the &lt;code&gt;assets/vendor/&lt;/code&gt; directory, and is part of the default Phoenix installation. Let’s remove this hard-coded library and fetch the latest version from NPM:&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; Remove the existing library file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;rm&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; assets/vendor/topbar.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; Install topbar from NPM&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; --prefix&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; assets&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; topbar&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; --save&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We also need to update the reference to the library in &lt;code&gt;app.ts&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;diff --git a/assets/js/app.ts b/assets/js/app.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;index df0cdd9..70c1398 100644&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;--&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; a/assets/js/app.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; b/assets/js/app.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#C4A7E7&quot;&gt; -20,7 +20,7 &lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; import &quot;phoenix_html&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; // Establish Phoenix Socket and LiveView configuration.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; import {Socket} from &quot;phoenix&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; import {LiveSocket} from &quot;phoenix_live_view&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#EB6F92&quot;&gt;import topbar from &quot;../vendor/topbar&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;import topbar from &quot;topbar&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; let csrfToken = document.querySelector(&quot;meta[name=&apos;csrf-token&apos;]&quot;).getAttribute(&quot;content&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; let liveSocket = new LiveSocket(&quot;/live&quot;, Socket, {params: {_csrf_token: csrfToken}})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can see that the error no longer appears in our type check. But why? It turns out the newer version of the library is already typed, so we don’t need to install any additional type declarations. We are now down to 2 errors, the next one being a null check:&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;js/app.ts:25:17&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; TS2531:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; is&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; possibly&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &apos;null&apos;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;25&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; csrfToken&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; document.querySelector&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;&quot;meta[name=&apos;csrf-token&apos;]&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;.getAttribute&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;&quot;content&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our script does not know if the &lt;code&gt;querySelector&lt;/code&gt; will return a value or not, so we need to check for &lt;code&gt;null&lt;/code&gt; before calling &lt;code&gt;getAttribute&lt;/code&gt;. We can fix this by adding a null check to the code. We’ll use the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining&quot;&gt;optional chaining operator&lt;/a&gt; to do this. This is an ES2020 feature, but thanks to esbuild with the &lt;code&gt;--target=es2017&lt;/code&gt; flag, we can use it without any additional configuration.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;diff --git a/assets/js/app.ts b/assets/js/app.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;index 70c1398..653efb4 100644&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;--&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; a/assets/js/app.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; b/assets/js/app.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#C4A7E7&quot;&gt; -22,7 +22,7 &lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; import {Socket} from &quot;phoenix&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; import {LiveSocket} from &quot;phoenix_live_view&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; import topbar from &quot;topbar&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#EB6F92&quot;&gt;let csrfToken = document.querySelector(&quot;meta[name=&apos;csrf-token&apos;]&quot;).getAttribute(&quot;content&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;let csrfToken = document.querySelector(&quot;meta[name=&apos;csrf-token&apos;]&quot;)?.getAttribute(&quot;content&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; let liveSocket = new LiveSocket(&quot;/live&quot;, Socket, {params: {_csrf_token: csrfToken}})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; // Show progress bar on live navigation and form submits&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We are down to the last error about the &lt;code&gt;liveSocket&lt;/code&gt; variable not existing in the global browser scope:&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;js/app.ts:44:8&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; TS2339:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; Property&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &apos;liveSocket&apos;&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; does&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; not&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; exist&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; on&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &apos;Window &amp;#x26; typeof globalThis&apos;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;44&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; window.liveSocket&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; liveSocket&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;          ~~~~~~~~~~&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To fix this, we will need to add a type declaration for the &lt;code&gt;liveSocket&lt;/code&gt; variable. We can do this by adding a &lt;code&gt;global.d.ts&lt;/code&gt; file to our &lt;code&gt;assets&lt;/code&gt; directory. This file will be automatically loaded by the TypeScript compiler, and we can add our type declaration to it.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; Create a global.d.ts file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;touch&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; assets/global.d.ts&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We now need to add the type declaration for the &lt;code&gt;liveSocket&lt;/code&gt; variable. We can do this by adding the following code to our &lt;code&gt;global.d.ts&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;import &lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt; LiveSocket&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; from &lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;&quot;phoenix_live_view&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;declare&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt; global&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;  interface&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt; Window&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97;font-style:italic&quot;&gt;    liveSocket&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt; LiveSocket&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can see that the error is gone, and we have a working TypeScript setup!&lt;/p&gt;
&lt;h2 id=&quot;integrating-with-alpinejs&quot;&gt;Integrating with Alpine.js&lt;a class=&quot;anchor-link&quot; href=&quot;#integrating-with-alpinejs&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; fill=&quot;currentcolor&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span is:raw=&quot;&quot; class=&quot;sr-only&quot;&gt;Section titled Integrating with Alpine.js&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;LiveView excels at interactivity that requires coordination with the backend, but we shouldn’t have to go to the server for purely client-side interactions. To that end, Alpine.js was developed to facilitate implementing client-side interactivity. It has been adopted as part of the &lt;a href=&quot;https://thinkingelixir.com/petal-stack-in-elixir/&quot;&gt;PETAL stack&lt;/a&gt;, composed of &lt;strong&gt;P&lt;/strong&gt;hoenix Framework, &lt;strong&gt;E&lt;/strong&gt;lixir, &lt;strong&gt;T&lt;/strong&gt;ailwind CSS, &lt;strong&gt;A&lt;/strong&gt;lpine.js, and &lt;strong&gt;L&lt;/strong&gt;iveView. The default Phoenix installation comes with everything except Alpine.js, so we need to install it ourselves.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; Install Alpine.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; --prefix&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; assets&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; alpinejs&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; --save&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; Install the type declarations&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; --prefix&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; assets&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; @types/alpinejs&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; --save-dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we need to initialize Alpine.js in our &lt;code&gt;app.ts&lt;/code&gt; file. Following the &lt;a href=&quot;https://alpinejs.dev/essentials/installation&quot;&gt;Alpine.js documentation&lt;/a&gt;, we add the following code to the end of our &lt;code&gt;app.ts&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;//&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; Import and initialize Alpine.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;import &lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;Alpine&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; from &lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;&quot;alpinejs&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;window&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;Alpine&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt; Alpine&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;Alpine&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While this works, we can see a type error from binding Alpine to the window. This is not strictly required for Alpine to function, but the docs recommend this approach to allow tinkering with Alpine from the browser developer tools during development.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;js/app.ts:48:8&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; TS2339:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; Property&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &apos;Alpine&apos;&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; does&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; not&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; exist&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; on&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &apos;Window &amp;#x26; typeof globalThis&apos;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;48&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; window.Alpine&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; Alpine&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;          ~~~~~~&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can fix this by adding a type declaration for the &lt;code&gt;Alpine&lt;/code&gt; variable in our &lt;code&gt;global.d.ts&lt;/code&gt; file.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;diff --git a/assets/global.d.ts b/assets/global.d.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;index 82143f6..def88aa 100644&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;--&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; a/assets/global.d.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; b/assets/global.d.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#C4A7E7&quot;&gt; -1,7 +1,9 &lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;import { Alpine } from &quot;alpinejs&quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; import { LiveSocket } from &quot;phoenix_live_view&quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; declare global {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;   interface Window {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;     liveSocket: LiveSocket;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;    Alpine: Alpine;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;   }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On a normal web server this would be enough to get started with Alpine.js, but we are using LiveView to render our page. LiveView uses &lt;a href=&quot;https://github.com/patrick-steele-idem/morphdom&quot;&gt;morphdom&lt;/a&gt; to update the DOM from the server. This means that Alpine.js will not be able to see the changes made by LiveView and Alpine.js will lose track on the elements its attached to. This can be fixed using the &lt;code&gt;onBeforeElUpdated&lt;/code&gt; liveSocket lifecycle hook to preserve the Alpine.js state.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;diff --git a/assets/js/app.ts b/assets/js/app.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;index e12f521..8221d5d 100644&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;--&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; a/assets/js/app.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; b/assets/js/app.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#C4A7E7&quot;&gt; -23,7 +23,13 &lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; import {LiveSocket} from &quot;phoenix_live_view&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; import topbar from &quot;topbar&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; let csrfToken = document.querySelector(&quot;meta[name=&apos;csrf-token&apos;]&quot;)?.getAttribute(&quot;content&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#EB6F92&quot;&gt;let liveSocket = new LiveSocket(&quot;/live&quot;, Socket, {params: {_csrf_token: csrfToken}})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;let liveSocket = new LiveSocket(&quot;/live&quot;, Socket, {params: {_csrf_token: csrfToken},   dom: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;    onBeforeElUpdated(from, to) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;      if (from._x_dataStack) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;        window.Alpine.clone(from, to)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;  }})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; // Show progress bar on live navigation and form submits&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; topbar.config({barColors: {0: &quot;#29d&quot;}, shadowColor: &quot;rgba(0, 0, 0, .3)&quot;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works great, but we can see that we have new errors in our type check:&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;js/app.ts:27:5&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; TS2322:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; Type&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &apos;(from: HTMLElement, to: HTMLElement) =&gt; void&apos;&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; is&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; not&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; assignable&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &apos;(fromEl: HTMLElement, toEl: HTMLElement) =&gt; boolean&apos;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;  Type&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &apos;void&apos;&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; is&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; not&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; assignable&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &apos;boolean&apos;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;27&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;     onBeforeElUpdated&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;from,&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;       ~~~~~~~~~~~~~~~~~&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;js/app.ts:28:16&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; TS2339:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; Property&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &apos;_x_dataStack&apos;&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; does&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; not&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; exist&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; on&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &apos;HTMLElement&apos;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;28&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;       if&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; (from._x_dataStack) &lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;                  ~~~~~~~~~~~~&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first error indicates that we need to return a boolean from the lifecycle hook rather than returning nothing (&lt;code&gt;void&lt;/code&gt;), so we can &lt;code&gt;return false&lt;/code&gt; to fix that error. For the following error, we can use one of the type declarations provided by &lt;code&gt;@types/alpinejs&lt;/code&gt; in order to create an &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/2/objects.html#intersection-types&quot;&gt;intersection type&lt;/a&gt; of &lt;code&gt;HTMLElement&lt;/code&gt; with Alpine.js’ augmentations. To do this, we would need to modify our &lt;code&gt;app.ts&lt;/code&gt; with the following:&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;diff --git a/assets/js/app.ts b/assets/js/app.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;index e12f521..e8b8468 100644&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;--&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; a/assets/js/app.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; b/assets/js/app.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#C4A7E7&quot;&gt; -23,7 +23,15 &lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; import {LiveSocket} from &quot;phoenix_live_view&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; import topbar from &quot;topbar&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; let csrfToken = document.querySelector(&quot;meta[name=&apos;csrf-token&apos;]&quot;)?.getAttribute(&quot;content&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#EB6F92&quot;&gt;let liveSocket = new LiveSocket(&quot;/live&quot;, Socket, {params: {_csrf_token: csrfToken}})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;let liveSocket = new LiveSocket(&quot;/live&quot;, Socket, {params: {_csrf_token: csrfToken},   dom: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;    onBeforeElUpdated(from, to) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;      const stack = (from as HTMLElement &amp;#x26; XAttributes)._x_dataStack;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;      if (stack) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;        Alpine.clone(from, to);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;      return false;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;  }})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; // Show progress bar on live navigation and form submits&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; topbar.config({barColors: {0: &quot;#29d&quot;}, shadowColor: &quot;rgba(0, 0, 0, .3)&quot;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#C4A7E7&quot;&gt; -40,6 +48,6 &lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; liveSocket.connect()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; window.liveSocket = liveSocket&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; // Import and initialize Alpine.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#EB6F92&quot;&gt;import Alpine from &quot;alpinejs&quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;import Alpine, { XAttributes } from &quot;alpinejs&quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; window.Alpine = Alpine;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; Alpine.start();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To finish up, we can add a simple Alpine.js component to our application and see it in action. Taking inspiration from the &lt;a href=&quot;https://alpinejs.dev/start-here&quot;&gt;Alpine.js documentation&lt;/a&gt;, we can add the following code to our home page template:&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;diff --git a/lib/phoenix_typescript_web/controllers/page_html/home.html.heex b/lib/phoenix_typescript_web/controllers/page_html/home.html.heex&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;index e9fc48d..358ab0c 100644&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;--&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; a/lib/phoenix_typescript_web/controllers/page_html/home.html.heex&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; b/lib/phoenix_typescript_web/controllers/page_html/home.html.heex&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#C4A7E7&quot;&gt; -46,8 +46,13 &lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;         fill=&quot;#FD4F00&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;       /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;     &amp;#x3C;/svg&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;     &amp;#x3C;h1 class=&quot;text-brand mt-10 flex items-center text-sm font-semibold leading-6&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#EB6F92&quot;&gt;      Phoenix Framework&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;      &amp;#x3C;span&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;        x-data=&quot;{ message: &apos;I &lt;span role=&quot;img&quot; aria-label=&quot;red heart&quot;&gt;❤️&lt;/span&gt;  Phoenix Framework with Alpine and TypeScript&apos; }&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;        x-text=&quot;message&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;      &gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;      &amp;#x3C;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;       &amp;#x3C;small class=&quot;bg-brand/5 text-[0.8125rem] ml-3 rounded-full px-2 font-medium leading-6&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;         v&amp;#x3C;%= Application.spec(:phoenix, :vsn) %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;       &amp;#x3C;/small&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If everything is working correctly, we should see the following:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://disusered.com/assets/phoenix-with-typescript/phoenix-with-typescript-finished.png&quot; alt=&quot;A screenshot of our Phoenix project with Alpine.js&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;typed-client-hooks&quot;&gt;Typed client hooks&lt;a class=&quot;anchor-link&quot; href=&quot;#typed-client-hooks&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; fill=&quot;currentcolor&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span is:raw=&quot;&quot; class=&quot;sr-only&quot;&gt;Section titled Typed client hooks&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/js-interop.html#client-hooks-via-phx-hook&quot;&gt;Client Hooks&lt;/a&gt; are a way for Phoenix to run client-side JavaScript when an element is added, updated, or removed by the server. For this, we need to add a &lt;code&gt;phx-hook&lt;/code&gt; attribute to the element, as well as a unique &lt;code&gt;id&lt;/code&gt;. For example, we can run a hook automatically on page load by adding the following to our &lt;code&gt;home.html.heex&lt;/code&gt; template:&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;diff --git a/lib/phoenix_typescript_web/controllers/page_html/home.html.heex b/lib/phoenix_typescript_web/controllers/page_html/home.html.heex&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;index 358ab0c..dcd7e3f 100644&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;--&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; a/lib/phoenix_typescript_web/controllers/page_html/home.html.heex&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; b/lib/phoenix_typescript_web/controllers/page_html/home.html.heex&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#C4A7E7&quot;&gt; -47,7 +47,11 &lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;       /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;     &amp;#x3C;/svg&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#EB6F92&quot;&gt;    &amp;#x3C;h1 class=&quot;text-brand mt-10 flex items-center text-sm font-semibold leading-6&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;    &amp;#x3C;h1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;      phx-hook=&quot;HomeHeader&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;      id=&quot;header&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;      class=&quot;text-brand mt-10 flex items-center text-sm font-semibold leading-6&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;    &gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;       &amp;#x3C;span&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;         x-data=&quot;{ message: &apos;I &lt;span role=&quot;img&quot; aria-label=&quot;red heart&quot;&gt;❤️&lt;/span&gt;  Phoenix Framework with Alpine and TypeScript&apos; }&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;         x-text=&quot;message&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When loading the home page of our Phoenix server, we’ll see… nothing&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;! That’s because we haven’t defined the hook yet. Let’s add it to our &lt;code&gt;app.ts&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;diff --git a/assets/js/app.ts b/assets/js/app.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;index e8b8468..13b58ad 100644&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;--&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; a/assets/js/app.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; b/assets/js/app.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#C4A7E7&quot;&gt; -22,8 +22,19 &lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; import {Socket} from &quot;phoenix&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; import {LiveSocket} from &quot;phoenix_live_view&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; import topbar from &quot;topbar&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;// Add example hook&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;const Hooks = {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;  HomeHeader: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;    mounted() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;      console.log(&quot;HomeHeader mounted on element: &quot;, this.el)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; let csrfToken = document.querySelector(&quot;meta[name=&apos;csrf-token&apos;]&quot;)?.getAttribute(&quot;content&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#EB6F92&quot;&gt;let liveSocket = new LiveSocket(&quot;/live&quot;, Socket, {params: {_csrf_token: csrfToken},   dom: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;let liveSocket = new LiveSocket(&quot;/live&quot;, Socket, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;  hooks: Hooks,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;  params: {_csrf_token: csrfToken},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;  dom: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;     onBeforeElUpdated(from, to) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;       const stack = (from as HTMLElement &amp;#x26; XAttributes)._x_dataStack;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;       if (stack) {&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While this works, we get a type error in our type check:&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;js/app.ts:29:59&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; TS2339:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; Property&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &apos;el&apos;&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; does&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; not&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; exist&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; on&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &apos;{ mounted(): void; }&apos;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;29&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;       console.log&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;&quot;HomeHeader mounted on element: &quot;&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; this.el&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;                                                             ~~&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can be fixed by using another type declaration from &lt;code&gt;@types/phoenix_live_view&lt;/code&gt; along with TypeScript’s &lt;code&gt;Partial&lt;/code&gt; utility type, which sets all properties of a type to optional. We can add the following to our &lt;code&gt;app.ts&lt;/code&gt; file to get rid of the error and have a fully typed hook&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;diff --git a/assets/js/app.ts b/assets/js/app.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;index fbccd94..9768e86 100644&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;--&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; a/assets/js/app.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; b/assets/js/app.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#C4A7E7&quot;&gt; -19,11 +19,11 &lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; import &quot;phoenix_html&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; // Establish Phoenix Socket and LiveView configuration.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; import {Socket} from &quot;phoenix&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#EB6F92&quot;&gt;import {LiveSocket} from &quot;phoenix_live_view&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;import {LiveSocket, ViewHook} from &quot;phoenix_live_view&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; import topbar from &quot;topbar&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; // Add example hook&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#EB6F92&quot;&gt;const Hooks = {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;const Hooks: { [name: string]: Partial&amp;#x3C;ViewHook&gt;} = {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;   HomeHeader: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;     mounted() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;       console.log(&quot;HomeHeader mounted on element: &quot;, this.el)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;typed-client-server-communication&quot;&gt;Typed client-server communication&lt;a class=&quot;anchor-link&quot; href=&quot;#typed-client-server-communication&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; fill=&quot;currentcolor&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span is:raw=&quot;&quot; class=&quot;sr-only&quot;&gt;Section titled Typed client-server communication&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The final issue I encountered when working with TypeScript was how to type events sent from Phoenix to the front-end through LiveView’s &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html#push_event/3&quot;&gt;push_event&lt;/a&gt;. Let’s add a route with a LiveView controller to our &lt;code&gt;router.ex&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;diff --git a/lib/phoenix_typescript_web/router.ex b/lib/phoenix_typescript_web/router.ex&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;index da82283..bbfea43 100644&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;--&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; a/lib/phoenix_typescript_web/router.ex&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; b/lib/phoenix_typescript_web/router.ex&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#C4A7E7&quot;&gt; -18,6 +18,7 &lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; defmodule PhoenixTypescriptWeb.Router do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;     pipe_through :browser&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;     get &quot;/&quot;, PageController, :home&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;    live &quot;/demo&quot;, DemoController&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;   end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;   # Other scopes may use custom stacks.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We also need to add the controller in &lt;code&gt;lib/phoenix_typescript_web/controllers/demo_controller.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;defmodule&lt;/span&gt;&lt;span style=&quot;color:#C4A7E7;font-style:italic&quot;&gt; PhoenixTypescriptWeb&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;DemoController&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;  use&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt; PhoenixTypescriptWeb&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;live_view&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;  def&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt; handle_event&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; _&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; socket&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;    {:&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;noreply&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;     socket&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;     |&gt;&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt; push_event&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;&quot;demo-event&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; %&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &quot;World&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;})}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;  def&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt; render&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;assigns&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;    ~H&quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E6A86&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;button&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C4A7E7;font-style:italic&quot;&gt;      type&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;&quot;button&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C4A7E7;font-style:italic&quot;&gt;      class&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;&quot;rounded-md bg-black px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C4A7E7;font-style:italic&quot;&gt;      phx-click&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E6A86&quot;&gt;    &gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;      Click me&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E6A86&quot;&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#6E6A86&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;    &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We also need to add the event listener in our &lt;code&gt;app.ts&lt;/code&gt; file, the following can be added to the end of the file:&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;//&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; Add handler for custom event&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;window&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;addEventListener&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;`phx:demo-event`&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#C4A7E7;font-style:italic&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;  console&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;`Hello &lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;detail&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we open the new route in our browser, we see our button and if we click on it can it works as expected:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://disusered.com/assets/phoenix-with-typescript/phoenix-with-typescript-button.png&quot; alt=&quot;A screenshot of the browser with the developer tools console showing our output&quot;&gt;&lt;/p&gt;
&lt;p&gt;This works, but we get a type error in our type check:&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;js/app.ts:72:26&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; error&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; TS2339:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; Property&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &apos;detail&apos;&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; does&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; not&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; exist&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; on&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &apos;Event&apos;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;72&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;   console.log&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;Hello&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; ${&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;detail&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;                            ~~~~~~&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Events handled by the front-end are of type &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent&quot;&gt;CustomEvent&lt;/a&gt; and are unique in that they are typed according to the event name. We can use this to our advantage by creating a type declaration for our event. We can add the following to our &lt;code&gt;global.d.ts&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;diff&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;diff --git a/assets/global.d.ts b/assets/global.d.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;index 71cae7a..09bfbb2 100644&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;-&lt;/span&gt;--&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; a/assets/global.d.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; b/assets/global.d.ts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#C4A7E7&quot;&gt; -6,4 +6,8 &lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;@@&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; declare global {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;     liveSocket: LiveSocket;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;     Alpine: Alpine;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;   }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;  interface WindowEventMap {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;    &quot;phx:demo-event&quot;: CustomEvent&amp;#x3C;{ name: string }&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;&lt;span style=&quot;user-select: none;&quot;&gt;+&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this declaration, we can see that the type error is gone and we have a fully typed client-server communication, including autocompletion in our IDE when accessing the &lt;code&gt;e.detail&lt;/code&gt; property.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;a class=&quot;anchor-link&quot; href=&quot;#conclusion&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; fill=&quot;currentcolor&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span is:raw=&quot;&quot; class=&quot;sr-only&quot;&gt;Section titled Conclusion&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I had to comb through many different sources to get this setup up and running, so I hope having it all in one place will help other Phoenix developers to get started with TypeScript in their projects. In a future post, I will cover how to deploy this setup to production. If you have any questions or suggestions, feel free to reach out to me on &lt;a href=&quot;https://twitter.com/disusered&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://tilde.zone/@disusered&quot;&gt;Mastodon&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;section data-footnotes=&quot;&quot; class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;a class=&quot;anchor-link&quot; href=&quot;#footnote-label&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; fill=&quot;currentcolor&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span is:raw=&quot;&quot; class=&quot;sr-only&quot;&gt;Section titled Footnotes&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;Nothing in the web page, but we will see an error in the console saying &lt;code&gt;unknown hook found for &quot;HomeHeader&quot;&lt;/code&gt; &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded><polychrome:hash>a9cdbc580ca116978430884fa967a218a4aab23c8ce7676ab2d7b6da0460335c</polychrome:hash><author>Carlos</author></item><item><title>Using Phaser with Astro</title><link>https://disusered.com/blog/playing-with-phaser/</link><guid isPermaLink="true">https://disusered.com/blog/playing-with-phaser/</guid><description>My attempt to use Phaser within an Astro blog using MDX</description><pubDate>Wed, 20 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve been toying with the idea of making a videogame for a long time, but was lacking motivation. I recently came across a thread by Brian Bucklew who documented his work in porting his &lt;a href=&quot;https://www.cavesofqud.com/&quot;&gt;Caves of Qud&lt;/a&gt; from Unity to &lt;a href=&quot;https://godotengine.org/&quot;&gt;Godot&lt;/a&gt;. The thread is a great read and I highly recommend it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://disusered.com/assets/playing-with-phaser/playing-with-phaser-tweet.png&quot; alt=&quot;Screenshot of Brian Bucklew&amp;#x27;s tweet about migrating to Godot&quot;&gt;&lt;/p&gt;
&lt;p&gt;After reading the thread, it seems I finally found that motivation as I jumped into learning Godot. I very quickly realized I didn’t want to learn a GDScript, so before investing more effort into Godot, I decided to try out &lt;a href=&quot;https://phaser.io/&quot;&gt;Phaser&lt;/a&gt;, a JavaScript game engine that runs on the web. I began going through the &lt;a href=&quot;https://phaser.io/learn&quot;&gt;official tutorial&lt;/a&gt; and the first steps include setting up a web server. I thought to myself, “I can do that in Astro!&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;” So I did.&lt;/p&gt;
&lt;p&gt;The first Astro-related issue I ran into is that the content folder for the blog has to be in Markdown or JSON. Fortunately, Astro supports &lt;a href=&quot;https://mdxjs.com/&quot;&gt;MDX&lt;/a&gt;, which is Markdown that can render JSX inline. I can even import components from the project and use them in my Markdown. So, I create an MDX file in my content directory and immediately realize there is no syntax highlighting for this filetype in Neovim.&lt;/p&gt;
&lt;p&gt;I search for a Treesitter grammar with no luck. I search online and find nothing, at most there are recommendations to &lt;code&gt;set filetype&lt;/code&gt; to JSX, but this would mean no language server features. I decided to write the MDX without syntax highlighting and develop the Phaser tutorial in a component file to import into the MDX file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;components/Phaser/HelloWorld.astro&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E6A86&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#C4A7E7;font-style:italic&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;&quot;wrapper&quot;&lt;/span&gt;&lt;span style=&quot;color:#6E6A86&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E6A86&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#C4A7E7;font-style:italic&quot;&gt; data-button&lt;/span&gt;&lt;span style=&quot;color:#6E6A86&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;Click Me!&lt;/span&gt;&lt;span style=&quot;color:#6E6A86&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#6E6A86&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E6A86&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#6E6A86&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E6A86&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#6E6A86&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;  // Find our component DOM on the page.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;  const button = document.querySelector(&quot;[data-button]&quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;  // Add event listeners to send alert when a button is clicked.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;  button.addEventListener(&quot;click&quot;, () =&gt; alert(&quot;You clicked the button &lt;span role=&quot;img&quot; aria-label=&quot;party popper&quot;&gt;🎉&lt;/span&gt;&quot;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E6A86&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#6E6A86&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;MDX&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;import &lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;HelloWorld&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; from &lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;&quot;../../components/Phaser/HelloWorld.astro&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E6A86&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;HelloWorld&lt;/span&gt;&lt;span style=&quot;color:#6E6A86&quot;&gt; /&gt;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;embed&quot;&gt;&lt;iframe src=&quot;https://disusered.com/demos/phaser/hello-world/&quot; title=&quot;https://disusered.com/demos/phaser/hello-world/&quot; sandbox=&quot;allow-scripts allow-same-origin allow-modals&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen style=&quot;width:100%;aspect-ratio:16/9;border:0&quot;&gt;&lt;/iframe&gt;&lt;figcaption&gt;&lt;a href=&quot;https://disusered.com/demos/phaser/hello-world/&quot;&gt;https://disusered.com/demos/phaser/hello-world/&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;By creating an &lt;code&gt;.astro&lt;/code&gt; file in my &lt;code&gt;components/&lt;/code&gt; directory, I am now able to load it into my MDX file and render it. I can even add styles and arbitrary HTML by using the Astro component syntax!&lt;/p&gt;
&lt;p&gt;On to using Phaser in MDX. The first issue I ran into was that the preload function was fetching from the Phaser asset library and couldn’t be loaded due to CORS restrictions. I decided to host the assets locally by downloading them to the &lt;code&gt;/public/&lt;/code&gt; folder. I’m not sure if there is a better way to do this, but it works for now.&lt;/p&gt;
&lt;p&gt;A second issue I encountered was that there was a console error when using the tutorial code as-is. It was a simple fix, thankfully the error was self-documenting. The particle emitter was changed since the tutorial was published.&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;//&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; Old&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt; particles&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0;font-style:italic&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;particles&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;&quot;red&quot;&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt; emitter&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt; particles&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;createEmitter&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;  speed&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;  scale&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; start&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; end&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;  blendMode&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &quot;ADD&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA;font-style:italic&quot;&gt;//&lt;/span&gt;&lt;span style=&quot;color:#6E6A86;font-style:italic&quot;&gt; New: https://github.com/photonstorm/phaser/issues/6476#issue-1669398672&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt; emitter&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0;font-style:italic&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;particles&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &quot;red&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;  speed&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;  scale&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; start&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; end&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;  blendMode&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &quot;ADD&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After addressing these issues, I was able to get the Phaser game to load inline successfully. I also tried to an &lt;a href=&quot;https://docs.astro.build/en/reference/directives-reference/#client-directives&quot;&gt;Astro client directive&lt;/a&gt; to load the scripts only when the client is idle, but this embeds the script as-is and I wouldn’t be able to use TypeScript, so I skipped it.&lt;/p&gt;
&lt;figure class=&quot;embed&quot;&gt;&lt;iframe src=&quot;https://disusered.com/demos/phaser/load-phaser/&quot; title=&quot;https://disusered.com/demos/phaser/load-phaser/&quot; sandbox=&quot;allow-scripts allow-same-origin allow-modals&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen style=&quot;width:100%;aspect-ratio:16/9;border:0&quot;&gt;&lt;/iframe&gt;&lt;figcaption&gt;&lt;a href=&quot;https://disusered.com/demos/phaser/load-phaser/&quot;&gt;https://disusered.com/demos/phaser/load-phaser/&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;All in all, I converted the tutorial to TypeScript, loaded the assets locally, fixed the particle emitter, loaded Phaser into a &lt;code&gt;&amp;#x3C;div&gt;&lt;/code&gt; tag and added some styles so it would fit on the page and not be too tall. The final source&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; for the tutorial:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;components/Phaser/LoadPhaser.astro&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;  import &lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;Phaser&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt; Types&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; }&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; from &lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;&quot;phaser&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt; gameConfig&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt; Types&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;Core&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;GameConfig&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;    type&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt; Phaser&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;AUTO&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;    width&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &quot;100%&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;    height&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt; 300&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;    parent&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &quot;phaser-1&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;    physics&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;      default&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &quot;arcade&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;      arcade&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;        gravity&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; y&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt; 200&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;      },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;    scene&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;      preload&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt; preload&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;      create&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt; create&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;  function&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt; preload&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0;font-style:italic&quot;&gt;    this&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;load&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;image&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;&quot;sky&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &quot;/phaser/assets/space3.png&quot;&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0;font-style:italic&quot;&gt;    this&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;load&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;image&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;&quot;logo&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &quot;/phaser/assets/phaser3-logo.png&quot;&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0;font-style:italic&quot;&gt;    this&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;load&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;image&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;&quot;red&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &quot;/phaser/assets/red.png&quot;&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;  function&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt; create&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0;font-style:italic&quot;&gt;    this&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;image&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;400&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt; 300&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &quot;sky&quot;&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt; emitter&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0;font-style:italic&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;particles&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &quot;red&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;      speed&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;      scale&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; start&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt; end&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;      blendMode&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &quot;ADD&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;    }&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt; logo&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0;font-style:italic&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;physics&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;image&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;400&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt; &quot;logo&quot;&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;    logo&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;setVelocity&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt; 200&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;    logo&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;setBounce&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;    logo&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;setCollideWorldBounds&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;    emitter&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;startFollow&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;logo&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt; game&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt; Phaser&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#EA9A97&quot;&gt;Game&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;gameConfig&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;MDX&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code rose-pine-moon&quot; style=&quot;background-color:#232136;color:#e0def4; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt;import &lt;/span&gt;&lt;span style=&quot;color:#E0DEF4;font-style:italic&quot;&gt;LoadPhaser&lt;/span&gt;&lt;span style=&quot;color:#3E8FB0&quot;&gt; from &lt;/span&gt;&lt;span style=&quot;color:#F6C177&quot;&gt;&quot;../../components/Phaser/LoadPhaser.astro&quot;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E6A86&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9CCFD8&quot;&gt;LoadPhaser&lt;/span&gt;&lt;span style=&quot;color:#6E6A86&quot;&gt; /&gt;&lt;/span&gt;&lt;span style=&quot;color:#908CAA&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’m looking forward to learning more about Phaser and continuing to document my progress on my blog. I also hope to find a follow-up tutorial that isn’t from 2018 and uses the latest Phaser API. I’m not sure what I’ll build with Phaser, but I’m sure I’ll find something fun to make.&lt;/p&gt;
&lt;hr&gt;
&lt;section data-footnotes=&quot;&quot; class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;a class=&quot;anchor-link&quot; href=&quot;#footnote-label&quot;&gt;&lt;span aria-hidden=&quot;true&quot; class=&quot;anchor-icon&quot;&gt;&lt;svg width=&quot;16&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; fill=&quot;currentcolor&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;&lt;span is:raw=&quot;&quot; class=&quot;sr-only&quot;&gt;Section titled Footnotes&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;This blog is built with &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt;, which was created by the folks behind Snowpack. Since Snowpack is now deprecated, Astro uses Vite under the hood. &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;The source for the entire blog is available on &lt;a href=&quot;https://github.com/disusered/blog&quot;&gt;GitHub&lt;/a&gt;. &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded><polychrome:hash>6fa72b6dd09040872878d71cb8182f26dfd8b94850261c0fe11543a9a14eb9b6</polychrome:hash><author>Carlos</author></item></channel></rss>