Skip to content

Instantly share code, notes, and snippets.

@haxxxton
Last active March 1, 2023 13:25
Show Gist options
  • Save haxxxton/1ae485b1896eed22d8f16808de696a02 to your computer and use it in GitHub Desktop.
Save haxxxton/1ae485b1896eed22d8f16808de696a02 to your computer and use it in GitHub Desktop.
Used to fix htmlentities that are incorrectly parsed/output during react-email's build process.

HTML Entity Fixer

Execute after running react-email's export command: eg

email export --pretty true --outDir output && ts-node ./htmlEntityFixer.ts

/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable no-console,no-underscore-dangle */
import fs from "fs";
import fse from "fs-extra";
import glob from "glob";
import mkdirp from "mkdirp";
import path from "path";
import rimraf from "rimraf";
function processHtmlString(htmlPath: string) {
let data = fs.readFileSync(htmlPath, {
encoding: "utf8",
});
data = data.replace(/'/g, "'");
data = data.replace(/ /g, " ");
data = data.replace(/‑/g, "‑");
data = data.replace(/’/g, "’");
// add any other weird entity outputs here
return data;
}
function copyFolder(srcDir: string, destDir: string) {
fse.copySync(srcDir, destDir, {
overwrite: true,
});
}
function processFile(htmlPath: string, destPath: string, outputDir: string) {
const outputFileDir = path.dirname(path.join(outputDir, destPath));
if (!fs.existsSync(outputFileDir)) {
console.log(`Making dir: ${outputFileDir}`);
mkdirp.sync(outputFileDir);
}
const fileString = processHtmlString(htmlPath);
const absDestPath = path.join(outputDir, destPath);
fs.writeFileSync(absDestPath, fileString);
}
function main() {
const outputDir = `./build`; // desired output folder
const htmlDir = `./output`; // folder that react-email outputs to
rimraf.sync(outputDir); // Clean old files
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir);
}
const files = glob.sync(path.join(htmlDir, "/**/*.html"));
files.forEach((htmlPath) => {
const htmlPathObj = path.parse(htmlPath);
const innerPath = path
.dirname(htmlPath)
.replace(htmlDir, "")
.replace(path.relative(process.cwd(), htmlDir), ""); // for relative dirs
const destPath = path.join(innerPath, htmlPathObj.base);
processFile(htmlPath, destPath, outputDir);
});
copyFolder(`${htmlDir}/static`, `${outputDir}/static`);
}
if (require.main === module) {
main();
}
export default {
processHtmlString,
processFile,
main,
};
{
"name": "my-email-template",
"version": "0.1.0",
"scripts": {
"dev": "email dev",
"entityFix": "ts-node ./htmlEntityFixer.ts",
"build": "email export --pretty true --outDir output && ts-node ./htmlEntityFixer.ts"
},
"dependencies": {
"@react-email/body": "0.0.1",
"@react-email/button": "0.0.6",
"@react-email/container": "0.0.7",
"@react-email/head": "0.0.4",
"@react-email/html": "0.0.4",
"@react-email/img": "0.0.4",
"@react-email/link": "0.0.4",
"@react-email/section": "0.0.8",
"@react-email/text": "0.0.4",
"@types/fs-extra": "^11.0.1",
"@types/glob": "^8.0.1",
"fs-extra": "^11.1.0",
"glob": "^8.0.3",
"mkdirp": "^2.1.3",
"react-email": "1.7.13",
"rimraf": "^4.1.2",
"yargs": "^17.6.2"
}
}
@heysujal
Copy link

heysujal commented Mar 1, 2023

Where do I have to put this file ?

@haxxxton
Copy link
Author

haxxxton commented Mar 1, 2023

Where do I have to put this file ?

@heysujal this is an example of how i use this in a project that uses react-email. This should give you an idea of the dependencies i am using to power the htmlEntityFixer.ts file

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment