<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Marc</title>
    <description>The latest articles on Forem by Marc (@6174).</description>
    <link>https://forem.com/6174</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F991788%2Fb24a9ce4-eb16-4d75-b725-8af3037ef780.png</url>
      <title>Forem: Marc</title>
      <link>https://forem.com/6174</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/6174"/>
    <language>en</language>
    <item>
      <title>Building Desktop Applications with Tauri, Nextjs, Firebase</title>
      <dc:creator>Marc</dc:creator>
      <pubDate>Sun, 26 Feb 2023 09:15:47 +0000</pubDate>
      <link>https://forem.com/6174/building-desktop-applications-with-tauri-nextjs-firebase-54j7</link>
      <guid>https://forem.com/6174/building-desktop-applications-with-tauri-nextjs-firebase-54j7</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally published at &lt;a href="https://medium.com/@marcchen955/building-desktop-applications-with-tauri-nextjs-firebase-ae56904afd4f" rel="noopener noreferrer"&gt;medium&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  TL;DR
&lt;/h1&gt;

&lt;p&gt;In this article, I will compare Tauri and Electron and explore the possible challenges when applying Tauri to real-world projects, especially when integrating with Firebase.&lt;/p&gt;

&lt;h1&gt;
  
  
  Background
&lt;/h1&gt;

&lt;p&gt;I'm working on a whiteboard product at &lt;a href="https://doodleboard.pro/" rel="noopener noreferrer"&gt;https://doodleboard.pro&lt;/a&gt; and trying to make it work on different devices, such as phones and iPads. I've been exploring various options because I don't want to force users to install yet another browser by using Electron, which is the most established choice out there. Here are some of the other options I've looked at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://neutralino.js.org/" rel="noopener noreferrer"&gt;https://neutralino.js.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://microsoft.github.io/react-native-windows/" rel="noopener noreferrer"&gt;https://microsoft.github.io/react-native-windows/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/wailsapp/wails/" rel="noopener noreferrer"&gt;https://github.com/wailsapp/wails/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://solito.dev/" rel="noopener noreferrer"&gt;https://solito.dev/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tauri-apps/tauri/" rel="noopener noreferrer"&gt;https://github.com/tauri-apps/tauri/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.electronjs.org/" rel="noopener noreferrer"&gt;https://www.electronjs.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://flutter.io/" rel="noopener noreferrer"&gt;https://flutter.io/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And DoodleBoard is built on Next.js and Firebase, so I need to figure out how to integrate these technologies together.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why choose Tauri?
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fehe4te3ar725m5alrajg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fehe4te3ar725m5alrajg.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I had to pick an option that would work for me, and after weighing my options, I landed on Tauri. &lt;/p&gt;

&lt;p&gt;Electron is cool and all, but it's a biggie in terms of package size, plus it's not mobile-friendly. I needed something that could run on multiple platforms and not make users install more browers.&lt;/p&gt;

&lt;p&gt;Flutter is a well-known framework, but using it for a whiteboard and text editor would be a massive undertaking. Plus, it can't reuse web code, which is a no-go for me.&lt;/p&gt;

&lt;p&gt;React Native is another popular choice, but reusing the code is only possible for some parts of the project. And, let's face it, implementing a whiteboard using React Native would be quite a challenge.&lt;/p&gt;

&lt;p&gt;Wails and Tauri have a very similar architecture. Compare to Wails, Tauri has a more active and experienced community. I figured I'd go with the more established option to avoid unnecessary headaches. Also, Wails doesn't work on mobile devices.&lt;/p&gt;

&lt;p&gt;Tauri could reuse almost all of my existing code and offered a solution for multiple platforms. Plus, the package size is nice and small. So, that's why I went with Tauri.&lt;/p&gt;

&lt;h1&gt;
  
  
  What critical problems need to be solved to integrate Firebase + Next.js with Tauri?
&lt;/h1&gt;

&lt;p&gt;Tauri's hello world demo is too simple, but there may be various issues when applied to real projects. The core of this article is to sort out these issues and share them with the community.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How Tauri work?&lt;/li&gt;
&lt;li&gt;How to solve CORS network request issues in Tauri&lt;/li&gt;
&lt;li&gt;How to compile Tauri and Next.js into one project?&lt;/li&gt;
&lt;li&gt;How to reuse existing code as much as possible?&lt;/li&gt;
&lt;li&gt;How to add Deeplink to your Tauri app?&lt;/li&gt;
&lt;li&gt;How to integrate Firebase Auth in Tauri?&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  How Tauri work?
&lt;/h1&gt;

&lt;p&gt;To better tackle real problems,we must understand the underlying architecture of Tauri. Tauri essentially uses the WRY library to wrap the native browser of the operating system, providing a convenient interface layer for the browser and Rust to call each other. &lt;/p&gt;

&lt;p&gt;Therefore, our frontend code runs in the native browser, while our backend code runs in the Rust layer provided by Tauri. This is also why Tauri is fast and has a small footprint.&lt;/p&gt;

&lt;p&gt;Below is the architecture diagram I have mapped out for Tauri:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftmt06yn715seje9txmpl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftmt06yn715seje9txmpl.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  How to solve CORS network request issues in Tauri?
&lt;/h1&gt;

&lt;p&gt;Because the frontend code in Tauri runs in a browser, it will encounter the CORS problem when making network requests. The following is a simplified diagram of the structure. Since the frontend code runs in an environment with a special domain name, requesting &lt;a href="https://your-backend.com" rel="noopener noreferrer"&gt;https://your-backend.com&lt;/a&gt; will result in a cross-origin problem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fny356x7aifkolqpzuu3u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fny356x7aifkolqpzuu3u.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So how can we solve this problem? There are two ways:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution One:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To configure CORS in your own API request, I use Next.js, so you only need to add CORS in your own handler.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvijhejw5b5vsd3l895i3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvijhejw5b5vsd3l895i3.png" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// https://www.npmjs.com/package/nextjs-cors &lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;NextCors&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nextjs-cors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// Run the cors middleware&lt;/span&gt;
   &lt;span class="c1"&gt;// nextjs-cors uses the cors package, so we invite you to check the documentation https://github.com/expressjs/cors&lt;/span&gt;
   &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nc"&gt;NextCors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Options&lt;/span&gt;
      &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;HEAD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PUT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PATCH&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DELETE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;optionsSuccessStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// some legacy browsers (IE11, various SmartTVs) choke on 204&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;

   &lt;span class="c1"&gt;// Rest of the API logic&lt;/span&gt;
   &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello NextJs Cors!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Solution Two:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In some cases, CORS cannot be modified, so you can also use the Fetch library provided by Tauri Runtime layer. This means the request is sent through the Rust backend. Here's how to do it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F67polxieif21rkq1ltvd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F67polxieif21rkq1ltvd.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Configure tauri.conf.json to support the corresponding API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tauri&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;allowlist&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;all&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// enable all http APIs&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;request&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;// enable HTTP request API&lt;/span&gt;
                &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scope&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.github.com/repos/tauri-apps/*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also add * in scope to allow any request. It's worth noting that Tauri has done a great job in security handling, and many areas can be restricted through configuration.&lt;/p&gt;

&lt;p&gt;Use fetch in the frontend through Tauri API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tauri-apps/api/http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3003/users/2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In real-world applications, different environments may require different fetch methods, so you can encapsulate the fetch method into a custom module and dynamically obtain the required fetch (Browser Native) for different scenarios.&lt;/p&gt;

&lt;h1&gt;
  
  
  How to compile Tauri and Next.js into one project?
&lt;/h1&gt;

&lt;p&gt;I need to integrate Tauri into my project, which is built based on pnpm workspace with a basic structure as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;doodleboard&lt;/span&gt;
  &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;apps&lt;/span&gt;
    &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;
  &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;packages&lt;/span&gt;
    &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;pkg1&lt;/span&gt;
    &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;pkg2&lt;/span&gt;
  &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;Readme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;md&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After adding Tauri, my project structure becomes like this, which basically reuses the main body of the Next.js project and adds a new src-tauri directory. So with Tauri added, the overall project structure is very clean.&lt;/p&gt;

&lt;p&gt;It is worth noting that, due to the code reuse of Next.js for both front-end and back-end, when using Next.js to write the Tauri front-end, it needs to be compiled and packaged separately. Only the front-end code will run, and the back-end code will not run. Therefore, SSR code should not appear here.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;doodleboard&lt;/span&gt;
  &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;apps&lt;/span&gt;
    &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;
    &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;desktop&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;
      &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;pages&lt;/span&gt;
        &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;_app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tsx&lt;/span&gt;
        &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tsx&lt;/span&gt;
      &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;tauri&lt;/span&gt;
        &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;
                    &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rs&lt;/span&gt;
        &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;tauri&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;
      &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt;
  &lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="nx"&gt;packages&lt;/span&gt;
    &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;pkg1&lt;/span&gt;
    &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;pkg2&lt;/span&gt;
  &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;Readme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;md&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And Tauri is also very convenient in the development and debugging stage. Basically, it just adds the original Next.js command in the tauri.config.json file. After configuring it, running &lt;strong&gt;&lt;code&gt;pnpm tauri dev&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
 will automatically compile and package the frontend to generate the desktop project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;build&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;beforeBuildCommand&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pnpm build &amp;amp;&amp;amp; pnpm export&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;beforeDevCommand&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pnpm dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;devPath&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;distDir&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../out&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is worth noting that, due to the code reuse of Next.js for both front-end and back-end, when using Next.js to write the Tauri front-end, it needs to be compiled and packaged separately. Only the front-end code will run, and the back-end code will not run. Therefore, SSR code should not appear here.&lt;/p&gt;

&lt;h1&gt;
  
  
  How to Maximize Code Reuse?
&lt;/h1&gt;

&lt;p&gt;After creating your project structure according to the above guide, your Tauri desktop project can reuse other packages in the pnpm workspace, including code from the main-next-project.&lt;/p&gt;

&lt;p&gt;In my experience, Tauri can achieve about 95% code reuse, with customization only necessary for desktop interactions. Therefore, when writing business code, try to abstract it as much as possible into workspace packages.&lt;/p&gt;

&lt;h1&gt;
  
  
  How to Add Deeplinks to Your Tauri App?
&lt;/h1&gt;

&lt;p&gt;Deeplinks are a way to use custom URIs within an application, allowing browsers to redirect to the app in scenarios such as authorization.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faot0zy8bvx404tjuxr7x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faot0zy8bvx404tjuxr7x.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, after some research, I found that Tauri does not currently support deeplinks. So what can you do? Especially when you need to use authorization login, how do you get the browser and Tauri to communicate? I discovered two possible solutions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution 1:&lt;/strong&gt; Use a server as an intermediary for communication, such as Firebase. For a more detailed example, see here: &lt;a href="https://sevenbits.hashnode.dev/demystifying-user-authentication-with-google-in-electron" rel="noopener noreferrer"&gt;https://sevenbits.hashnode.dev/demystifying-user-authentication-with-google-in-electron&lt;/a&gt;. The author's scenario involves using Electron, but the essence is the same.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0m2qgnk1ihtc7r6paqe5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0m2qgnk1ihtc7r6paqe5.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution 2:&lt;/strong&gt; Use Rust to implement a local server and have the frontend communicate with it via HTTP.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx00w5jj8ceg211bts753.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx00w5jj8ceg211bts753.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Additional:&lt;/strong&gt; Deeplinks can also be implemented as a Tauri plugin, for example, with this library: &lt;a href="https://github.com/maidsafe-archive/system_uri/blob/master/src/lib.rs" rel="noopener noreferrer"&gt;https://github.com/maidsafe-archive/system_uri/blob/master/src/lib.rs&lt;/a&gt;. However, it currently cannot pass parameters.&lt;/p&gt;

&lt;h1&gt;
  
  
  How to integrate Firebase Auth in Tauri?
&lt;/h1&gt;

&lt;p&gt;Once the communication problem mentioned above is solved, it is easy to implement Firebase Auth. I chose the second communication method. In order to enable Firebase authorization login on the desktop side, you can use the sign in with custom token API.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://firebase.google.com/docs/auth/admin/create-custom-tokens" rel="noopener noreferrer"&gt;https://firebase.google.com/docs/auth/admin/create-custom-tokens&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The following figure shows the entire authorization process.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxpfy67mxm4oa91lihkpp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxpfy67mxm4oa91lihkpp.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What's Next?
&lt;/h1&gt;

&lt;p&gt;After solving these problems, the product can be up and running. Here is the result of my successful run, but there are still many issues to be resolved, so it cannot be used in real life.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71y0z39i9j7tzjzdb2kh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71y0z39i9j7tzjzdb2kh.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk4mbu5mlsmu5b76zjj7s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk4mbu5mlsmu5b76zjj7s.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the DoodleBoard scenario, the following issues need to be addressed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How to make Tauri support multi-tab structures like Figma &amp;amp; Notion, as Tauri does not have an Electron Browser view.&lt;/li&gt;
&lt;li&gt;Tauri uses a native browser, and Safari's performance with WebGL is very poor. Even Figma has lag issues when running in Safari. I don't want my product to encounter performance problems in the basic experience, so I need to think about solutions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Overall, Tauri has already solved the majority of issues and is still rapidly iterating. I hope it will continue to improve.&lt;/p&gt;

&lt;p&gt;Finally, everyone is welcome to use my product: &lt;a href="https://doodleboard.pro/" rel="noopener noreferrer"&gt;https://doodleboard.pro&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>firebase</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
