<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Fredrik Burmester on Medium]]></title>
        <description><![CDATA[Stories by Fredrik Burmester on Medium]]></description>
        <link>https://medium.com/@fredrik.burmester?source=rss-802eda068bb4------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*cQVIIOBlZYYPWf6G</url>
            <title>Stories by Fredrik Burmester on Medium</title>
            <link>https://medium.com/@fredrik.burmester?source=rss-802eda068bb4------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 31 May 2026 19:57:50 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@fredrik.burmester/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Bottom Tab Navigation in Expo Router 3 (SDK 50) with Authentication]]></title>
            <link>https://medium.com/@fredrik.burmester/bottom-tab-navigation-in-expo-router-3-sdk-50-with-authentication-b8d4529b2e0f?source=rss-802eda068bb4------2</link>
            <guid isPermaLink="false">https://medium.com/p/b8d4529b2e0f</guid>
            <category><![CDATA[react-native]]></category>
            <category><![CDATA[nativewind]]></category>
            <category><![CDATA[expo-router]]></category>
            <category><![CDATA[expo]]></category>
            <category><![CDATA[authentication]]></category>
            <dc:creator><![CDATA[Fredrik Burmester]]></dc:creator>
            <pubDate>Fri, 01 Mar 2024 14:14:18 GMT</pubDate>
            <atom:updated>2024-03-01T14:14:18.144Z</atom:updated>
            <content:encoded><![CDATA[<p>Since my <a href="https://medium.com/@fredrik.burmester/bottom-tabs-in-expo-router-with-authentication-acf7f7edee6d">last article</a> about how to create a tab router in Expo did so well, I thought I’d create an updated version. This version uses Expo Router v3 and Expo SDK 50.</p><p>I will keep this short, since you can see the <a href="https://github.com/fredrikburmester/expo-router-3-tab-example-with-auth"><strong>fully working code on Github here</strong></a>, and there are not that many changes since the last version.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*HyFDbBO79xGj7_ux.png" /><figcaption>Expo SDK 50</figcaption></figure><h3>Updates</h3><p><strong>The main difference is the file structure.</strong> In the previous version we only protected our routes by using a hook in our auth provider, but swiping back from the home page took you back to the login page, sometimes creating weird edge cases.</p><p>Now we use this file structure. The two folders (auth) and (public) helps us keep the authenticated paths protected.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/370/1*HGw9gDAYoI-s4agKRXV70g.png" /></figure><p>This means that our AuthProvider now has this logic for protecting our routes:</p><pre>function useProtectedRoute(user: User | null) {<br>  const segments = useSegments();<br><br>  useEffect(() =&gt; {<br>    const inAuthGroup = segments[0] === &quot;(auth)&quot;;<br><br>    console.log(inAuthGroup);<br><br>    if (!user &amp;&amp; inAuthGroup) {<br>      router.replace(&quot;/login&quot;);<br>    } else if (user &amp;&amp; !inAuthGroup) {<br>      router.replace(&quot;/(auth)/(tabs)/&quot;);<br>    }<br>  }, [user, segments]);<br>}</pre><p>Here’s is video on the finished results:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*mau2ovYAl6_DVRO8NJ4J6w.gif" /><figcaption>Finished results</figcaption></figure><h3>Conclusion</h3><p>There you have it! Again, a super easy way to get a tab router in Expo Router v3 (Expo SDK 50). I’ve also thrown in Nativewind (tailwind) for styling.</p><p>Don’t forget to check out the <a href="https://github.com/fredrikburmester/expo-router-3-tab-example-with-auth"><strong>repo on Github</strong></a>.</p><p>Hope this helps!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b8d4529b2e0f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Bottom Tabs in Expo Router with authentication]]></title>
            <link>https://medium.com/@fredrik.burmester/bottom-tabs-in-expo-router-with-authentication-acf7f7edee6d?source=rss-802eda068bb4------2</link>
            <guid isPermaLink="false">https://medium.com/p/acf7f7edee6d</guid>
            <category><![CDATA[react-native]]></category>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[expo]]></category>
            <category><![CDATA[authentication]]></category>
            <dc:creator><![CDATA[Fredrik Burmester]]></dc:creator>
            <pubDate>Mon, 12 Jun 2023 17:32:20 GMT</pubDate>
            <atom:updated>2024-03-01T14:16:05.095Z</atom:updated>
            <content:encoded><![CDATA[<h3>Bottom tab navigation in Expo Router with authentication</h3><p>⚠️ Check out the new and improved Expo router v3 version: <a href="https://medium.com/@fredrik.burmester/bottom-tab-navigation-in-expo-router-3-sdk-50-with-authentication-b8d4529b2e0f">https://medium.com/@fredrik.burmester/bottom-tab-navigation-in-expo-router-3-sdk-50-with-authentication-b8d4529b2e0f</a></p><h3>Introduction</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/562/1*ZhEeMNHbuBbsusFNWk8AaA.png" /></figure><p>In this tutorial, I will guide you through the process of setting up a bottom tab router using Expo Router, incorporating authentication routes and stack navigation. By the end, you’ll understand how to structure your files, create a tab router, and integrate authentication and stack routes. <strong>Check out the bottom of the article for a link to my git repo with a fully working example.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*4e0C7v4bxnzPSIt_GasX9g.gif" /><figcaption>Demo</figcaption></figure><h3><strong>Step 1: </strong>File Structure</h3><p>To get started, let’s organize our project’s file structure. Within the “app” folder, we will create two main groups: “auth” and “tabs”. Additionally, we’ll create two layout files and include all the desired tabs within the “tabs” group.</p><p>Inside the auth group, we create a single login file.</p><p>The other file routes can be whatever you want and will act as stacks, stacking on top of our tab navigation. If you instead want to navigate within the tabs navigation, you can nest navigations within the “tabs” folder.</p><pre>- app/<br>  - (auth)/<br>    - login.tsx<br>  - (tabs)/<br>    - _layout.tsx<br>    - home.tsx<br>    - account.tsx<br>  - other.tsx<br>  - other/ <br>  - _layout.tsx<br></pre><h3>Step 2: Layouts</h3><p>Expo provides various layout options that you can use to create different navigation patterns and user interfaces. Some of the layout options are tabs, stacks, drawers etc.</p><p>Below I’ve created a tab router. The “initialRouteName” prop is set to “home”, indicating that the “home” screen is the initial screen displayed when the tab navigation is rendered. The “Tabs” component has multiple “Tabs.Screen” components. Each “Tabs.Screen” represents a tab screen. It defines the screen’s name and various options. This should correlate with the files in the file structure above.</p><pre>// app/(tabs)/_layout.tsx<br><br>export default function TabsLayout() {<br>  return (<br>    &lt;Tabs<br>      initialRouteName=&quot;home&quot;<br>      screenOptions={{<br>        ...<br>      }}<br>      tabBar={(props) =&gt;<br>        Platform.OS === &quot;ios&quot; ? (<br>          &lt;BlurView<br>            style={{ position: &quot;absolute&quot;, bottom: 0, left: 0, right: 0 }}<br>            tint={colorScheme == &quot;dark&quot; ? &quot;dark&quot; : &quot;light&quot;}<br>            intensity={95}<br>          &gt;<br>            &lt;BottomTabBar {...props} /&gt;<br>          &lt;/BlurView&gt;<br>        ) : (<br>          &lt;BottomTabBar {...props} /&gt;<br>        )<br>      }<br>    &gt;<br>      &lt;Tabs.Screen<br>        name=&quot;home&quot;<br>        options={{<br>          href: &quot;/home&quot;,<br>          tabBarIcon: ({ color }) =&gt; (<br>            ...<br>          ),<br>        }}<br>      /&gt;<br>      &lt;Tabs.Screen<br>        name=&quot;account&quot;<br>        options={{<br>          href: {<br>            pathname: &quot;/account&quot;,<br>          },<br>          tabBarIcon: ({ color }) =&gt; (<br>            ...<br>          ),<br>        }}<br>      /&gt;<br>    &lt;/Tabs&gt;<br>  );<br>}<br></pre><p>Next is the main layout:</p><p>Defining the stack is not strictly necessary, but allows for more flexibility, allows for nice animations and allows us to differentiate between our tabs and other stack screens. Feel free to try replacing the &lt;Stack /&gt; (and everything in it) with &lt;Slot /&gt; and see what happens.</p><pre>// app/_layout.tsx<br><br>import { AuthProvider } from &quot;../context/AuthProvider&quot;;<br><br>export default function RootLayout() {<br>  return (<br>    &lt;Stack<br>      screenOptions={{<br>        ...<br>      }}<br>    &gt;<br>      &lt;Stack.Screen<br>        name=&quot;(tabs)&quot;<br>        options={{<br>          ...<br>        }}<br>      /&gt;<br>      {/* &lt;Stack.Screen<br>        name=&quot;other&quot;<br>        options={{<br>          ...<br>        }}<br>      /&gt; */}<br>    &lt;/Stack&gt;<br>  );<br>}</pre><p>Inside each tab, make sure to export the function as such:</p><pre>// app/(tabs)/account.tsx<br><br>export default function Account() {<br>  return ...<br>}</pre><h3>Step 3: Stack screens</h3><p>All screens defined outside of the tab group will act as stack screens and stack on top of the tab navigation with a nice animation (if you define the stack layout above), allowing you to go back by pressing the back button in the upper left-hand corner.</p><h3>Step 4: Authentication</h3><p>I decided to include this part since many want to integrate authentication into their app and keep the rest of the app secure. Luckily it’s really simple!</p><p>Go back to the main _layout.tsx file and add your auth provider like so:</p><pre>// app/_layout.tsx<br><br>export default function RootLayout() {<br>  return (<br>    &lt;AuthProvider&gt;<br>      &lt;Stack&gt;<br>       ...<br>      &lt;/Stack&gt;<br>    &lt;/AuthProvider&gt;<br>  );<br>}</pre><p>The only extra code we need to add is within our AuthProvider. This is inspired by the auth tutorial in the <a href="https://expo.github.io/router/docs/guides/auth">Expo Router docs</a>.</p><pre>export function AuthProvider({ children }: { children: JSX.Element }): JSX.Element {<br>  <br>  ...<br>  useProtectedRoute(user);<br>  ...<br><br>  return &lt;AuthContext.Provider value={authContext}&gt;{children}&lt;/AuthContext.Provider&gt;;<br>}<br><br>function useProtectedRoute(user: any) {<br>  const segments = useSegments();<br>  const router = useRouter();<br><br>  useEffect(() =&gt; {<br>    const inAuthGroup = segments[0] === &quot;(auth)&quot;;<br><br>    if (<br>      // If the user is not signed in and the initial segment is not anything in the auth group.<br>      !user &amp;&amp;<br>      !inAuthGroup<br>    ) {<br>      // Redirect to the sign-in page.<br>      router.replace(&quot;/login&quot;);<br>    } else if (user &amp;&amp; inAuthGroup) {<br>      // Redirect away from the sign-in page.<br>      router.replace(&quot;/home&quot;);<br>    }<br>  }, [user, segments]);<br>}</pre><h3>Conclusion</h3><p><a href="https://github.com/fredrikburmester/expo-tab-router-exmaple">Here’s a link to my repo</a> with a working example!</p><p>Thank you for following along with this tutorial. I hope you found it helpful in implementing bottom tab routers with auth and stacks in your Expo project. Happy coding!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=acf7f7edee6d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to set up FileRun (Nextcloud alternative) on your UNRAID server in a Docker container with…]]></title>
            <link>https://medium.com/@fredrik.burmester/how-to-set-up-filerun-nextcloud-alternative-on-your-unraid-server-in-a-docker-container-with-57855e55961d?source=rss-802eda068bb4------2</link>
            <guid isPermaLink="false">https://medium.com/p/57855e55961d</guid>
            <category><![CDATA[nginx]]></category>
            <category><![CDATA[file-run]]></category>
            <category><![CDATA[mariadb]]></category>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[unraid]]></category>
            <dc:creator><![CDATA[Fredrik Burmester]]></dc:creator>
            <pubDate>Mon, 09 Jan 2023 10:27:22 GMT</pubDate>
            <atom:updated>2023-01-09T10:27:22.270Z</atom:updated>
            <content:encoded><![CDATA[<h3>How to set up FileRun (Nextcloud alternative) on your UNRAID server in a Docker container with HTTPS</h3><figure><img alt="FileRun" src="https://cdn-images-1.medium.com/max/602/1*WAk03N1BI80VrX8FvLBIXA.png" /><figcaption>FileRun</figcaption></figure><p>For the better part of a week, I’ve been trying to set up FileRun in a docker container. Posting on <a href="https://www.reddit.com/r/unRAID">r/unRAID</a> for help and getting some awesome feedback. Now I’d like to share what I’ve learned!</p><p>I’d like to thank <a href="https://www.reddit.com/user/m-jeri">u/m-jeri</a> for all the help setting up the container: <a href="https://www.reddit.com/r/unRAID/comments/an7225/trying\_to\_install\_filerun\_docker\_container/](https://www.reddit.com/r/unRAID/comments/an7225/trying_to_install_filerun_docker_container/)">https://www.reddit.com/r/unRAID/comments/an7225/trying_to_install_filerun_docker_container/</a><br>and <a href="https://www.reddit.com/user/theworldisweird_">u/theworldisweird_</a> for help with Nginx.</p><p>Prerequisites:</p><ol><li>MariaDB (container already set up and working)</li><li>NginxProxyManager (container and port forwarding already set up and working)</li><li>A CNAME sub-domain that points to your external IP. (DuckDNS or similar is recommended).</li></ol><h4>Creating the database</h4><p>Start by creating a user and a database in MariaDB that FileRun can use. And, of course, it’s recommended to use secure passwords. Here are all the commands you need to enter one line at a time (ignore the comments):</p><pre>mysql -uroot -p; /* Enter your mariadb password when prompted. */<br> CREATE USER &#39;&lt;user_name&gt;&#39; IDENTIFIED by &#39;&lt;user_password&gt;&#39;; /* Choose any username and password. */<br> CREATE DATABASE IF NOT EXISTS &lt;file_run_db_name&gt;; /* Choose any database name. */<br> GRANT ALL PRIVILEGES ON &lt;file_run_db_name&gt;.* TO &#39;&lt;user_name&gt;&#39; IDENTIFIED BY &#39;&lt;user_password&gt;&#39;; <br> FLUSH PRIVILEGES;<br> exit</pre><p>Now you have a DB that FileRun can use.</p><h4>Data storage</h4><p>Decide if you want to store all files within FileRun or link your current shares. If you want to link your shares you can create a folder within your appdata folder (or make it a share if you plan to store files in the FileRun instance) named filerun. Inside this folder, create three more, named: html, db and user-files. The file structure will look like this:</p><pre>appdata <br> +- filerun<br> | +- db<br> | +- html<br> | +- user-files</pre><h4>Installing the Docker container</h4><p>Now we can start setting up the Docker container. The images below show how the container should look.</p><figure><img alt="Container setup in unRAID" src="https://cdn-images-1.medium.com/max/1024/1*YzPjUZzIlG0kusrFDSFuow.png" /></figure><p>— Do not add Host Path 4 at the bottom. This is for step 7<br> — Icon URL is: <a href="https://avatars2.githubusercontent.com/u/6422152?s=400&amp;v=4">https://avatars2.githubusercontent.com/u/6422152?s=400&amp;v=4</a><br> — Fill in the fields that are blank in the image with your MariaDB username, DB and password and so on (i used filerun as username and mypassword as password everywhere to make it easy for myself, do not do this of course).<br> — Note that host paths do not have a slash at the end, for some reason, it didn’t work for me with a slash.<br> — Also note that you don’t need to change the WebUI. Leave it as <a href="http://[IP]:[PORT:8080]/`">http://[IP]:[PORT:8080]/</a>.<br> — You do <strong>not</strong> need to forward port 8080 in your router.</p><h4>Start the container</h4><p>You can now start up the container and enter the login credentials `superuser` and `superuser`.<br>Now you have a fully working FileRun setup. In the next step, I will explain how to access it from WAN with HTTPS.</p><h4>NginxProxyManager</h4><p>Open NginxProxyManager and create a new proxy host according to this:</p><figure><img alt="NginxProxyManager setup" src="https://cdn-images-1.medium.com/max/998/1*Teh6ITfSvENAqZ7tghB2rQ.png" /></figure><p>The IP address is the address you entered in the container setup, which should be the IP of your unRAID server. Make sure the port is the port of your FileRun container. And because FileRun doesn’t natively run on HTTPS you should have HTTP selected.<br>On the next page, <em>SSL,</em> you should request a new certificate.<br>Now you have your FileRun instance running HTTPS accessed by <a href="https://filerun.mydomain.com`">https://filerun.mydomain.com</a>. In the next step, I will show how to link your existing unRAID shares to your FileRun account.</p><h4>Create a new user</h4><p>Logged in to the superuser account, create a new user, go to permissions for that user and give it the path `/user-files/username` and click create folder now. (You choose your username.)</p><h4>FileRun Permissions</h4><p>Add the Host Path 4 mentioned in step 3. The container path should be /user-files/username. And host path should be /mnt/user if you want to add all your shares. If not, specify that share, like /mnt/user/Documents for example.</p><p>The problem is that all the files that FileRun creates are locked and if you try to access those files from another application or SMB share you will not have permission to do so. Therefore we have to change the permission of all files that FileRun creates. Go to where you placed your filerun folder and open `/mnt/user/appdata/filerun/html/customizables/config.php` if the file doesn’t exist then create it. And enter this:</p><pre>&lt;?php <br> umask(000);<br> php?&gt;</pre><p>This is not considered safe because your files are not protected at all now. <br>See this for more info: <a href="https://www.cyberciti.biz/tips/understanding-linux-unix-umask-value-usage.html">https://www.cyberciti.biz/tips/understanding-linux-unix-umask-value-usage.html</a></p><h4>Hide certain folders from FileRun</h4><p>Now if you’re like me and don’t want all shares showing up in FileRun you can add some lines to the `config.php` file to exclude them from FileRun.</p><pre>&lt;?php <br> umask(000);<br> $config[&#39;app&#39;][&#39;hidden_folder_names&#39;][] = &quot;appdata&quot;;<br> $config[&#39;app&#39;][&#39;hidden_folder_names&#39;][] = &quot;appdata-backup&quot;;<br> $config[&#39;app&#39;][&#39;hidden_folder_names&#39;][] = &quot;isos&quot;;<br> $config[&#39;app&#39;][&#39;hidden_folder_names&#39;][] = &quot;domains&quot;;<br> $config[&#39;app&#39;][&#39;hidden_folder_names&#39;][] = &quot;system&quot;;<br> php?&gt;</pre><p>For more info: <a href="https://docs.filerun.com/advanced_configuration">https://docs.filerun.com/advanced_configuration</a>.</p><p>Now you have FileRun all set up and ready to go! Have fun!</p><p>I hope this helps someone in their journey or maybe teaches some of you something. I know that I’ve learned a lot from all this.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=57855e55961d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Nuxt 3 website with Cloudflare Workers and GitHub Actions]]></title>
            <link>https://medium.com/@fredrik.burmester/nuxt-3-website-with-cloudflare-workers-and-github-actions-336411530aa1?source=rss-802eda068bb4------2</link>
            <guid isPermaLink="false">https://medium.com/p/336411530aa1</guid>
            <category><![CDATA[cloudflare]]></category>
            <category><![CDATA[wrangler]]></category>
            <category><![CDATA[github-actions]]></category>
            <category><![CDATA[workers]]></category>
            <category><![CDATA[nuxt]]></category>
            <dc:creator><![CDATA[Fredrik Burmester]]></dc:creator>
            <pubDate>Mon, 09 Jan 2023 10:10:45 GMT</pubDate>
            <atom:updated>2023-01-09T10:11:17.089Z</atom:updated>
            <content:encoded><![CDATA[<h3>Publish a Nuxt 3 website with Cloudflare Workers and GitHub Actions</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*pFWBEK3ef2lKyMyVBtIjow.jpeg" /></figure><h4>What are Cloudflare workers?</h4><p>Cloudflare workers is a way of running serverless functions on the Cloudflare global network. You can run almost anything, like, APIs, chat apps and websites. For some examples, check out their <a href="https://developers.cloudflare.com/workers/examples/">examples page</a>.</p><p>If you want to know more about how exactly workers work, check out <a href="https://developers.cloudflare.com/workers/learning/how-workers-works/">their documentation on workers</a>.</p><h4>Setting up the Nuxt 3 project</h4><p>Go to <a href="https://v3.nuxtjs.org/getting-started/installation">Nuxt 3 docs</a> and follow the instructions to get a Nuxt app going.</p><h4>Setting up GitHub Actions</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NBfJpN6UNVK6z-80PMmCZg.png" /></figure><p>When you have a Nuxt project up and running, the next step is to publish the app. There are a few ways to publish to Cloudflare: using <a href="https://github.com/cloudflare/wrangler2">wrangler</a> with <a href="https://nitro.unjs.io/">nitro</a>, direct upload from the wrangler2 CLI or manually by uploading a folder with all the compiled files, creating a <a href="https://pages.cloudflare.com/">page</a> from Cloudflare’s interface, or with Github actions. We will use <a href="https://nitro.unjs.io/deploy/providers/cloudflare">this guide</a> made by Nitro using wrangler2.</p><h4>Creating configuration files</h4><p>Start by creating an action for your repository. Do this by creating a file in the root of your repository</p><pre>.github/workflows/&lt;name&gt;.yml</pre><p>where the name is your workflow’s name, for example:</p><pre>.github/workflows/cloudflare.yml</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/588/1*7Nf-7Z5hCNrKYs3eKO2W-A.png" /></figure><p>Next, we will fill this file with publishing instructions. We will define our build environment and the <em>publish</em> script inside this file.</p><pre>name: cloudflare<br><br>on:<br>  push:<br>    branches:<br>      - main<br>      - develop<br><br>jobs:<br>  ci:<br>    runs-on: ubuntu-latest<br><br>    strategy:<br>      matrix:<br>        os: [ ubuntu-latest ]<br>        node: [ 16 ]<br><br>    steps:<br>      - uses: actions/setup-node@v1<br>        with:<br>          node-version: 16<br><br>      - name: Checkout<br>        uses: actions/checkout@master<br><br>      - name: Cache node_modules<br>        uses: actions/cache@v2<br>        with:<br>          path: node_modules<br>          key: ubuntu-latest-node-v16-deps-${{ hashFiles(format(&#39;{0}{1}&#39;, github.workspace, &#39;/yarn.lock&#39;)) }}<br><br>      - name: Install Dependencies<br>        if: steps.cache.outputs.cache-hit != &#39;true&#39;<br>        run: yarn<br><br>      - name: Build<br>        run: yarn build<br>        env:<br>          NITRO_PRESET: cloudflare<br>          NUXT_API_URL: &#39;https://cms.fredrikburmester.com/&#39;<br>          NUXT_SSR: &#39;true&#39;<br><br>      - name: Publish to Cloudflare<br>        uses: cloudflare/wrangler-action@2.0.0<br>        with:<br>          apiToken: ${{ secrets.CF_API_TOKEN }}<br>          command: publish --name fb-nuxt-${{ github.ref_name }}<br>name: cloudflare</pre><h4>Build environment</h4><p>As you can see, we are telling the action to publish on a push to the main or develop branch. We are using the latest ubuntu environment with node 16.</p><blockquote>Nuxt 3 requires the node version to be &gt;16 and &lt;17. Setting the GitHub action node version to 17 will not result in 17.0.0 but rather the latest 17 version. Setting the GitHub action node version to 16 will result in the latest 16 version, for example, 16.8.0.</blockquote><h4>Caching node modules</h4><p>We then cache the node_modules, for which several methods exist on the internet. Choose the one that suits you.</p><h4>Building the application</h4><p>We use yarn here to build the application but if you are using npm, then use the respective command.</p><p>By adding the env section, we can control some variables based on our environment, like dev och prod.</p><h4>Publishing to Cloudflare</h4><p>Usually, we don’t include the build command here. We typically opt out of the with command since it’s unnecessary if we do the next step as Nitro does in the guide. But we want to make environment-specific publications, and since using separate environments is not supported inside a single worker, we need to build separately named workers to act as prod and dev environments. We do this by suffixing the worker name with the GitHub repository branch name.</p><h4>Wrangler setup</h4><p>Next, we’ll look at the instructions in the guide I mentioned above. We will create a wrangler.toml file for some variables. We will exclude the name in this config since we set the name in the build command in the chapter above.</p><pre>main = &quot;./.output/server/index.mjs&quot;<br>workers_dev = true<br>compatibility_date = &quot;2022–10–17&quot;<br>account_id = &quot;&lt;cloudflare_worker_account_id&gt;&quot;<br>[site]<br>bucket = &quot;.output/public&quot;</pre><p>We tell wrangler where the files end up from the `yarn build` command, which is in ./.output/public, and we also set the main js file and the Cloudflare account id, which you can find in the Cloudflare console in the worker section on the right.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/524/1*7Wmr_yIcMhzo4gotufF9FQ.png" /><figcaption>The left section of the Cloudflare account page where you can access the overview of the workers console.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rzdVhbHITU7CfNhLw-ZCeQ.png" /><figcaption>A screenshot of the right section of the Cloudflare console.</figcaption></figure><p>And that’s it! ✅</p><p>Now, this GitHub Action will kick in every time you push to your dev and main branch, building and pushing the Nuxt app to the Cloudflare edge network.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=336411530aa1" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>