Skip to content

Commit

Permalink
docs: rework of the tutorial
Browse files Browse the repository at this point in the history
  • Loading branch information
darrachequesne committed Sep 8, 2023
1 parent 08cf30a commit fa75c7d
Show file tree
Hide file tree
Showing 33 changed files with 3,989 additions and 9 deletions.
82 changes: 82 additions & 0 deletions docs/tutorial/01-introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
title: Tutorial - Introduction
sidebar_label: Introduction
slug: introduction
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Getting started

Welcome to the Socket.IO tutorial!

In this tutorial we'll create a basic chat application. It requires almost no basic prior knowledge of Node.JS or Socket.IO, so it’s ideal for users of all knowledge levels.

## Introduction

Writing a chat application with popular web applications stacks like LAMP (PHP) has normally been very hard. It involves polling the server for changes, keeping track of timestamps, and it’s a lot slower than it should be.

Sockets have traditionally been the solution around which most real-time chat systems are architected, providing a bi-directional communication channel between a client and a server.

This means that the server can *push* messages to clients. Whenever you write a chat message, the idea is that the server will get it and push it to all other connected clients.

## How to use this tutorial

### Tooling

Any text editor (from a basic text editor to a complete IDE such as [VS Code](https://code.visualstudio.com/)) should be sufficient to complete this tutorial.

Additionally, at the end of each step you will find a link to some online platforms ([CodeSandbox](https://codesandbox.io) and [StackBlitz](https://stackblitz.com), namely), allowing you to run the code directly from your browser:

![Screenshot of the CodeSandbox platform](/images/codesandbox.png)

### Syntax settings

In the Node.js world, there are two ways to import modules:

- the standard way: ECMAScript modules (or ESM)

```js
import { Server } from "socket.io";
```

Reference: https://nodejs.org/api/esm.html

- the legacy way: CommonJS

```js
const { Server } = require("socket.io");
```

Reference: https://nodejs.org/api/modules.html

Socket.IO supports both syntax.

:::tip

We recommend using the ESM syntax in your project, though this might not always be feasible due to some packages not supporting this syntax.

:::

For your convenience, throughout the tutorial, each code block allows you to select your preferred syntax:

<Tabs groupId="lang">
<TabItem value="cjs" label="CommonJS" default>

```js
const { Server } = require("socket.io");
```

</TabItem>
<TabItem value="mjs" label="ES modules">

```js
import { Server } from "socket.io";
```

</TabItem>
</Tabs>


Ready? Click "Next" to get started.
139 changes: 139 additions & 0 deletions docs/tutorial/02-project-initialization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
---
title: "Tutorial step #1 - Project initialization"
sidebar_label: "Step #1: Project initialization"
slug: step-1
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Project initialization

The first goal is to set up a simple HTML webpage that serves out a form and a list of messages. We’re going to use the Node.JS web framework `express` to this end. Make sure [Node.JS](https://nodejs.org) is installed.

First let’s create a `package.json` manifest file that describes our project. I recommend you place it in a dedicated empty directory (I’ll call mine `socket-chat-example`).

<Tabs groupId="lang">
<TabItem value="cjs" label="CommonJS" default>

```json
{
"name": "socket-chat-example",
"version": "0.0.1",
"description": "my first socket.io app",
"type": "commonjs",
"dependencies": {}
}
```

</TabItem>
<TabItem value="mjs" label="ES modules">

```json
{
"name": "socket-chat-example",
"version": "0.0.1",
"description": "my first socket.io app",
"type": "module",
"dependencies": {}
}
```

</TabItem>
</Tabs>

:::caution

The "name" property must be unique, you cannot use a value like "socket.io" or "express", because npm will complain when installing the dependency.

:::

Now, in order to easily populate the `dependencies` property with the things we need, we’ll use `npm install`:

```
npm install express@4
```

Once it's installed we can create an `index.js` file that will set up our application.

<Tabs groupId="lang">
<TabItem value="cjs" label="CommonJS" default>

```js
const express = require('express');
const { createServer } = require('node:http');

const app = express();
const server = createServer(app);

app.get('/', (req, res) => {
res.send('<h1>Hello world</h1>');
});

server.listen(3000, () => {
console.log('server running at http://localhost:3000');
});
```

</TabItem>
<TabItem value="mjs" label="ES modules">

```js
import express from 'express';
import { createServer } from 'node:http';

const app = express();
const server = createServer(app);

app.get('/', (req, res) => {
res.send('<h1>Hello world</h1>');
});

server.listen(3000, () => {
console.log('server running at http://localhost:3000');
});
```

</TabItem>
</Tabs>

This means that:

- Express initializes `app` to be a function handler that you can supply to an HTTP server (as seen in line 5).
- We define a route handler `/` that gets called when we hit our website home.
- We make the http server listen on port 3000.

If you run `node index.js` you should see the following:

<img src="/images/chat-1.png" alt="A console saying that the server has started listening on port 3000" />

And if you point your browser to `http://localhost:3000`:

<img src="/images/chat-2.png" alt="A browser displaying a big 'Hello World'" />

So far, so good!

:::tip

<Tabs groupId="lang">
<TabItem value="cjs" label="CommonJS" default attributes={{ className: 'display-none' }}>

You can run this example directly in your browser on:

- [CodeSandbox](https://codesandbox.io/p/sandbox/github/socketio/chat-example/tree/cjs/step1?file=index.js)
- [StackBlitz](https://stackblitz.com/github/socketio/chat-example/tree/cjs/step1?file=index.js)


</TabItem>
<TabItem value="mjs" label="ES modules" attributes={{ className: 'display-none' }}>

You can run this example directly in your browser on:

- [CodeSandbox](https://codesandbox.io/p/sandbox/github/socketio/chat-example/tree/esm/step1?file=index.js)
- [StackBlitz](https://stackblitz.com/github/socketio/chat-example/tree/esm/step1?file=index.js)


</TabItem>
</Tabs>

:::
121 changes: 121 additions & 0 deletions docs/tutorial/03-serving-html.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
---
title: "Tutorial step #2 - Serving HTML"
sidebar_label: "Step #2: Serving HTML"
slug: step-2
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Serving HTML

So far in `index.js` we’re calling `res.send` and passing it a string of HTML. Our code would look very confusing if we just placed our entire application’s HTML there, so instead we're going to create a `index.html` file and serve that instead.

Let’s refactor our route handler to use `sendFile` instead.

<Tabs groupId="lang">
<TabItem value="cjs" label="CommonJS" default>

```js
const express = require('express');
const { createServer } = require('node:http');
// highlight-start
const { join } = require('node:path');
// highlight-end

const app = express();
const server = createServer(app);

// highlight-start
app.get('/', (req, res) => {
res.sendFile(join(__dirname, 'index.html'));
});
// highlight-end

server.listen(3000, () => {
console.log('server running at http://localhost:3000');
});
```

</TabItem>
<TabItem value="mjs" label="ES modules">

```js
import express from 'express';
import { createServer } from 'node:http';

const app = express();
const server = createServer(app);

// highlight-start
app.get('/', (req, res) => {
res.sendFile(new URL('./index.html', import.meta.url).pathname);
});
// highlight-end

server.listen(3000, () => {
console.log('server running at http://localhost:3000');
});
```
</TabItem>
</Tabs>
Put the following in your `index.html` file:
```html
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Socket.IO chat</title>
<style>
body { margin: 0; padding-bottom: 3rem; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }

#form { background: rgba(0, 0, 0, 0.15); padding: 0.25rem; position: fixed; bottom: 0; left: 0; right: 0; display: flex; height: 3rem; box-sizing: border-box; backdrop-filter: blur(10px); }
#input { border: none; padding: 0 1rem; flex-grow: 1; border-radius: 2rem; margin: 0.25rem; }
#input:focus { outline: none; }
#form > button { background: #333; border: none; padding: 0 1rem; margin: 0.25rem; border-radius: 3px; outline: none; color: #fff; }

#messages { list-style-type: none; margin: 0; padding: 0; }
#messages > li { padding: 0.5rem 1rem; }
#messages > li:nth-child(odd) { background: #efefef; }
</style>
</head>
<body>
<ul id="messages"></ul>
<form id="form" action="">
<input id="input" autocomplete="off" /><button>Send</button>
</form>
</body>
</html>
```
If you restart the process (by hitting Control+C and running `node index.js` again) and refresh the page it should look like this:
<img src="/images/chat-3.png" alt="A browser displaying an input and a 'Send' button" />
:::tip
<Tabs groupId="lang">
<TabItem value="cjs" label="CommonJS" default attributes={{ className: 'display-none' }}>
You can run this example directly in your browser on:
- [CodeSandbox](https://codesandbox.io/p/sandbox/github/socketio/chat-example/tree/cjs/step2?file=index.js)
- [StackBlitz](https://stackblitz.com/github/socketio/chat-example/tree/cjs/step2?file=index.js)
</TabItem>
<TabItem value="mjs" label="ES modules" attributes={{ className: 'display-none' }}>
You can run this example directly in your browser on:
- [CodeSandbox](https://codesandbox.io/p/sandbox/github/socketio/chat-example/tree/esm/step2?file=index.js)
- [StackBlitz](https://stackblitz.com/github/socketio/chat-example/tree/esm/step2?file=index.js)
</TabItem>
</Tabs>
:::
Loading

0 comments on commit fa75c7d

Please sign in to comment.