?? Building a Cross-Platform Memory Monitor App with Go, Wails, and TailwindCSS: My Journey in Crafting a Real-Time UI

?? Building a Cross-Platform Memory Monitor App with Go, Wails, and TailwindCSS: My Journey in Crafting a Real-Time UI

As developers, we're always looking for efficient ways to monitor system performance and create seamless user experiences across different platforms. Recently, I decided to build a cross-platform memory monitor app using Go and Wails, leveraging TailwindCSS for the UI. The goal? A lightweight, real-time memory usage monitor that works on macOS, Windows, and Linux (Ubuntu) and boost my software development skills.

Here's a deep dive into my experience and how you can build a similar app. Let's go! ??

So why I want to use wails ? I am a full stack web developer and I use React a lot. So this is a good point to use some of my knowledge in project.

First of all I need to install Wails. Checkout the document and install wails-cli:

go install github.com/wailsapp/wails/v2/cmd/wails@latest        

Now init the application with wails-cli:

wails init -n gitlab.com/naHDop/sys-monitor -t react-ts        

??? Step 1: Collecting Memory Usage Data with Go

The first step was grabbing system memory data in real-time. I used the gopsutil library in Go to fetch metrics like total memory, used memory, and free memory. I include code into generated (by wails-cli) file `app.go -> func startup` Here's a quick look at how I collected the data:

// startup is called at application startup
func (a *App) startup(ctx context.Context) {
	// Perform your setup here
	a.ctx = ctx
	// Use a ticker to send memory updates to the frontend
	go func() {
		ticker := time.NewTicker(1 * time.Second)
		defer ticker.Stop()

		for {
			select {
			case <-ticker.C:
				v, _ := mem.VirtualMemory()

				// Send memory data to frontend
				runtime.EventsEmit(ctx, "memoryUpdate", v.Total/1024/1024, v.Used/1024/1024, v.Free/1024/1024, v.UsedPercent)
			}
		}
	}()
}        

?? Step 2: Switching to Wails for Modern UI Flexibility

Once the backend logic was up and running, I turned to Wails for building the front-end. Wails lets you build native desktop apps using modern web technologies like React and TailwindCSS while using Go for the backend.

This was a game-changer! With Wails, I could leverage React for the dynamic UI and have real-time updates for the memory data.

?? Real-Time Data Visualization with React and TailwindCSS

Using Recharts in React, I built a real-time line chart to visualize memory usage. So you need to install in in frontend foler

cd frontend
npm i recharts        

Here’s how the core UI component looks (frontend/src/App.tsx):

import './App.css'
import { useEffect, useState } from "react";
import { EventsOn } from "../wailsjs/runtime";
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from "recharts";

function App() {
    const [memoryData, setMemoryData] = useState([{
        timestamp: new Date().toLocaleTimeString(),
        usedPercent: 0,
    }]);
    const [stats, setStats] = useState({
        total: 0,
        used: 0,
        free: 0,
        usedPercent: 0,
    });

    useEffect(() => {
        // Subscribe to the memoryUpdate event from Go backend
        EventsOn("memoryUpdate", (total, used, free, usedPercent) => {
            const timestamp = new Date().toLocaleTimeString();
            setStats({ total, used, free, usedPercent })

            // Append new memory usage data to the chart
            setMemoryData((prevState) => {
                // Ensure the previous data is being accumulated and sliced correctly
                const newData = [...prevState, { timestamp, usedPercent }];
                return newData.slice(-60); // Keep the last 60 points (for example, 60 seconds of data)
            })
        });
    }, []);


    return (
        <div className="min-h-screen bg-gray-100 p-6">
            {/* Header */}
            <header className="mb-8">
                <h1 className="text-3xl font-semibold text-gray-800 text-center">
                    Memory Monitor Dashboard
                </h1>
            </header>

            {/* Memory Stats */}
            <div className="grid grid-cols-1 sm:grid-cols-3 lg:grid-cols-3 gap-6 mb-8">
                <div className="p-4 bg-white shadow-lg rounded-lg">
                    <h2 className="text-m font-medium text-gray-600">Total Memory</h2>
                    <p className="text-xl font-semibold text-gray-900">{stats.total} MB</p>
                </div>
                <div className="p-4 bg-white shadow-lg rounded-lg">
                    <h2 className="text-m font-medium text-gray-600">Used Memory</h2>
                    <p className="text-xl font-semibold text-gray-900">{stats.used} MB</p>
                </div>
                <div className="p-4 bg-white shadow-lg rounded-lg">
                    <h2 className="text-m font-medium text-gray-600">Memory Usage</h2>
                    <p className="text-xl font-semibold text-gray-900">{`${stats.usedPercent.toFixed(2)}%`}</p>
                </div>
            </div>

            {/* Line Chart */}
            <div className="p-4 bg-white shadow-lg rounded-lg">
                <h2 className="text-s font-medium text-gray-600 mb-4">Memory Usage (%)</h2>
                <ResponsiveContainer width="100%" height={200}>
                    <LineChart data={memoryData}>
                        <CartesianGrid strokeDasharray="3 3" />
                        <XAxis dataKey="timestamp" />
                        <YAxis domain={[0, 100]} />
                        <Tooltip />
                        <Line type="monotone" dataKey="usedPercent" stroke={stats.usedPercent > 75 ? "#d88884" : "#8884d8"} strokeWidth={2} dot={false} />
                    </LineChart>
                </ResponsiveContainer>
            </div>
        </div>
    )
}

export default App        

This component dynamically updates every second, displaying memory usage as it changes. TailwindCSS made styling this super smooth and easy! ?

? Challenges Faced and Solutions

Of course, no development journey is complete without its challenges. Here are some issues I faced and how I overcame them:

  1. Real-Time Chart Updates: One challenge was ensuring smooth real-time updates to the line chart. By batching the memory data into an array and using Recharts, I was able to keep the graph running smoothly.
  2. Data Storage and History: Displaying only the most recent memory data point led to an incomplete view of trends. After updating the logic to store previous data points, the chart began showing a history of memory usage over time.
  3. Optimizing UI: Using TailwindCSS, I was able to rapidly build and customize the UI for different screen sizes and use cases. It helped maintain consistency across the app while reducing the manual styling work.



?? Key Learnings from this Experience

This project was an incredible learning experience for me, and here are my key takeaways:

  1. Wails is a fantastic choice for developers looking to combine Go and modern web tech (React, Vue, etc.) for desktop apps. It gives you the best of both worlds—native power with web flexibility.
  2. Go’s concurrency makes it really easy to collect and process data like system memory usage without impacting the app's responsiveness.
  3. TailwindCSS allows for rapid UI prototyping and a consistent design across all screens. It’s particularly useful for building adaptive layouts like this memory monitor.


?? Conclusion

In the end, building this cross-platform memory monitor app was a rewarding experience. I pushed the boundaries of what Go can do in the desktop space, integrated modern web technologies, and created a real-time, visually appealing tool.

Whether you're building cross-platform apps or just exploring Go with modern UIs, I highly recommend Wails for a smooth, developer-friendly experience.

If you're interested in trying this out or have questions, feel free to connect! I'd love to discuss more about Go, Wails, or building cross-platform applications.


要查看或添加评论,请登录

社区洞察

其他会员也浏览了