Skip to content

Commit

Permalink
Merge pull request #2 from markwylde/implement-hashing
Browse files Browse the repository at this point in the history
Implement hashing
  • Loading branch information
markwylde authored Apr 11, 2024
2 parents 651d42d + b15e0db commit 3fc643e
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 19 deletions.
24 changes: 24 additions & 0 deletions lib/convertFilesToUseHashes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { stat, readdir, readFile, writeFile } from 'fs/promises';
import path from 'path';

export default async function convertFilesToUseHashes(baseDir, lookup) {
for (const file of await readdir(baseDir)) {
const filePath = path.resolve(baseDir, file);
const stats = await stat(filePath);
if (stats.isDirectory()) {
await convertFilesToUseHashes(filePath, lookup);
continue;
}

let content = await readFile(filePath, 'utf8');
Object.keys(lookup).forEach((filepath) => {
content = content.replaceAll(`"${filepath}"`, `"./${lookup[filepath]}"`);
content = content.replaceAll(`"./${filepath}"`, `"./${lookup[filepath]}"`);
content = content.replaceAll(`"/${filepath}"`, `"./${lookup[filepath]}"`);
content = content.replaceAll(`'${filepath}'`, `"./${lookup[filepath]}"`);
content = content.replaceAll(`'./${filepath}'`, `"./${lookup[filepath]}"`);
content = content.replaceAll(`'/${filepath}'`, `"./${lookup[filepath]}"`);
});
await writeFile(filePath, content);
}
}
35 changes: 35 additions & 0 deletions lib/hashFiles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import fs from 'fs';
import path from 'path';
import crypto from 'crypto';

export default async function hashFiles(directory, hashTable = {}, relativePath = '') {
const files = await fs.promises.readdir(directory, { withFileTypes: true });
const promises = files.map(file => new Promise(async (resolve) => {
const sourceFile = path.resolve(directory, file.name);
const stats = await fs.promises.stat(sourceFile);
if (stats.isDirectory()) {
await hashFiles(sourceFile, hashTable, path.join(relativePath, file.name));
resolve();
return;
}
if (sourceFile.endsWith('.html')) {
resolve();
return;
}

const hash = crypto.createHash('md5');
const stream = fs.createReadStream(sourceFile);
stream.on('data', data => hash.update(data));
stream.on('end', async () => {
const hashString = hash.digest('hex');
const fileName = path.basename(file.name, path.extname(file.name));
const fileExt = path.extname(file.name);
const targetFile = path.resolve(directory, `${fileName}-${hashString.slice(0, 8)}${fileExt}`);
await fs.promises.rename(sourceFile, targetFile);
hashTable[path.join(relativePath, file.name)] = path.join(relativePath, `${fileName}-${hashString.slice(0, 8)}${fileExt}`);
resolve();
});
}));
await Promise.all(promises);
return hashTable;
}
5 changes: 5 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import micromatch from 'micromatch';

import ejsLoader from './loaders/ejs.js';
import cssLoader from './loaders/css.js';
import hashFiles from './hashFiles.js';
import convertFilesToUseHashes from './convertFilesToUseHashes.js';

const loopRegex = /\[.* of .*\]/;
const variableRegex = /\[(.*?)\]/g;
Expand Down Expand Up @@ -117,6 +119,9 @@ async function statictron (options) {
}

await render(source, output, options);

const lookup = await hashFiles(output);
await convertFilesToUseHashes(output, lookup);
}

statictron.loaders = {
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "statictron",
"version": "3.0.5",
"version": "4.0.0",
"type": "module",
"description": "Build a static website using ejs.",
"bin": {
Expand Down
32 changes: 16 additions & 16 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ test('api - source and output', async t => {
'_partials/foot/index.html',
'_partials/head/index.html',
'_partials/header/index.html',
'index.css',
'index-bfb298cd.css',
'index.html',
'plane.svg'
'plane-4dc849bc.svg'
]
);

Expand All @@ -68,7 +68,7 @@ test('api - source and output', async t => {
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Example Site</title>
<link rel="stylesheet" href="index.css">
<link rel="stylesheet" href="./index-bfb298cd.css">
</head>
<body>
Expand All @@ -77,7 +77,7 @@ test('api - source and output', async t => {
</header>
<h1>Home Page</h1>
<p>This is a test</p>
<img src="plane.svg" />
<img src="./plane-4dc849bc.svg" />
</body>
</html>
Expand Down Expand Up @@ -148,13 +148,13 @@ test('api - css gets bundled', async t => {
'_partials/foot/index.html',
'_partials/head/index.html',
'_partials/header/index.html',
'index.css',
'index-bfb298cd.css',
'index.html',
'plane.svg'
'plane-4dc849bc.svg'
]
);

t.equal(await fs.readFile('./demo/dist/index.css', 'utf8'), `
t.equal(await fs.readFile('./demo/dist/index-bfb298cd.css', 'utf8'), `
header {
background-color: black;
color: white;
Expand Down Expand Up @@ -182,9 +182,9 @@ test('api - scope', async t => {
'_partials/foot/index.html',
'_partials/head/index.html',
'_partials/header/index.html',
'index.css',
'index-bfb298cd.css',
'index.html',
'plane.svg'
'plane-4dc849bc.svg'
]
);

Expand All @@ -197,7 +197,7 @@ test('api - scope', async t => {
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Example Site</title>
<link rel="stylesheet" href="index.css">
<link rel="stylesheet" href="./index-bfb298cd.css">
</head>
<body>
Expand All @@ -206,7 +206,7 @@ test('api - scope', async t => {
</header>
<h1>Test Title From Scope</h1>
<p>This is a test</p>
<img src="plane.svg" />
<img src="./plane-4dc849bc.svg" />
</body>
</html>
Expand All @@ -227,7 +227,7 @@ test('api - ignore as a string', async t => {
const files = await globby('**/*', { cwd: './demo/dist' });
t.deepEqual(
files.sort(),
['index.css', 'index.html', 'plane.svg']
['index-bfb298cd.css', 'index.html', 'plane-4dc849bc.svg']
);
});

Expand All @@ -245,7 +245,7 @@ test('api - ignore as an array', async t => {
const files = await globby('**/*', { cwd: './demo/dist' });
t.deepEqual(
files.sort(),
['index.css', 'index.html', 'plane.svg']
['index-bfb298cd.css', 'index.html', 'plane-4dc849bc.svg']
);
});

Expand All @@ -266,7 +266,7 @@ test('api - multiple ignore', async t => {
const files = await globby('**/*', { cwd: './demo/dist' });
t.deepEqual(
files.sort(),
['_partials/header/index.html', 'index.css', 'index.html', 'plane.svg']
['_partials/header/index.html', 'index-bfb298cd.css', 'index.html', 'plane-4dc849bc.svg']
);
});

Expand Down Expand Up @@ -297,9 +297,9 @@ test('api - file based loop', async t => {
files.sort(),
[
'first/index.html',
'index.css',
'index-bfb298cd.css',
'index.html',
'plane.svg',
'plane-4dc849bc.svg',
'second/index.html'
]
);
Expand Down

0 comments on commit 3fc643e

Please sign in to comment.