OSD600- Improving Siteit through refactoring and upgrading to ESM
Tags: opensource, ssg, javascript, es6
Published: 2022-11-02 00:09:23


[Siteit](https://github.com/SerpentBytes/siteit) has undergone profound changes as I did some significant refactoring and upgrading. It was a _time-consuming_ and _thought-provoking_ procedure overall. Nonetheless, it improved the source code and also my coding skills. 

### Converting to ESM
I have longed to try out the new ECMAScript features, so converting the source code into a `module` was necessary. This process was not as simple as updating the `package.json` by adding the property `type: module`. I had to also set up Babel and Webpack configuration for Siteit to benefit from the new and experimental ES syntax. 

#### Outcome
Instead of importing the files and modules the _old way_:
```node
var fs = require('fs')
```
I can do the same using the following syntax:

```node
import fs from 'fs'
```
Moreover, I can assign default parameters as follows:
```node
const functionName = (value = "hello") => console.log(value)
```
These are some ways Siteit is benefiting from the new ES syntax. I listed only some of the features of ES I have implemented in Siteit recently, as the main focus of this blog entry is how I improved Siteit source code through refactoring techniques. 

---

## Refactoring the Code

### Extracting functions
- `parseFileName`
- `generateMarkup`

#### Extracting `parseFileName`
- Extracting this function was necessary throughout the `html-generator.js` file, as there are multiple instances where we have to chain multiple function calls to produce the filename for the rendered `HTML` document. 

```node
const parseFileName = (filePath, newExt = '') => {
    return path
        .basename(filePath)
        .replace(getFileExt(filePath), newExt ? newExt : '')
}
``` 
- The `parseFileName` function has two use cases:
1. Return only the file name (without extension)
2. Return the file name (with extension passed as  2nd argument)

#### Extracting `generateMarkup`
-  `generateMarkup` is another function necessary to extract, as the lines of code responsible for producing markup are repeated several times throughout the `html-generator.js`, with slight modifications. 

```node
const generateMarkup = (data, isIndex = false, fileExt = '') => {
    const contentForIndex = `<ul>${data.mainContent}</ul>`
    const headingForTxtFile =
        fileExt === '.txt' ? `<h1>${data.mainHeading}</h1>` : ''
    let markup = `<!DOCTYPE html>
        <html lang="en">
        <head>
        <meta charset="utf-8">
        ${styles}
        <title>${data.title ? data.title : 'Index'}</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        </head>
        <body>
        ${isIndex ? '<h1>Index</h1>' : headingForTxtFile}
        ${isIndex ? contentForIndex : data.mainContent}
        </body>
        </html>`

    return markup
}
```
- The parseFileName function has three use cases:

1. Return HTML `markup` for the index file.  
2. Return HTML `markup` for a `.txt` format file.
3. Return HTML `markup` for a `.md` format file.

### Extracting the `FileParser` class
- There were many functions in `utility.js` that operated on a shared source, depended on one another, and all dealt with process file operation. It made sense to combine all this logic into one class. This was hectic as some lines of code were introduced by the project contributors. 

```node
export class FileParser {
    constructor(source) {
        this.source = source[1].splice(1).toString().replace(',', ' ')
    }
    distManager() {
      // manage creation and deletion of the output directory
    }
    processFile(altSrc) {
      // process a single file 
      // invokes distManager 
   
    }
    processDir(altSrc) {
      // processes a directory
      // invokes processFile
    }
    processInput(altSrc) {
      // invokes processFile or processDir based on the source 
    }
    processConfig() {
      /// parsed JSON object and invokes processInput
    }
}
```
I have omitted the member function logic as it would make this blog entry long. Click [here](https://github.com/SerpentBytes/siteit/blob/master/src/file-parser.js) to see the full implementation

#### Splitting the Code
Since `FileParser` as a class was massive in `utility.js`, I moved it to a new file named `file-parser`. 

### Outcome
- Less repetition in code as a single call to `parseFileName` and `generateMarkup` with correct parameters is enough. 
- The `utility.js` is shorter now, as we have grouped the logic associated with incoming file management into a single class called `FileParser`, which is in a different file. 

## Make code Prettier
Earlier in the semester, I got feedback to format my source code and the rendered HTML using Prettier instead of Pretty. I have modified the scripts in `package.json` to ensure the code is formatted each time the user executes the `npm` scripts; prettier reformats the source code. 
The updated scripts look as follows:
```node
scripts": {
 "build": "babel ./src -d build && npx prettier --write .",
 "start": "npm run build && node build/index.js -v"
}
```
## Conclusion
Not only did I learn different techniques to refactor my code, but I also learned how to interactively `rebase` my code and `merge` it to the `master` branch.

 It's really interesting how much progress I have made in a span of a few weeks.