Skip to content

Commit

Permalink
feat: add a new blog
Browse files Browse the repository at this point in the history
  • Loading branch information
DevanshBajaj committed Jun 17, 2024
1 parent 2915eeb commit 9f86112
Show file tree
Hide file tree
Showing 3 changed files with 249 additions and 138 deletions.
148 changes: 148 additions & 0 deletions posts/nextjs-ssr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
---
title: 'Getting Started with Server-Side Rendering in Next.js Using SQLite'
date: '2023-06-17'
author: 'devansh bajaj'
image: '../images/profile.png'
---

## Introduction to Server-Side Rendering in Next.js with an Example

### What is Server-Side Rendering?

Server-Side Rendering (SSR) is a data rendering method in which web pages are loaded on the server rather than in the client's browser. This means that the server generates the required content, such as the HTML file, and sends it to the client, where it is then displayed without any delays. This approach improves performance, enhances SEO, and enhances user experience by rendering the content quickly.

### What Are We Going to Do?

We will create a simple Next.js project to learn how to get started with SSR and how to call a database query directly in a Next.js page. In case someone is concerned about the safety of this approach, I will address that first.

### Is It Unsafe?

This approach is completely safe for demonstrating the power of a server component as it does not expose any database secrets to the client-side and queries the database from the server only. Additionally, it is advantageous because we can skip the API layer for a quick demonstration. (P.S.: You can also implement an API layer in a Next.js project, which we can discuss in a different blog.)

<br />

### Let's Dive Into a Step-by-Step Tutorial

#### Step 1: Set Up Your Next.js Project

First, make sure you have Node.js and npm installed on your machine. Then, create a new Next.js project by running the following command:

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

Fill in the prompts as you see fit. Here is what I selected:

```bash
✔ What is your project named? sql_next
✔ Would you like to use TypeScript? Yes
✔ Would you like to use ESLint? Yes
✔ Would you like to use Tailwind CSS? Yes
✔ Would you like to use `src/` directory? Yes
✔ Would you like to use App Router? (recommended) Yes
✔ Would you like to customize the default import alias (@/*)? Yes
```

Now, install the sqlite3 dependency that we require for the database:

```bash
npm install sqlite3
```

#### Step 2: Create a Server-Side Rendered Page

Here is how you can create an SSR page:

1. **Create a new route in the `app` directory**:
Structure: `app/ssr/page.tsx`

2. **Add the data fetching logic to the page**:
Create a `getData` function where we will perform our database operations and return the data.


```typescript
import { FC } from "react";
import sqlite3 from "sqlite3";
import { promisify } from "util";

type Quote = {
id: number;
text: string;
};

type Props = {
data: Quote[];
};

const getData = async (): Promise<Quote[]> => {

// Create new DB
const db = new sqlite3.Database(":memory:");
const run = promisify(db.run.bind(db));
const all = promisify(db.all.bind(db));

// Create a table and insert some data
await run("CREATE TABLE quotes (id INTEGER PRIMARY KEY, text TEXT)");
const insertStmt = await db.prepare("INSERT INTO quotes (text) VALUES (?)");
const quotes = [
"The only limit to our realization of tomorrow is our doubts of today.",
"Do not wait to strike till the iron is hot; but make it hot by striking.",
"The future belongs to those who believe in the beauty of their dreams.",
"The best way to predict the future is to create it.",
"You miss 100% of the shots you don't take.",
];

for (const quote of quotes) {
await insertStmt.run(quote);
}

await promisify(insertStmt.finalize.bind(insertStmt))();
const data = await all("SELECT id, text FROM quotes");
await db.close();
return data as Quote[];
};

```

In this async function, we handle the creation, insertion, and fetching of data from the SQLite database.

`promisify` is used to convert the `db.run` and `db.all` methods to their promise-based versions so that we can use `await` within the async function.

We have used some motivational quotes here because who doesn't like a bit of motivation while learning something new?

3. **Add a server component to render the data list on the page**:
Add the following code right below our function. This `SSRPage` component will return and render the data on the page.

``` typescript
// below the code mentioned above
const SSRPage: FC<Props> = async () => {
const data = await getData();

return (
<div className="flex flex-col gap-4 m-8">
<h1>Server-Side Rendering with Next.js App Router</h1>
<p>Quotes fetched from the database:</p>
<ol className="flex flex-col gap-2 ml-4 list-inside list-decimal">
{data.map((quote) => (
<li key={quote.id}>{quote.text}</li>
))}
</ol>
</div>
);
};

export default SSRPage;
```
### Conclusion

This was a simple example to showcase the possibilities of SSR in Next.js, providing significant performance and SEO benefits. By following this tutorial, you’ve learned how to set up a server-side rendered page, fetch data from a database, and use the new App Router introduced in Next.js 13.

Feel free to experiment further with this example and explore additional features such as Static Site Generation (SSG), API routes, and dynamic routing.

Thank you for reading!

### Important Links

1. [Next.js Documentation](https://nextjs.org/docs/app)
2. [SQLite3 on npm](https://www.npmjs.com/package/sqlite3)

38 changes: 0 additions & 38 deletions posts/placeholder.md

This file was deleted.

201 changes: 101 additions & 100 deletions styles/global.css
Original file line number Diff line number Diff line change
@@ -1,101 +1,102 @@
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700;800&display=swap');

:root {
--theme-bg: #ffffff;
--theme-bgcode: #1F1E1F;
--theme-text: #000;
--theme-accent: #D81B60;
--theme-sectext: #828282;
--transition: all 0.25s cubic-bezier(0.65, 0.05, 0.36, 1);
}
html [data-theme="light"], [data-theme='light'] {
--theme-bg: #ffffff;
--theme-bgcode: #1F1E1F;
--theme-text: #000;
--theme-accent: #D81B60;
--theme-sectext: #828282;
}
[data-theme="dark"], [data-theme='dark'] {
--theme-bg: #212121;
--theme-bgcode: #212121;
--theme-text: #ffffff;
--theme-accent: #D81B60;
--theme-sectext: #CFCFCF;
}
[data-theme="nord"] , [data-theme='nord'] body {
--theme-bg: #1F1E1F;
--theme-bgcode: #1F1E1F;
--theme-text: #ffffff;
--theme-accent: #9AC1B4;
--theme-sectext: #CFCFCF;
}
[data-theme="blue"] , [data-theme='blue'] body {
--theme-bg: #161c35;
--theme-bgcode: #161c35;
--theme-text: #ffffff;
--theme-accent: #7c91e2;
--theme-sectext: #CFCFCF;
}


html,
body {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
font-family: 'Poppins', sans-serif;
line-height: 1.6;
font-size: 18px;
background-color: var(--theme-bg);
color: var(--theme-text);
}

* {
box-sizing: border-box;
}

a {
text-decoration: none;
}

img {
max-width: 100%;
display: block;
}

select {
-webkit-appearance: none;
appearance: none;
}

.container {
max-width: 36rem;
padding: 0 1rem;
margin: 1rem auto 8rem;
min-height: 100%;
display: flex;
flex-direction: column;
align-items: stretch;
}

::-webkit-scrollbar {
width: 6px;
height: 4px;
}
::-webkit-scrollbar-track {
background: var(--theme-bg);
}

::-webkit-scrollbar-thumb {
border: 4px solid rgba(0, 0, 0, 0);
background-clip: padding-box;
border-radius: 9999px;
background: var(--theme-accent);
}

@media (max-width: 767px) {
.container{
margin: 1rem auto 0rem;
}
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700;800&display=swap');

:root {
--theme-bg: #ffffff;
--theme-bgcode: #1F1E1F;
--theme-text: #000;
--theme-accent: #D81B60;
--theme-sectext: #828282;
--transition: all 0.25s cubic-bezier(0.65, 0.05, 0.36, 1);
}
html [data-theme="light"], [data-theme='light'] {
--theme-bg: #ffffff;
--theme-bgcode: #1F1E1F;
--theme-text: #000;
--theme-accent: #D81B60;
--theme-sectext: #828282;
}
[data-theme="dark"], [data-theme='dark'] {
--theme-bg: #212121;
--theme-bgcode: #212121;
--theme-text: #ffffff;
--theme-accent: #D81B60;
--theme-sectext: #CFCFCF;
}
[data-theme="nord"] , [data-theme='nord'] body {
--theme-bg: #1F1E1F;
--theme-bgcode: #1F1E1F;
--theme-text: #ffffff;
--theme-accent: #9AC1B4;
--theme-sectext: #CFCFCF;
}
[data-theme="blue"] , [data-theme='blue'] body {
--theme-bg: #161c35;
--theme-bgcode: #161c35;
--theme-text: #ffffff;
--theme-accent: #7c91e2;
--theme-sectext: #CFCFCF;
}


html,
body {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
font-family: 'Poppins', sans-serif;
line-height: 1.6;
font-size: 18px;
background-color: var(--theme-bg);
color: var(--theme-text);
}

* {
box-sizing: border-box;
}

a {
text-decoration: none;
color: var(--theme-accent);
}

img {
max-width: 100%;
display: block;
}

select {
-webkit-appearance: none;
appearance: none;
}

.container {
max-width: 36rem;
padding: 0 1rem;
margin: 1rem auto 8rem;
min-height: 100%;
display: flex;
flex-direction: column;
align-items: stretch;
}

::-webkit-scrollbar {
width: 6px;
height: 4px;
}
::-webkit-scrollbar-track {
background: var(--theme-bg);
}

::-webkit-scrollbar-thumb {
border: 4px solid rgba(0, 0, 0, 0);
background-clip: padding-box;
border-radius: 9999px;
background: var(--theme-accent);
}

@media (max-width: 767px) {
.container{
margin: 1rem auto 0rem;
}
}

0 comments on commit 9f86112

Please sign in to comment.