Build an application with Github Copilot X - part 1
Tags: githubcopilot, nextjs, programming, webdev
Published: 2023-05-23 22:52:16

If you are going to become a parent, you have to decide on a name for your newborn child. Depending on how many people are involved in the decision process, often times at least two, it's not an easy task.

I don't know how you see it, but for me naming girls was always 10x easier then boys.
What all of this has to do with Github Copilot X? I just got access to the private beta. And after my wife and I tried an app with Tinder-like matching for child names, I got a bit frustrated with what I found. Server barley reachable, the invite of my partner, for matches to even be possible, not working and some design decisions let me think: hey, maybe some AI magic with the new tool might enable me to quickly set this up.

Now, I set myself a timer for 60 minutes and we see where we land.

What tools will we be using? I decided to go with my current favorites:

- NextJS
- Tailwind & shadcn/ui
- Supabase
- Github Copilot Chat
- VS Code Insider Preview

First small hint: I have to use the Insider Preview of VS 
Code, to be able to use the new Github Copilot.

First I need to find a list of names. 15 minutes of my time already spent, I found a database of names given to children in cologne. That will do for the moment.

I open my console and type following command:

`npx create-next-app@latest --typescript`

Notice the "@latest". This I needed to set to get the latest version (13.4.3 as of now), where app router is stable. I also gone with typescript, as I usually do. 40 minutes left.

At this point I have to mention, I would have gone with create-t3-app, but they are not yet supporting app router in NextJS, therefore I've gone with plain NextJS.

After deleting the boilerplate, let's dive into Github Copilot Chat.

My first task was to take the CSV and process it. Prompt:

> Create a typescript function to process a CSV file and and insert the data into a database. The columns are "Jahr" (number), "vorname" (string), "anzahl" (number) and "geschlecht" (string)

That was my result:

```typescript
import fs from 'fs';
import csv from 'csv-parser';
import { createClient } from '@supabase/supabase-js';

interface Row {
  Jahr: number;
  vorname: string;
  anzahl: number;
  geschlecht: string;
}

async function processCsvFile(filePath: string) {
  const supabaseUrl = 'https://your-supabase-url.supabase.co';
  const supabaseKey = 'your-supabase-key';
  const supabase = createClient(supabaseUrl, supabaseKey);

  const stream = fs.createReadStream(filePath).pipe(csv<Row>());

  for await (const row of stream) {
    const { Jahr, vorname, anzahl, geschlecht } = row;

    const { error } = await supabase.from('mytable').insert([{ Jahr, vorname, anzahl, geschlecht }]);

    if (error) {
      console.error(error);
    }
  }
}
```

Honestly not bad. It also gave comments what packages to use.

`npm i @supabase/supabase-js csv-parser`

I then went ahead and connected the project to Vercel for deployment and Supabase for the backend. I won't add this here, you can find tons of resources in the respective docs.

Copying the code I noticed, that the generic call of "csv" is not working. There we had some hallucination I fear. I asked Copilot to fix it's mistake. But it only renamed the import and did not get his error. At this point I called it a day and searched for the library docs and fixed it myself.

Next try. We need an upload field to get the file in.

> Create a component for uploading a csv and call the function "processCsvFile" from the getNames file
 
We've done it this time. it gave me following component:

```typescript
import { useState } from 'react';
import { processCsvFile } from '../lib/getNames';

export default function CsvUploader() {
  const [file, setFile] = useState<File | null>(null);

  const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const selectedFile = event.target.files?.[0];
    if (selectedFile) {
      setFile(selectedFile);
      const path = URL.createObjectURL(selectedFile);
      processCsvFile(path);
    }
  };

  return (
    <div>
      <label htmlFor="csv-file">Upload CSV file:</label>
      <input type="file" id="csv-file" accept=".csv" onChange={handleFileChange} />
    </div>
  );
}
```

While, after correcting the import path, the code compiled, I was not able to use the component without 'use client'. End even then the compiler wasn't happy, because he could not find fs.

I guess it has something to do with server side and client side rendering.

At this point my time was up and we have to make this a multi part story.

First impression of Copilot Chat: I have the access for 1,5 days at this point. And I have the feeling, that the hallucination issue is very present. My zero show approach might need some more prompt design, but nevertheless it's a bit disappoint for the moment. We'll try better prompts next time and see, if we just got caught in a bad example.

I'll keep you updated next time I go into this. Until then, thanks for reading and have a nice week!

Kind regards
Eddi