DEV Community

Vivian
Vivian

Posted on

OSD600 - Refactoring My SSG

1. Lab5 requirement

As my-ssg was updated with a lot of new features over the past few weeks and these features were written by different contributors, my-ssg's source code will unavoidably contain duplicated logic, inconsistent naming conventions, etc...

This lab requires us to refactor the existing code so its structure and maintainability will be improved. Additionally, this is a good practice for using git rebase we have learned this week.

Here are some modifications I had applied to my-ssg:
Applied modifications

2. Refactoring process

First of all, I started looking at the index.js file where option declarations and input path validation are placed. This file seemed a bit lengthy back to the time so I decided to extract checkInput() and trackDistFolder() into a newly module.

Secondly, I realized that using global variables is not necessary and some variable names and file names are not really good. As a result, I changed global variables to scoped variables and renamed some variables/file names to get more meaningful names.

During the refactor process, I encountered some errors and these errors made my program exit inappropriately. Therefore, whenever there is an error, I will display a log message and use return statement with a non-zero exit code to solve this situation.

 try {
    await fsPromise.mkdir("./dist");
    console.log(chalk.bold.green("--- dist folder is created successfully! ---"));
  } catch (err) {
    console.log(chalk.bold.red("***Cannot create dist folder!***"));
    return process.exit(-1);
  }
Enter fullscreen mode Exit fullscreen mode

Next, as I stated above, it is inevitable for the source code to not contain any logic repetition. Not surprisingly, I could find some here:

  • Repeated logic and not clear variable names:
const sortedFile = files.filter((file) => path.extname(`${inputPath}/${file}`) === ".txt");

sortedFile.forEach((file) => { 
const fileName = fileModule.readFile(`${inputPath}/${file}`, cssLink, language, outputContainer);
const url = `./${encodeURI(fileName)}.html`;
body += `<a href=\"${url}\">${fileName}</a>\n`;
});

const sortedMDFile = files.filter((file) => path.extname(`${inputPath}/${file}`) === ".md");

sortedMDFile.forEach((file) => {
const fileName = fileModule.readFile(`${inputPath}/${file}`, cssLink, language, outputContainer);
const url = `./${encodeURI(fileName)}.html`;
body += `<a href=\"${url}\">${fileName}</a>\n`;
});

Enter fullscreen mode Exit fullscreen mode

---> Solution:
----> Create getBodyHTML():

function getBodyHTML(path, stylesheet, language, outputContainer, fileExtension){
  let fileName = fileExtension == ".txt" 
                 ? readFile(path, stylesheet, language, outputContainer) 
                 : readMDFile(path, stylesheet, language, outputContainer) ;
  let url = `./${encodeURI(fileName)}.html`;
  return `<a href=\"${url}\">${fileName}</a><br>\n`;
}
Enter fullscreen mode Exit fullscreen mode

----> Rename variables:

const textFile = files.filter((file) => path.extname(`${pathToFile}/${file}`) === ".txt");
textFile.forEach((file) => {
      body += getBodyHTML(`${pathToFile}/${file}`, stylesheet, language, outputContainer, ".txt");
    });

 const mdFile = files.filter((file) => path.extname(`${pathToFile}/${file}`) === ".md");
    mdFile.forEach((file) => {
     body += getBodyHTML(`${pathToFile}/${file}`, stylesheet, language, outputContainer, ".md");
    });

Enter fullscreen mode Exit fullscreen mode
  • Since I just created the checkInput module, now I can use it after finishing reading a .json file instead of copying the same checking logic in index.js as before:
const fs = require("fs");
const check = require("./checkInput");

module.exports.readJson = (pathToFile) => {
  fs.readFile(pathToFile, "utf8", (err, json) => {
    if (err) {
      console.log(chalk.bold.red("***Cannot read the file!***"));
      return process.exit(-1);
    }
    const data = JSON.parse(json);

    const stylesheet = data.stylesheet || "https://cdn.jsdelivr.net/npm/water.css@2/out/water.css";
    const language = data.lang || "en-CA";

    check.checkInput(data.input, stylesheet, language, true);
  });
};
Enter fullscreen mode Exit fullscreen mode

After all, my final commit is 92e007

3. Rebasing

Overall, git rebase -i is a very helpful command. It helped me to squash multiple commits into a single one. Meanwhile, git commit --amend allowed me to adding or modifying the commit message so it will be more meaningful and understandable.

Top comments (0)