DEV Community

Cover image for OSD600- Improving Siteit through refactoring and upgrading to ESM
TD
TD

Posted on • Edited on

OSD600- Improving Siteit through refactoring and upgrading to ESM

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:

var fs = require('fs')
Enter fullscreen mode Exit fullscreen mode

I can do the same using the following syntax:

import fs from 'fs'
Enter fullscreen mode Exit fullscreen mode

Moreover, I can assign default parameters as follows:

const functionName = (value = "hello") => console.log(value)
Enter fullscreen mode Exit fullscreen mode

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.
const parseFileName = (filePath, newExt = '') => {
    return path
        .basename(filePath)
        .replace(getFileExt(filePath), newExt ? newExt : '')
}
Enter fullscreen mode Exit fullscreen mode
  • The parseFileName function has two use cases:
  • Return only the file name (without extension)
  • 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.
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
}
Enter fullscreen mode Exit fullscreen mode
  • 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.
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
    }
}
Enter fullscreen mode Exit fullscreen mode

I have omitted the member function logic as it would make this blog entry long. Click here 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:

scripts": {
 "build": "babel ./src -d build && npx prettier --write .",
 "start": "npm run build && node build/index.js -v"
}
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)