<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Webview on Techformist</title>
    <link>https://techformist.com/tags/webview/</link>
    <description>Recent content in Webview on Techformist</description>
    <image>
      <url>https://techformist.com/logo.svg</url>
      <link>https://techformist.com/logo.svg</link>
    </image>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Sat, 07 Oct 2023 06:30:00 +0000</lastBuildDate><atom:link href="https://techformist.com/tags/webview/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Go Webview Experiments and a Simple Todo Demo App</title>
      <link>https://techformist.com/go-webview-experiments/</link>
      <pubDate>Sat, 07 Oct 2023 06:30:00 +0000</pubDate>
      
      <guid>https://techformist.com/go-webview-experiments/</guid>
      <description>&lt;p&gt;Applications in Electron are great, but they are also heavy and slow. I have been looking for a way to build an app that can be -&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;universal (kinda - I will start with desktop experience for the masses but will eventually gravitate towards everything, everywhere, all at once)&lt;/li&gt;
&lt;li&gt;light weight - space and memory&lt;/li&gt;
&lt;li&gt;fast&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Just to set the frame of reference - what I want from UI development is ease of development - html, css, and js and other such delightful technologies make things easy, GTK / Xamarin / Qt / WinForms / WPF / etc. are not so much fun.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Applications in Electron are great, but they are also heavy and slow. I have been looking for a way to build an app that can be -</p>
<ul>
<li>universal (kinda - I will start with desktop experience for the masses but will eventually gravitate towards everything, everywhere, all at once)</li>
<li>light weight - space and memory</li>
<li>fast</li>
</ul>
<p>Just to set the frame of reference - what I want from UI development is ease of development - html, css, and js and other such delightful technologies make things easy, GTK / Xamarin / Qt / WinForms / WPF / etc. are not so much fun.</p>
<p>What better way to do most of the features outlined here than in Go? This is an attempt to build a simple todo app using the combined power of Go and web technologies.</p>
<p>We will start with a simple window with webview in Golang, and then move to Wails to see how it makes the entire experience better. We will also see how to incrementally add functionality to the app.</p>
<h1 id="getting-started-installation--setup">Getting Started: Installation &amp; Setup</h1>
<p>If you intend to follow along, ensure you have Go on the system. If you don&rsquo;t, you can get it from <a href="https://golang.org/dl/">here</a>.</p>
<p>Having VSCode from <a href="https://code.visualstudio.com/download">here</a> and the Golang extension from <a href="https://marketplace.visualstudio.com/items?itemName=golang.Go">here</a> will be helpful.</p>
<p>Once the entire setup is done, create a new folder, open a terminal either in explorer or from VSCode, and create a new Go project -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">go mod init go-webview-todo
</span></span></code></pre></div><p>This will create a <code>go.mod</code> file in the project root - it will be used to manage dependencies. Open the project folder in VSCode.</p>
<p>Create a file called <code>main.go</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s">&#34;Hello World&#34;</span><span class="p">)</span><span class="w">
</span></span></span></code></pre></div><p>Now, run the file using the <code>Run</code> button in VSCode or using a terminal. You should see the output in the terminal.</p>
<p>Now that everything is running with your setup, we will focus on next steps.</p>
<h1 id="install-dependencies">Install Dependencies</h1>
<p>There are more than a few options to create webview apps -</p>
<ol>
<li><a href="github.com/zserge/webview">zserge/webview</a>
Simple, cross-platform, portable, and lightweight. It is a tiny cross-platform webview library for C/C++/Golang to build modern cross-platform GUIs. It supports two-way JavaScript bindings (to call JavaScript from C/C++/Go and to call C/C++/Go from JavaScript). Needs CGO and some special flags to run on Windows.</li>
<li>Go bindings for webview library <a href="https://github.com/webview/webview_go">webview/webview_go</a>
Underlying library was intended for C/C++, but has a Go wrapper around it.</li>
<li><a href="https://github.com/ImVexed/muon">ImVexed/muon</a>
Uses Ultralight, a cross-platform WebKit rewrite in C++, instead of Chrome. Lightweight alternative to Electron. Not maintained actively anymore.</li>
<li>Advanced / fully-featured libraries like <a href="https://github.com/wailsapp/wails">wailsapp/wails</a> or <a href="https://github.com/fyne-io/fyne">fyne-io/fyne</a>
May use webview libraries in the backend, but abstract away the entire setup and make the entire experience pleasant. We will get to this state at the very end.</li>
</ol>
<p>.. and more.</p>
<p>We will start with the simplest option - <code>zserge/webview</code>.</p>
<h1 id="develop-a-simple-window-with-webview-in-golang">Develop a simple window with webview in Golang</h1>
<p>Install the library using <code>go get</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">go get github.com/zserge/webview
</span></span></code></pre></div><p>Create a new file called <code>main.go</code> and add the following code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="s">&#34;github.com/zserge/webview&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">w</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">webview</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="nx">webview</span><span class="p">.</span><span class="nx">Settings</span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">Title</span><span class="p">:</span><span class="w">                  </span><span class="s">&#34;My test web view app&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">URL</span><span class="p">:</span><span class="w">                    </span><span class="s">&#34;http://google.com&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">Width</span><span class="p">:</span><span class="w">                  </span><span class="mi">1000</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">Height</span><span class="p">:</span><span class="w">                 </span><span class="mi">800</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">Resizable</span><span class="p">:</span><span class="w">              </span><span class="kc">true</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">Debug</span><span class="p">:</span><span class="w">                  </span><span class="kc">true</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">ExternalInvokeCallback</span><span class="p">:</span><span class="w"> </span><span class="kc">nil</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">defer</span><span class="w"> </span><span class="nx">w</span><span class="p">.</span><span class="nf">Destroy</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">w</span><span class="p">.</span><span class="nf">SetTitle</span><span class="p">(</span><span class="s">&#34;My App&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">w</span><span class="p">.</span><span class="nf">Navigate</span><span class="p">(</span><span class="s">&#34;https://google.com&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">w</span><span class="p">.</span><span class="nf">Run</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>You should see a nice window.. in theory. In practice I could not get my module to work in Windows. I gave up after a few tries.</p>
<p>Close to the webview package is webview2 - <a href="https://github.com/jchv/go-webview2">jchv/go-webview2</a>. This library does not need CGO but is Windows specific.</p>
<p>Install <code>webview2</code> with -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">go get <span class="s2">&#34;github.com/jchv/go-webview2&#34;</span>
</span></span></code></pre></div><p>Change the code in <code>main.go</code> ever so slightly -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="s">&#34;github.com/jchv/go-webview2&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">w</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">webview2</span><span class="p">.</span><span class="nf">NewWithOptions</span><span class="p">(</span><span class="nx">webview2</span><span class="p">.</span><span class="nx">WebViewOptions</span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">Window</span><span class="p">:</span><span class="w">        </span><span class="kc">nil</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">Debug</span><span class="p">:</span><span class="w">         </span><span class="kc">true</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">DataPath</span><span class="p">:</span><span class="w">      </span><span class="s">&#34;&#34;</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">AutoFocus</span><span class="p">:</span><span class="w">     </span><span class="kc">false</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">WindowOptions</span><span class="p">:</span><span class="w"> </span><span class="nx">webview2</span><span class="p">.</span><span class="nx">WindowOptions</span><span class="p">{</span><span class="nx">Title</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;Demo View&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">Width</span><span class="p">:</span><span class="w"> </span><span class="mi">1000</span><span class="p">,</span><span class="w"> </span><span class="nx">Height</span><span class="p">:</span><span class="w"> </span><span class="mi">800</span><span class="p">},</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">w</span><span class="p">.</span><span class="nf">SetSize</span><span class="p">(</span><span class="mi">800</span><span class="p">,</span><span class="w"> </span><span class="mi">600</span><span class="p">,</span><span class="w"> </span><span class="nx">webview2</span><span class="p">.</span><span class="nx">HintFixed</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">w</span><span class="p">.</span><span class="nf">Navigate</span><span class="p">(</span><span class="s">&#34;https://google.com&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">defer</span><span class="w"> </span><span class="nx">w</span><span class="p">.</span><span class="nf">Destroy</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">w</span><span class="p">.</span><span class="nf">Run</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>And, voila -</p>
<p><img loading="lazy" src="/2023/golang-webview2-window.png" type="" alt="golang-webview2-window"  /></p>
<h1 id="moving-to-wails">Moving to Wails</h1>
<p>While the code above is pretty simple and straight-forward, the developer experience may not be the best. Let&rsquo;s see whether that changes with Wails.</p>
<p>First, install <a href="https://nodejs.org/en/download">Node</a> if you don&rsquo;t already have it.</p>
<p>Install Wails in your project folder.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">go install github.com/wailsapp/wails/v2/cmd/wails@latest
</span></span></code></pre></div><p>In Terminal, hit the below command to check whether Wails has been installed correctly -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">wails doctor
</span></span></code></pre></div><p><img loading="lazy" src="/2023/wails-doctor-output.png" type="" alt="wails-doctor-output.png"  /></p>
<p>See the <a href="https://wails.app/gettingstarted/installing/">Wails documentation</a> if you are facing any issues.</p>
<p>Now, let&rsquo;s create a new project using Wails. Note that we will be using Vue for the frontend.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">wails init -n go-webview-wails-todo -t vue
</span></span></code></pre></div><p>React, Svelte or vanilla JS are supported Wails OOB, and there are more community-supported templates for other frameworks.</p>
<p>Open the project folder in VSCode.Change the statement <code>module changeme</code> in <code>go.mod</code> to <code>module go-webview-wails-todo</code>. Update the <code>README</code> if you want.</p>
<p>Run the app -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">wails dev
</span></span></code></pre></div><p>This should start your application.</p>
<p><img loading="lazy" src="/2023/wails-dev-output.png" type="" alt="wails-dev-output"  /></p>
<p>Add a simple function to <code>app.go</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">a</span><span class="w"> </span><span class="o">*</span><span class="nx">App</span><span class="p">)</span><span class="w"> </span><span class="nf">TodoList</span><span class="p">()</span><span class="w"> </span><span class="p">[]</span><span class="kt">string</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">return</span><span class="w"> </span><span class="p">[]</span><span class="kt">string</span><span class="p">{</span><span class="s">&#34;todo1&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;todo2&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;todo3&#34;</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>Include some ready styling with <a href="https://jenil.github.io/chota/">chota css</a> with the below line in <code>head</code> section of <code>frontend/index.html</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;stylesheet&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;https://unpkg.com/chota@latest&#34;</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>Update the <code>frontend/src/App.vue</code> file to display the list of todos -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">ListTodos</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;../wailsjs/go/main/App&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">todos</span> <span class="o">=</span> <span class="nx">reactive</span><span class="p">({</span> <span class="nx">data</span><span class="o">:</span> <span class="p">[]</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">getTodoList</span> <span class="o">=</span> <span class="kr">async</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">todos</span><span class="p">.</span><span class="nx">data</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">ListTodos</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;todos.data: &#39;</span><span class="p">,</span> <span class="p">...</span><span class="nx">todos</span><span class="p">.</span><span class="nx">data</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="nx">onMounted</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">getTodoList</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`Fetched todos..!`</span><span class="p">,</span> <span class="nx">todos</span><span class="p">.</span><span class="nx">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;container&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">nav</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;nav&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;nav-left&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;brand&#34;</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;#&#34;</span><span class="p">&gt;</span>Wails Todos!<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">nav</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;row&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-12&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          {{todos.data}}}
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>You should see the list of hard-coded <code>todos</code> in the app.</p>
<p>Couple of really cool things happened so far -</p>
<ol>
<li>The logic you wrote in Go is available in the frontend as a function. You can call it from the frontend and use the data in the frontend. All you needed to do was to add the function to the <code>App</code> struct in <code>app.go</code> and wails took care of the rest.</li>
<li>You will see <code>wails.js</code> folder with Go APIs being exposed to the frontend as JS functions. You would also see types generated out of <code>struct</code> if we had used Typescript</li>
<li><code>wails</code> command did the hot-reload for both golang and vue, and bound everything together for you. You did not have to do anything else other than focus on the app logic</li>
</ol>
<h1 id="adding-functionality-to-our-wails-app">Adding functionality to our wails app</h1>
<p>Let&rsquo;s make our app easier to read / maintain with a few changes.</p>
<p>Add the below <code>struct</code> to <code>app.go</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span><span class="w"> </span><span class="nx">todo</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Id</span><span class="w">          </span><span class="kt">int</span><span class="w">    </span><span class="s">`json:&#34;id&#34;`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Description</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="s">`json:&#34;description&#34;`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Due</span><span class="w">         </span><span class="kt">string</span><span class="w"> </span><span class="s">`json:&#34;due&#34;`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Status</span><span class="w">      </span><span class="kt">string</span><span class="w"> </span><span class="s">`json:&#34;status&#34;`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Created</span><span class="w">     </span><span class="kt">string</span><span class="w"> </span><span class="s">`json:&#34;created&#34;`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>Notice the capital letters for <code>Id</code>, <code>Description</code> etc. - that is Go way of making fields public and accessible from outside the package.</p>
<p>After <code>Greet</code> function, introduce the below code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">a</span><span class="w"> </span><span class="o">*</span><span class="nx">App</span><span class="p">)</span><span class="w"> </span><span class="nf">ListTodos</span><span class="p">()</span><span class="w"> </span><span class="p">[]</span><span class="nx">todo</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">return</span><span class="w"> </span><span class="p">[]</span><span class="nx">todo</span><span class="p">{{</span><span class="nx">Id</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="nx">Description</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;Code Go&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">Due</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;2023-10-15&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">Status</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;In Progress&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">Created</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;2023-10-01 18:30&#34;</span><span class="p">}}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">a</span><span class="w"> </span><span class="o">*</span><span class="nx">App</span><span class="p">)</span><span class="w"> </span><span class="nf">CreateTodo</span><span class="p">(</span><span class="nx">todoItem</span><span class="w"> </span><span class="nx">todo</span><span class="p">)</span><span class="w"> </span><span class="nx">todo</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">todoItem</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">return</span><span class="w"> </span><span class="nx">todo</span><span class="p">{</span><span class="nx">Id</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="nx">Description</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;Code Go&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">Due</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;2023-10-15&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">Status</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;In Progress&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">Created</span><span class="p">:</span><span class="w"> </span><span class="s">&#34;2023-10-01 18:30&#34;</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>We are yet to implement a database -</p>
<ul>
<li>The dummy data in <code>ListTodos</code> will be replaced with actual data from a database</li>
<li><code>CreateTodo</code> will be used to create a new todo item</li>
</ul>
<p>The functions just return &ldquo;some&rdquo; data to demonstrate how the <code>todo</code>, a <code>struct</code> in Golang is available to the frontend. Click on them buttons to see output in console - both in Terminal running <code>go</code> and in the browser.</p>
<p>The changes in Vue are more extensive -</p>
<ol>
<li>Create Vue components for list and new todos</li>
<li>Change <code>TodoList.vue</code> to point to the new components</li>
<li>Add some custom styling in <code>styles.css</code> (after removing the existing content)</li>
</ol>
<p>I have just included the code from <code>TodoList.vue</code> below, but you can see the entire code in the <a href="https://github.com/prashanth1k/go-webview-wails-todo">repo</a>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;todolist&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">v-for</span><span class="o">=</span><span class="s">&#34;todo in todos.data&#34;</span> <span class="na">:key</span><span class="o">=</span><span class="s">&#34;todo&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;todo-item row&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-1&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;checkbox&#34;</span> <span class="na">name</span><span class="o">=</span><span class="s">&#34;status&#34;</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;status&#34;</span> <span class="na">:checked</span><span class="o">=</span><span class="s">&#34;todo.status == &#39;Complete&#39; ? true : false&#34;</span>
</span></span><span class="line"><span class="cl">                        <span class="err">@</span><span class="na">click</span><span class="o">=</span><span class="s">&#34;updateTodo(todo)&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-3 dates&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://icongr.am/feather/calendar.svg?size=14&amp;color=D3D3D3&#34;</span> <span class="na">alt</span><span class="o">=</span><span class="s">&#34;&#34;</span><span class="p">&gt;</span> {{
</span></span><span class="line"><span class="cl">                        todo.due?.substring(0, 10) }}
</span></span><span class="line"><span class="cl">                <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-7&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    {{ todo.description }}
</span></span><span class="line"><span class="cl">                <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;col-1&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">&lt;</span><span class="nt">a</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;button error cardaction &#34;</span> <span class="err">@</span><span class="na">click</span><span class="o">=</span><span class="s">&#34;deleteTodo(todo)&#34;</span><span class="p">&gt;&lt;</span><span class="nt">img</span>
</span></span><span class="line"><span class="cl">                            <span class="na">src</span><span class="o">=</span><span class="s">&#34;https://icongr.am/feather/trash-2.svg?size=24&amp;color=FFFFFF&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">                <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">template</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">script</span> <span class="na">setup</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">props</span> <span class="o">=</span> <span class="nx">defineProps</span><span class="p">([</span><span class="s1">&#39;todos&#39;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">UpdateTodo</span><span class="p">,</span> <span class="nx">DeleteTodo</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;../../wailsjs/go/main/App&#39;</span>
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">emit</span> <span class="o">=</span> <span class="nx">defineEmits</span><span class="p">([</span><span class="s1">&#39;updateTodo&#39;</span><span class="p">,</span> <span class="s1">&#39;deleteTodo&#39;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">updateTodo</span> <span class="o">=</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">todo</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`Emitting updateTodo event..!`</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nx">todo</span><span class="p">.</span><span class="nx">status</span> <span class="o">=</span> <span class="nx">todo</span><span class="p">.</span><span class="nx">status</span> <span class="o">==</span> <span class="s2">&#34;Complete&#34;</span> <span class="o">?</span> <span class="s2">&#34;In Progress&#34;</span> <span class="o">:</span> <span class="s2">&#34;Complete&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">todoResponse</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">UpdateTodo</span><span class="p">(</span><span class="nx">todo</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;todoResponse: &#39;</span><span class="p">,</span> <span class="nx">todoResponse</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">emit</span><span class="p">(</span><span class="s1">&#39;updateTodo&#39;</span><span class="p">,</span> <span class="nx">todo</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">deleteTodo</span> <span class="o">=</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">todo</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`Emitting deleteTodo event..!`</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">todoResponse</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">DeleteTodo</span><span class="p">(</span><span class="nx">todo</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;todoResponse: &#39;</span><span class="p">,</span> <span class="nx">todoResponse</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="nx">emit</span><span class="p">(</span><span class="s1">&#39;deleteTodo&#39;</span><span class="p">,</span> <span class="nx">todo</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
</span></span></code></pre></div><p>And.. tada..
<img loading="lazy" src="/2023/go-webview-wails-todo-app.png" type="" alt="go-webview-wails-todo-app"  /></p>
<p>You can also see the output in a browser - just navigate to <code>http://localhost:34115/</code>. The browser window will be useful to refresh on demand and also see errors in the console faster.</p>
<h1 id="adding-the-database">Adding the database</h1>
<p>We will use SQLite and <a href="https://gorm.io/">gorm</a> as the ORM for our app. Include the below libraries in <code>app.go</code> -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">import</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="c1">// ...</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="s">&#34;github.com/glebarez/sqlite&#34;</span><span class="w"> 
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="s">&#34;gorm.io/gorm&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">)</span><span class="w">
</span></span></span></code></pre></div><p>On VSCode, you can follow editor prompts to <code>go get</code> both packages.</p>
<p>Now, include <code>db</code> in <code>App</code> struct -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span><span class="w"> </span><span class="nx">App</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">ctx</span><span class="w"> </span><span class="nx">context</span><span class="p">.</span><span class="nx">Context</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">db</span><span class="w">  </span><span class="nx">gorm</span><span class="p">.</span><span class="nx">DB</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>Modify the <code>todo</code> struct to make it special -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span><span class="w"> </span><span class="nx">todo</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Id</span><span class="w">          </span><span class="kt">int</span><span class="w">       </span><span class="s">`json:&#34;id&#34;`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Description</span><span class="w"> </span><span class="kt">string</span><span class="w">    </span><span class="s">`json:&#34;description&#34;`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Due</span><span class="w">         </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"> </span><span class="s">`json:&#34;due&#34; gorm:&#34;type:datetime&#34;`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Status</span><span class="w">      </span><span class="kt">string</span><span class="w">    </span><span class="s">`json:&#34;status&#34;`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Created</span><span class="w">     </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"> </span><span class="s">`json:&#34;created&#34; gorm:&#34;autoCreateTime;type:datetime&#34;`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">Updated</span><span class="w">     </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"> </span><span class="s">`json:&#34;updated&#34; gorm:&#34;autoUpdateTime;type:datetime&#34;`</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>In the <code>startup</code> function (<code>func (a *App) startup(...)</code>), add the below code -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">a</span><span class="w"> </span><span class="o">*</span><span class="nx">App</span><span class="p">)</span><span class="w"> </span><span class="nf">startup</span><span class="p">(</span><span class="nx">ctx</span><span class="w"> </span><span class="nx">context</span><span class="p">.</span><span class="nx">Context</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nx">db</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">gorm</span><span class="p">.</span><span class="nf">Open</span><span class="p">(</span><span class="nx">sqlite</span><span class="p">.</span><span class="nf">Open</span><span class="p">(</span><span class="s">&#34;data.db&#34;</span><span class="p">),</span><span class="w"> </span><span class="o">&amp;</span><span class="nx">gorm</span><span class="p">.</span><span class="nx">Config</span><span class="p">{})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">log</span><span class="p">.</span><span class="nf">Fatal</span><span class="p">(</span><span class="s">&#34;failed to connect database&#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">err</span><span class="p">.</span><span class="nf">Error</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">a</span><span class="p">.</span><span class="nx">db</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="o">*</span><span class="nx">db</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;Connected to database. db exists: &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">&#34;%t&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">db</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="c1">// AutoMigrate will create the todos table if it does not exist</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">if</span><span class="w"> </span><span class="p">!</span><span class="nx">db</span><span class="p">.</span><span class="nf">Table</span><span class="p">(</span><span class="s">&#34;todos&#34;</span><span class="p">).</span><span class="nf">Migrator</span><span class="p">().</span><span class="nf">HasTable</span><span class="p">(</span><span class="s">&#34;todos&#34;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">err</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">db</span><span class="p">.</span><span class="nf">AutoMigrate</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">todo</span><span class="p">{})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">			</span><span class="nx">log</span><span class="p">.</span><span class="nf">Fatal</span><span class="p">(</span><span class="s">&#34;Failed to migrate database&#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">err</span><span class="p">.</span><span class="nf">Error</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>The <code>startup</code> function is called when the app starts. We are using it to connect to the database and create the <code>todos</code> table if it does not exist.</p>
<p>Modify the previous functions to manipulate the DB.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">a</span><span class="w"> </span><span class="o">*</span><span class="nx">App</span><span class="p">)</span><span class="w"> </span><span class="nf">ListTodos</span><span class="p">()</span><span class="w"> </span><span class="p">[]</span><span class="nx">todo</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="c1">// return []todo{{Id: 1, Description: &#34;Code Go&#34;, Due: &#34;2023-10-15&#34;, Status: &#34;In Progress&#34;, Created: &#34;2023-10-01 18:30&#34;}}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="kd">var</span><span class="w"> </span><span class="nx">todos</span><span class="w"> </span><span class="p">[]</span><span class="nx">todo</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">result</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">a</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nf">Find</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">todos</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">if</span><span class="w"> </span><span class="nx">result</span><span class="p">.</span><span class="nx">Error</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nb">panic</span><span class="p">(</span><span class="s">&#34;Failed to retrieve todos: &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">result</span><span class="p">.</span><span class="nx">Error</span><span class="p">.</span><span class="nf">Error</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">return</span><span class="w"> </span><span class="nx">todos</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">a</span><span class="w"> </span><span class="o">*</span><span class="nx">App</span><span class="p">)</span><span class="w"> </span><span class="nf">CreateTodo</span><span class="p">(</span><span class="nx">todoItem</span><span class="w"> </span><span class="nx">todo</span><span class="p">)</span><span class="w"> </span><span class="nx">todo</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;Create: &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nf">prettyPrint</span><span class="p">(</span><span class="nx">todoItem</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="c1">// todoItem.Due, _ = time.Parse(time.RFC3339, todoItem.Due.String())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">result</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">a</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nf">Create</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">todoItem</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">if</span><span class="w"> </span><span class="nx">result</span><span class="p">.</span><span class="nx">Error</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;Failed to create todo item: &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">result</span><span class="p">.</span><span class="nx">Error</span><span class="p">.</span><span class="nf">Error</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="k">return</span><span class="w"> </span><span class="nx">todo</span><span class="p">{}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;db result: &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nf">prettyPrint</span><span class="p">(</span><span class="nx">result</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">return</span><span class="w"> </span><span class="nx">todoItem</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">a</span><span class="w"> </span><span class="o">*</span><span class="nx">App</span><span class="p">)</span><span class="w"> </span><span class="nf">UpdateTodo</span><span class="p">(</span><span class="nx">todoItem</span><span class="w"> </span><span class="nx">todo</span><span class="p">)</span><span class="w"> </span><span class="nx">todo</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;Update: &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nf">prettyPrint</span><span class="p">(</span><span class="nx">todoItem</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">result</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">a</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nf">Save</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">todoItem</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">if</span><span class="w"> </span><span class="nx">result</span><span class="p">.</span><span class="nx">Error</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;Failed to update todo item: &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">result</span><span class="p">.</span><span class="nx">Error</span><span class="p">.</span><span class="nf">Error</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="k">return</span><span class="w"> </span><span class="nx">todo</span><span class="p">{}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;update result: &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nf">prettyPrint</span><span class="p">(</span><span class="nx">todoItem</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">return</span><span class="w"> </span><span class="nx">todoItem</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">a</span><span class="w"> </span><span class="o">*</span><span class="nx">App</span><span class="p">)</span><span class="w"> </span><span class="nf">DeleteTodo</span><span class="p">(</span><span class="nx">todoItem</span><span class="w"> </span><span class="nx">todo</span><span class="p">)</span><span class="w"> </span><span class="nx">todo</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;Delete: &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nf">prettyPrint</span><span class="p">(</span><span class="nx">todoItem</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">result</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">a</span><span class="p">.</span><span class="nx">db</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="s">&#34;id = ?&#34;</span><span class="p">,</span><span class="w"> </span><span class="nx">todoItem</span><span class="p">.</span><span class="nx">Id</span><span class="p">).</span><span class="nf">Delete</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">todoItem</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">if</span><span class="w"> </span><span class="nx">result</span><span class="p">.</span><span class="nx">Error</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;Failed to delete todo item: &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">result</span><span class="p">.</span><span class="nx">Error</span><span class="p">.</span><span class="nf">Error</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">		</span><span class="k">return</span><span class="w"> </span><span class="nx">todo</span><span class="p">{}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;delete result: &#34;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nf">prettyPrint</span><span class="p">(</span><span class="nx">todoItem</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">return</span><span class="w"> </span><span class="nx">todoItem</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">prettyPrint</span><span class="p">(</span><span class="nx">i</span><span class="w"> </span><span class="kd">interface</span><span class="p">{})</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="nx">s</span><span class="p">,</span><span class="w"> </span><span class="nx">_</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">json</span><span class="p">.</span><span class="nf">MarshalIndent</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;&#34;</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;\t&#34;</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">	</span><span class="k">return</span><span class="w"> </span><span class="nb">string</span><span class="p">(</span><span class="nx">s</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>That is it! You now have a fully functional todo app with a database backend.</p>
<h1 id="building-your-app">Building your app</h1>
<p>Building the app is as simple as -</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">wails build
</span></span></code></pre></div><p>You should now see a fully decked up, single executable file in <code>build\bin</code> folder. Key points to note -</p>
<ul>
<li>the file measures some 13 MB</li>
<li>uses ~18 - 25 MB RAM</li>
</ul>
<p>The above measures should provide you a quick idea of the size compared to Electron-based apps (starts from ~85 MB - easily 100 MB+ on disk, 100-200 MB RAM) and native apps (may be in kb&rsquo;s - to a few MBs, and a couple of MBs of RAM).</p>
<p>Note that the db file is not included in the build - the program will just create the database file in the same folder as the executable (&amp; that may be different from the time you were developing the app).</p>
<h1 id="conclusion">Conclusion</h1>
<p>The todo app is a good start, but there are many features of Wails that I am yet to look into including real-time events and using deskop APIs.  You can see/ play around with the complete code on <a href="https://github.com/prashanth1k/go-webview-wails-todo">Github</a>.</p>
<p>Overall, Wails is a great way to build apps with Go and web technologies. It is easy to get started, and the developer experience is great.</p>
<p>Of course, this post would not be complete without mentioning the power of the web and how a few talented individuals (<a href="https://github.com/leaanthony">Lea Anthony</a> in this case) and supportive communities can do for the ecosystem.</p>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
