DEV Community

Tomasz Wegrzanowski
Tomasz Wegrzanowski

Posted on

2 2

Electron Adventures: Episode 88: Svelte CSV Viewer

I want to experiment with a few interesting OS integrations, but first let's get an app for that - a simple CSV viewer is Svelte.

When you start the app, it will open a file dialog and ask you to select one or more CSV files to open. Then it will open a new window for each selected file.

I picked a few CSV example files with Taylor Swift lyrics from Kaggle and put them into samples subfolder.

I'll be using d3-dsv to parse CSV files. It's part of the D3, but it can be used separately, so npm install d3-dsv.

index.js

First, we need to popup the dialog to select the CSV files.

let { app, BrowserWindow, dialog } = require("electron")

async function createWindow() {
  let { canceled, filePaths } = await dialog.showOpenDialog({
    properties: ["openFile", "multiSelections", "showHiddenFiles"],
    filters: [
      { name: "CSV files", extensions: ["csv"] },
      { name: "All Files", extensions: ["*"] }
    ],
    message: "Select a CSV file to open",
    defaultPath: `${__dirname}/samples`,
  })
  if (canceled) {
    app.quit()
  }
  for (let path of filePaths) {
    let qs = new URLSearchParams({ path }).toString();
    let win = new BrowserWindow({
      width: 1024,
      height: 768,
      webPreferences: {
        preload: `${__dirname}/preload.js`,
      },
    })
    win.loadURL(`http://localhost:5000/?${qs}`)
  }
}

app.on("ready", createWindow)

app.on("window-all-closed", () => {
  app.quit()
})
Enter fullscreen mode Exit fullscreen mode

As I mentioned before, this is Electron API weirdness. File dialogs are really a frontend concern, so logically they should go to the frontend process, but Electron API moves them to the backend, so we have to jump through a few hoops here.

For a small change from the hex editor, we setup default filter to only show *.csv files, it can be overridden by the user through the OS-specific filter dropdown.

preload.js

let fs = require("fs")
let { contextBridge } = require("electron")

let q = new URLSearchParams(window.location.search)

let path = q.get("path")
let data = fs.readFileSync(path, "utf8")

contextBridge.exposeInMainWorld(
  "api", { path, data }
)
Enter fullscreen mode Exit fullscreen mode

A small change from the hex editor, we want to return a String, not a Buffer, so we assume CSV is in UTF8. If it's not, well, it's 21st century, you should have fixed that already.

src/App.svelte

And now for a very simple CSV viewer - we just dump everything into a simple HTML table, with no special handling of headers, or data types, or anything.

<script>
  import {csvParseRows} from "d3-dsv"

  let data = csvParseRows(window.api.data)
  let fileName = window.api.path.split("/").slice(-1)[0]
  let title = `CSV Viewer - ${fileName}`
</script>

<h1>CSV Viewer</h1>

<table>
  {#each data as row}
    <tr>
      {#each row as column}
        <td>{column}</td>
      {/each}
    </tr>
  {/each}
</table>


<svelte:head>
  <title>{title}</title>
</svelte:head>

<style>
:global(body) {
  margin: 0;
  background-color: #444;
  color: #fff;
}
tr {
  text-align: center;
}
</style>
Enter fullscreen mode Exit fullscreen mode

Results

Here's the results:

Episode 88 Screenshot

Now that we have a base app, we'll be adding a few interesting enhancements to it over the next few episodes.

As usual, all the code for the episode is here.

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

SurveyJS custom survey software

JavaScript Form Builder UI Component

Generate dynamic JSON-driven forms directly in your JavaScript app (Angular, React, Vue.js, jQuery) with a fully customizable drag-and-drop form builder. Easily integrate with any backend system and retain full ownership over your data, with no user or form submission limits.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay