Skip to content

Commit

Permalink
Update Node.js snippets for ESM
Browse files Browse the repository at this point in the history
  • Loading branch information
Chalarangelo committed Oct 6, 2023
1 parent 6c183f5 commit fb1b4d9
Show file tree
Hide file tree
Showing 12 changed files with 52 additions and 58 deletions.
2 changes: 1 addition & 1 deletion content/collections/js/node.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ description: >-
The Node.js snippet collection contains JavaScript utilities for Node.js
18.x. It includes helper functions related to server-side code and
filesystem operations, while general-purpose helpers can be found in the
JavaScript snippet collection.
JavaScript snippet collection. All snippets can be used with the ESM syntax.
shortDescription: >-
Discover a collection of server-side JavaScript utility functions for
Node.js 18.x.
Expand Down
5 changes: 3 additions & 2 deletions content/snippets/js/s/convert-to-absolute-path.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ Converts a tilde path to an absolute path.
- Use `String.prototype.replace()` with a regular expression and `os.homedir()` to replace the `~` in the start of the path with the home directory.

```js
const untildify = str =>
str.replace(/^~($|\/|\\)/, `${require('os').homedir()}$1`);
import { homedir } from 'os';

const untildify = str => str.replace(/^~($|\/|\\)/, `${homedir()}$1`);
```

```js
Expand Down
4 changes: 2 additions & 2 deletions content/snippets/js/s/create-directory-if-not-exists.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ Creates a directory, if it does not exist.
- Use `fs.existsSync()` to check if the directory exists, `fs.mkdirSync()` to create it.

```js
const fs = require('fs');
import { existsSync, mkdirSync } from 'fs';

const createDirIfNotExists = dir =>
!fs.existsSync(dir) ? fs.mkdirSync(dir) : undefined;
!existsSync(dir) ? mkdirSync(dir) : undefined;
```

```js
Expand Down
4 changes: 2 additions & 2 deletions content/snippets/js/s/hash-node.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ Returns a promise.
- Use `setTimeout()` to prevent blocking on a long operation. Return a `Promise` to give it a familiar interface.

```js
const crypto = require('crypto');
import { createHash } from 'crypto';

const hashNode = val =>
new Promise(resolve =>
setTimeout(
() => resolve(crypto.createHash('sha256').update(val).digest('hex')),
() => resolve(createHash('sha256').update(val).digest('hex')),
0
)
);
Expand Down
2 changes: 1 addition & 1 deletion content/snippets/js/s/is-duplex-stream.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const isDuplexStream = val =>
```

```js
const Stream = require('stream');
import Stream from 'stream';

isDuplexStream(new Stream.Duplex()); // true
```
4 changes: 2 additions & 2 deletions content/snippets/js/s/is-readable-stream.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const isReadableStream = val =>
```

```js
const fs = require('fs');
import { createReadStream } from 'fs';

isReadableStream(fs.createReadStream('test.txt')); // true
isReadableStream(createReadStream('test.txt')); // true
```
4 changes: 2 additions & 2 deletions content/snippets/js/s/is-stream.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const isStream = val =>
```

```js
const fs = require('fs');
import { createReadStream } from 'fs';

isStream(fs.createReadStream('test.txt')); // true
isStream(createReadStream('test.txt')); // true
```
4 changes: 2 additions & 2 deletions content/snippets/js/s/is-writable-stream.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const isWritableStream = val =>
```

```js
const fs = require('fs');
import { createWriteStream } from 'fs';

isWritableStream(fs.createWriteStream('test.txt')); // true
isWritableStream(createWriteStream('test.txt')); // true
```
4 changes: 2 additions & 2 deletions content/snippets/js/s/json-to-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ Writes a JSON object to a file.
- Use `fs.writeFileSync()`, template literals and `JSON.stringify()` to write a `json` object to a `.json` file.

```js
const fs = require('fs');
import { writeFileSync } from 'fs';

const JSONToFile = (obj, filename) =>
fs.writeFileSync(`${filename}.json`, JSON.stringify(obj, null, 2));
writeFileSync(`${filename}.json`, JSON.stringify(obj, null, 2));
```

```js
Expand Down
66 changes: 31 additions & 35 deletions content/snippets/js/s/nodejs-static-file-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ dateModified: 2022-06-05
One of the simplest beginner backend projects you can create is a static file server. In its simplest form, a static file server will listen for requests and try to match the requested URL to a file on the local filesystem. Here's a minimal example of that in action:

```js
const fs = require('fs');
const http = require('http');
import { readFile } from 'fs';
import { createServer } from 'http';

http.createServer((req, res) => {
fs.readFile(__dirname + req.url, (err, data) => {
createServer((req, res) => {
readFile(__dirname + req.url, (err, data) => {
if (err) {
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end('404: File not found');
Expand All @@ -42,15 +42,15 @@ First and foremost, we don't necessarily want to serve files from the same direc
Here's a short snippet on how to resolve a file path using the `path` module:

```js
const fs = require('fs');
const path = require('path');
import { readFile } from 'fs';
import { join } from 'path';

const directoryName = './public';
const requestUrl = 'index.html';

const filePath = path.join(directoryName, requestUrl);
const filePath = join(directoryName, requestUrl);

fs.readFile(filePath, (err, data) => {
readFile(filePath, (err, data) => {
// ...
});
```
Expand All @@ -60,28 +60,26 @@ fs.readFile(filePath, (err, data) => {
Our next concern is security. Obviously, we don't want users prying around our machine unauthorized. Currently, it's not impossible to get access to files outside of the specified root directory (e.g. `GET /../../../`). To address this, we can use the `path` module again to check if the requested file is inside the root directory.

```js
const path = require('path');
import { join, normalize, resolve } from 'path';

const directoryName = './public';
const root = path.normalize(path.resolve(directoryName));
const root = normalize(resolve(directoryName));

const requestUrl = 'index.html';

const filePath = path.join(root, fileName);
const isPathUnderRoot = path
.normalize(path.resolve(filePath))
.startsWith(root);
const filePath = join(root, fileName);
const isPathUnderRoot = normalize(resolve(filePath)).startsWith(root);
```

Similarly, we can ensure that users don't get access to sensitive files by checking the file type. For this to work, we can specify an array or object of supported file types and check the file's extension using the `path` module once again.

```js
const path = require('path');
import { extname } from 'path';

const types = ['html', 'css', 'js', 'json'];

const requestUrl = 'index.html';
const extension = path.extname(requestUrl).slice(1);
const extension = extname(requestUrl).slice(1);

const isTypeSupported = types.includes(extension);
```
Expand All @@ -95,22 +93,22 @@ This is where things get a little tricky. To provide this functionality, we need
To implement this, we can use the `fs` module to check if one of them exists and handle things appropriately. A special case would also need to be added for the root url (`/`) to match it to the `index.html` file.

```js
const fs = require('fs');
const path = require('path');
import { accessSync, constants } from 'fs';
import { join, normalize, resolve, extname } from 'path';

const directoryName = './public';
const root = path.normalize(path.resolve(directoryName));
const root = normalize(resolve(directoryName));

const extension = path.extname(req.url).slice(1);
const extension = extname(req.url).slice(1);
let fileName = requestUrl;

if (requestUrl === '/') fileName = 'index.html';
else if (!extension) {
try {
fs.accessSync(path.join(root, requestUrl + '.html'), fs.constants.F_OK);
accessSync(join(root, requestUrl + '.html'), constants.F_OK);
fileName = requestUrl + '.html';
} catch (e) {
fileName = path.join(requestUrl, 'index.html');
fileName = join(requestUrl, 'index.html');
}
}
```
Expand All @@ -120,9 +118,9 @@ else if (!extension) {
After implementing all of the above, we can put everything together to create a static file server with all the functionality we need. I'll throw in a couple of finishing touches, such as logging requests to the console and handling a few more file types, and here's the final product:

```js
const fs = require('fs');
const http = require('http');
const path = require('path');
import { readFile, accessSync, constants } from 'fs';
import { createServer } from 'http';
import { join, normalize, resolve, extname } from 'path';

const port = 8000;
const directoryName = './public';
Expand All @@ -139,12 +137,12 @@ const types = {
xml: 'application/xml',
};

const root = path.normalize(path.resolve(directoryName));
const root = normalize(resolve(directoryName));

const server = http.createServer((req, res) => {
const server = createServer((req, res) => {
console.log(`${req.method} ${req.url}`);

const extension = path.extname(req.url).slice(1);
const extension = extname(req.url).slice(1);
const type = extension ? types[extension] : types.html;
const supportedExtension = Boolean(type);

Expand All @@ -158,25 +156,23 @@ const server = http.createServer((req, res) => {
if (req.url === '/') fileName = 'index.html';
else if (!extension) {
try {
fs.accessSync(path.join(root, req.url + '.html'), fs.constants.F_OK);
accessSync(join(root, req.url + '.html'), constants.F_OK);
fileName = req.url + '.html';
} catch (e) {
fileName = path.join(req.url, 'index.html');
fileName = join(req.url, 'index.html');
}
}

const filePath = path.join(root, fileName);
const isPathUnderRoot = path
.normalize(path.resolve(filePath))
.startsWith(root);
const filePath = join(root, fileName);
const isPathUnderRoot = normalize(resolve(filePath)).startsWith(root);

if (!isPathUnderRoot) {
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end('404: File not found');
return;
}

fs.readFile(filePath, (err, data) => {
readFile(filePath, (err, data) => {
if (err) {
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end('404: File not found');
Expand Down
7 changes: 2 additions & 5 deletions content/snippets/js/s/read-file-lines.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,10 @@ Returns an array of lines from the specified file.
- Use `String.prototype.split()` to create an array of lines from the contents of the file.

```js
const fs = require('fs');
import { readFileSync } from 'fs';

const readFileLines = filename =>
fs
.readFileSync(filename)
.toString('UTF8')
.split('\n');
readFileSync(filename).toString('UTF8').split('\n');
```

```js
Expand Down
4 changes: 2 additions & 2 deletions content/snippets/js/s/uuid-generator-node.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ Generates a UUID in Node.JS.
- [`crypto.randomUUID()`](https://nodejs.org/api/crypto.html#cryptorandomuuidoptions) provides similar functionality.

```js
const crypto = require('crypto');
import { randomBytes } from 'crypto';

const UUIDGeneratorNode = () =>
([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
(c ^ (crypto.randomBytes(1)[0] & (15 >> (c / 4)))).toString(16)
(c ^ (randomBytes(1)[0] & (15 >> (c / 4)))).toString(16)
);
```

Expand Down

0 comments on commit fb1b4d9

Please sign in to comment.