Skip to content

Instantly share code, notes, and snippets.

@mykeels
Created April 21, 2021 23:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mykeels/2cd54097d7555439fe75a2006aa4a626 to your computer and use it in GitHub Desktop.
Save mykeels/2cd54097d7555439fe75a2006aa4a626 to your computer and use it in GitHub Desktop.
A script to inline styles on *.hbs files in a directory
import { promises as fs } from 'fs';
import path from 'path';
import inlineCss from 'inline-css';
import env from '../common/config/env';
/**
* So there are multiple *.hbs files, in a directory, and one of them, contains a link reference to tailwind cdn like:
* <link rel="stylesheet" href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css">
* In this script, we inline all their styles by
* - reading each file's content
* - concatenating the contents, so we have a huge single file
* - passing the huge single file through the "inline-css" package.
* - splitting them again to save in the output directory.
*/
async function* walk(dir) {
const dirents = await fs.readdir(dir, { withFileTypes: true });
for (const dirent of dirents) {
const res = path.resolve(dir, dirent.name);
if (dirent.isDirectory()) {
yield* walk(res);
} else {
yield res;
}
}
}
(async () => {
const inputDir = path.join(
__dirname,
'../../src/common/services/notification/email/emailTemplates/templates'
);
const outputDir = path.join(
__dirname,
'../../dist/common/services/notification/email/emailTemplates/templates'
);
console.log(`Processing files in ${inputDir}`);
console.time('total');
const filePaths = [];
for await (const f of walk(inputDir)) {
if (f === inputDir) continue;
filePaths.push(f);
}
const BIG_SEP = '~~~~~sep~~~~~';
const SMALL_SEP = '-----sep-----';
const getFileHbs = async (filePath: string) => {
return fs.readFile(filePath, 'utf8').then((hbs) => ({ filePath, hbs }));
};
const contents = await Promise.all(filePaths.map(getFileHbs));
const hbs =
contents
.map(({ filePath, hbs }) => {
return `${filePath}
${SMALL_SEP}
${hbs}`;
})
.join(`\n${BIG_SEP}\n`);
const processedHbs = await inlineCss(hbs, {
url: env.app_url,
removeLinkTags: false,
removeStyleTags: false,
applyWidthAttributes: true,
applyTableAttributes: true
});
const toBeRemoved = [
/--tw-ring-color: rgba\(59, 130, 246, 0.5\);/g,
/--tw-ring-inset: var\(--tw-empty, \);/g,
/--tw-ring-offset-color: #fff;/g,
/--tw-ring-offset-shadow: 0 0 #0000;/g,
/--tw-ring-offset-width: 0px;/g,
/--tw-ring-shadow: 0 0 #0000;/g,
/--tw-shadow: 0 0 #0000;/g,
/--tw-bg-opacity: 1;/g,
/--tw-border-opacity: 1;/g,
/--tw-text-opacity: 1/g
];
const toBeReplaced = [
[/var\(--tw-bg-opacity\)/g, `1`],
[/var\(--tw-text-opacity\)/g, `1`],
[/var\(--tw-border-opacity\)/g, `1`],
[/style=" +/g, `style="`]
];
const removedProcessedHbs = toBeRemoved
.reduce((text: string, rm) => text.replace(rm, ''), processedHbs);
const replacedProcessedHbs = toBeReplaced.reduce(
(text: string, [item, replacement]) => text.replace(item, replacement as string),
removedProcessedHbs
);
const chunks = replacedProcessedHbs.split(BIG_SEP);
await Promise.all(
chunks.map((chunk) => {
const [filePath, hbs] = chunk.split(SMALL_SEP).map((c) => c.trim());
const fileName = filePath.replace(inputDir, '');
const outFilePath = path.join(outputDir, fileName);
return fs.writeFile(outFilePath, hbs, 'utf8');
console.log(`Written to ${outFilePath}`);
})
);
console.timeEnd('total');
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment