@zulaica/site-bundler 0.6.3 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/helpers/constants.mjs +20 -9
- package/lib/helpers/logger.mjs +21 -0
- package/lib/helpers/tests.mjs +103 -0
- package/lib/index.mjs +32 -24
- package/lib/index.test.mjs +89 -0
- package/lib/modules/copyAssets.mjs +22 -19
- package/lib/modules/copyAssets.test.mjs +86 -0
- package/lib/modules/preflight.mjs +19 -16
- package/lib/modules/preflight.test.mjs +37 -0
- package/lib/modules/processCSS.mjs +25 -12
- package/lib/modules/processCSS.test.mjs +60 -0
- package/lib/modules/processHTML.mjs +27 -11
- package/lib/modules/processHTML.test.mjs +50 -0
- package/lib/modules/processJS.mjs +30 -13
- package/lib/modules/processJS.test.mjs +67 -0
- package/package.json +23 -22
- package/lib/helpers/index.mjs +0 -4
- package/lib/helpers/loggers.mjs +0 -16
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
/* node:coverage disable */
|
|
1
2
|
export const EMOJI = Object.freeze({
|
|
2
|
-
artistPalette: '\
|
|
3
|
-
barChart: '\
|
|
4
|
-
cardIndexDividers: '\
|
|
5
|
-
constructionWorker: '\
|
|
6
|
-
fileCabinet: '\
|
|
7
|
-
fileFolder: '\
|
|
8
|
-
noEntry: '\
|
|
9
|
-
package: '\
|
|
10
|
-
wastebasket: '\
|
|
3
|
+
artistPalette: '\u{1f3a8}',
|
|
4
|
+
barChart: '\u{1f4ca}',
|
|
5
|
+
cardIndexDividers: '\u{1f5c2}',
|
|
6
|
+
constructionWorker: '\u{1f477}',
|
|
7
|
+
fileCabinet: '\u{1f5c4} ',
|
|
8
|
+
fileFolder: '\u{1f4c1}',
|
|
9
|
+
noEntry: '\u{26D4}',
|
|
10
|
+
package: '\u{1f4e6}',
|
|
11
|
+
wastebasket: '\u{1f5d1} '
|
|
11
12
|
});
|
|
12
13
|
|
|
13
14
|
export const EXCLUSIONS = Object.freeze([
|
|
@@ -34,6 +35,12 @@ export const OPTIONS = Object.freeze({
|
|
|
34
35
|
configFile: false,
|
|
35
36
|
minified: true
|
|
36
37
|
},
|
|
38
|
+
rollup: {
|
|
39
|
+
onwarn(warning, warn) {
|
|
40
|
+
if (warning.code === 'EMPTY_BUNDLE') return;
|
|
41
|
+
warn(warning);
|
|
42
|
+
}
|
|
43
|
+
},
|
|
37
44
|
postcss: {
|
|
38
45
|
cssnano: {
|
|
39
46
|
preset: [
|
|
@@ -72,6 +79,9 @@ export const OPTIONS = Object.freeze({
|
|
|
72
79
|
},
|
|
73
80
|
posthtml: {
|
|
74
81
|
htmlnano: {
|
|
82
|
+
collapseBooleanAttributes: {
|
|
83
|
+
amphtml: false
|
|
84
|
+
},
|
|
75
85
|
collapseWhitespace: 'aggressive',
|
|
76
86
|
minifyJs: false,
|
|
77
87
|
removeComments: 'all',
|
|
@@ -79,3 +89,4 @@ export const OPTIONS = Object.freeze({
|
|
|
79
89
|
}
|
|
80
90
|
}
|
|
81
91
|
});
|
|
92
|
+
/* node:coverage enable */
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { exit, stderr, stdout } from 'node:process';
|
|
2
|
+
import { clearLine, cursorTo } from 'node:readline';
|
|
3
|
+
import { EMOJI } from './constants.mjs';
|
|
4
|
+
|
|
5
|
+
export default class Logger {
|
|
6
|
+
static error = (error) => {
|
|
7
|
+
stderr.write(`${EMOJI.noEntry} An error has occurred\n`);
|
|
8
|
+
stderr.write(`${error.toString()}\n\n`);
|
|
9
|
+
stderr.write('', () => exit(1));
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
static message = (message, update = false) => {
|
|
13
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
14
|
+
if (update) {
|
|
15
|
+
cursorTo(stdout, 0);
|
|
16
|
+
clearLine(stdout, 0);
|
|
17
|
+
}
|
|
18
|
+
stdout.write(message);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { mkdir, rm } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { afterEach, beforeEach } from 'node:test';
|
|
5
|
+
|
|
6
|
+
const baseDir = join(tmpdir(), `site-bundler-test-${Date.now()}`);
|
|
7
|
+
|
|
8
|
+
export const inputDir = join(baseDir, 'input');
|
|
9
|
+
export const outputDir = join(baseDir, 'output');
|
|
10
|
+
|
|
11
|
+
export const inputCSS = `
|
|
12
|
+
/**
|
|
13
|
+
* This is a comment
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
body {
|
|
17
|
+
margin: 0;
|
|
18
|
+
padding: 20px;
|
|
19
|
+
font-family: Arial, sans-serif;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
h1 {
|
|
23
|
+
color: #333;
|
|
24
|
+
}
|
|
25
|
+
`;
|
|
26
|
+
|
|
27
|
+
export const processedCSS =
|
|
28
|
+
'body{font-family:Arial,sans-serif;margin:0;padding:20px}h1{color:#333}';
|
|
29
|
+
|
|
30
|
+
export const inputHTML = `
|
|
31
|
+
<!DOCTYPE html>
|
|
32
|
+
<html lang="en">
|
|
33
|
+
<head>
|
|
34
|
+
<!-- This is a comment -->
|
|
35
|
+
<meta charset="utf-8" />
|
|
36
|
+
<link rel="stylesheet" href="style.hash.css" />
|
|
37
|
+
<script src="script.hash.js"></script>
|
|
38
|
+
</head>
|
|
39
|
+
<body>
|
|
40
|
+
<header>
|
|
41
|
+
<h1> Test Site </h1>
|
|
42
|
+
<nav>
|
|
43
|
+
<ul>
|
|
44
|
+
<li><a href="#home">Home</a></li>
|
|
45
|
+
<li><a href="#about">About</a></li>
|
|
46
|
+
</ul>
|
|
47
|
+
</nav>
|
|
48
|
+
</header>
|
|
49
|
+
<main>
|
|
50
|
+
<section>
|
|
51
|
+
<article>
|
|
52
|
+
<h2>Article Title</h2>
|
|
53
|
+
<p>Article content goes here.</p>
|
|
54
|
+
<p aria-hidden="true">This is hidden.</p>
|
|
55
|
+
</article>
|
|
56
|
+
</section>
|
|
57
|
+
<aside>
|
|
58
|
+
<input type="text" disabled="disabled" placeholder="Enter text" />
|
|
59
|
+
</aside>
|
|
60
|
+
</main>
|
|
61
|
+
<footer>
|
|
62
|
+
<p>© Year</p>
|
|
63
|
+
</footer>
|
|
64
|
+
</body>
|
|
65
|
+
</html>
|
|
66
|
+
`;
|
|
67
|
+
|
|
68
|
+
export const processedHTML =
|
|
69
|
+
'<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><link rel="stylesheet" href="style.hash.css"><script src="script.hash.js"></script></head><body><header><h1>Test Site</h1><nav><ul><li><a href="#home">Home</a></li><li><a href="#about">About</a></li></ul></nav></header><main><section><article><h2>Article Title</h2><p>Article content goes here.</p><p aria-hidden="true">This is hidden.</p></article></section><aside><input type="text" disabled placeholder="Enter text"></aside></main><footer><p>© Year</p></footer></body></html>';
|
|
70
|
+
|
|
71
|
+
export const inputJS = `
|
|
72
|
+
// This is a comment
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* This is a comment
|
|
76
|
+
*/
|
|
77
|
+
|
|
78
|
+
const sum = (a, b) => {
|
|
79
|
+
return a + b;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
console.log('Site loaded');
|
|
83
|
+
|
|
84
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
85
|
+
console.log('DOM loaded');
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
export default sum;
|
|
89
|
+
`;
|
|
90
|
+
|
|
91
|
+
export const processedJS =
|
|
92
|
+
'const sum=(a,b)=>{return a+b};console.log("Site loaded");document.addEventListener("DOMContentLoaded",()=>{console.log("DOM loaded")});export{sum as default};';
|
|
93
|
+
|
|
94
|
+
export const setUpTestHooks = () => {
|
|
95
|
+
beforeEach(async () => {
|
|
96
|
+
await mkdir(inputDir, { recursive: true });
|
|
97
|
+
await mkdir(outputDir, { recursive: true });
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
afterEach(async () => {
|
|
101
|
+
await rm(baseDir, { recursive: true, force: true });
|
|
102
|
+
});
|
|
103
|
+
};
|
package/lib/index.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { program } from 'commander';
|
|
4
|
-
import { readFile } from 'fs/promises';
|
|
5
|
-
import { EMOJI
|
|
4
|
+
import { access, readFile } from 'node:fs/promises';
|
|
5
|
+
import { EMOJI } from './helpers/constants.mjs';
|
|
6
|
+
import Logger from './helpers/logger.mjs';
|
|
6
7
|
import {
|
|
7
8
|
copyAssets,
|
|
8
9
|
preflight,
|
|
@@ -11,28 +12,35 @@ import {
|
|
|
11
12
|
processJS
|
|
12
13
|
} from './modules/index.mjs';
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const opts = program.opts();
|
|
15
|
+
const { version } = JSON.parse(
|
|
16
|
+
await readFile(new URL('../package.json', import.meta.url))
|
|
17
|
+
);
|
|
18
|
+
program
|
|
19
|
+
.version(version)
|
|
20
|
+
.requiredOption('-i, --input-dir <input>', 'The input directory')
|
|
21
|
+
.requiredOption('-o, --output-dir <output>', 'The output directory')
|
|
22
|
+
.parse();
|
|
23
|
+
const opts = program.opts();
|
|
24
24
|
|
|
25
|
+
async function validateInput() {
|
|
25
26
|
try {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
await processCSS(opts);
|
|
30
|
-
await processJS(opts);
|
|
31
|
-
await processHTML(opts);
|
|
32
|
-
logMessage(`${EMOJI.package} Finished!`);
|
|
33
|
-
} catch (error) {
|
|
34
|
-
logError(error);
|
|
35
|
-
} finally {
|
|
36
|
-
logMessage('\n\n');
|
|
27
|
+
await access(opts.inputDir);
|
|
28
|
+
} catch {
|
|
29
|
+
Logger.error(`Input directory does not exist: ${opts.inputDir}`);
|
|
37
30
|
}
|
|
38
|
-
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
Logger.message(`${EMOJI.constructionWorker} Site Bundler v${version}\n\n`);
|
|
35
|
+
|
|
36
|
+
await validateInput();
|
|
37
|
+
await preflight(opts.outputDir);
|
|
38
|
+
await copyAssets(opts);
|
|
39
|
+
await processCSS(opts);
|
|
40
|
+
await processJS(opts);
|
|
41
|
+
await processHTML(opts);
|
|
42
|
+
|
|
43
|
+
Logger.message(`${EMOJI.package} Finished!\n\n`);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
Logger.error(error);
|
|
46
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { execFile } from 'node:child_process';
|
|
3
|
+
import { readdir, readFile, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { describe, it } from 'node:test';
|
|
6
|
+
import { promisify } from 'node:util';
|
|
7
|
+
import { EMOJI } from './helpers/constants.mjs';
|
|
8
|
+
import {
|
|
9
|
+
inputCSS,
|
|
10
|
+
inputDir,
|
|
11
|
+
inputHTML,
|
|
12
|
+
inputJS,
|
|
13
|
+
outputDir,
|
|
14
|
+
setUpTestHooks
|
|
15
|
+
} from './helpers/tests.mjs';
|
|
16
|
+
|
|
17
|
+
const execFileAsync = promisify(execFile);
|
|
18
|
+
const { version } = JSON.parse(
|
|
19
|
+
await readFile(new URL('../package.json', import.meta.url), 'utf8')
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
describe(`${EMOJI.package} CLI Integration`, () => {
|
|
23
|
+
setUpTestHooks();
|
|
24
|
+
|
|
25
|
+
it('should display version', async () => {
|
|
26
|
+
const { stdout } = await execFileAsync('node', [
|
|
27
|
+
join(process.cwd(), 'lib', 'index.mjs'),
|
|
28
|
+
'--version'
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
assert.ok(stdout.includes(version));
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should process complete site', async () => {
|
|
35
|
+
await writeFile(join(inputDir, 'index.html'), inputHTML);
|
|
36
|
+
await writeFile(join(inputDir, 'style.hash.css'), inputCSS);
|
|
37
|
+
await writeFile(join(inputDir, 'script.hash.js'), inputJS);
|
|
38
|
+
await writeFile(join(inputDir, 'favicon.ico'), '');
|
|
39
|
+
|
|
40
|
+
await assert.doesNotReject(() =>
|
|
41
|
+
execFileAsync('node', [
|
|
42
|
+
join(process.cwd(), 'lib', 'index.mjs'),
|
|
43
|
+
'-i',
|
|
44
|
+
inputDir,
|
|
45
|
+
'-o',
|
|
46
|
+
outputDir
|
|
47
|
+
])
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const outputFiles = await readdir(outputDir);
|
|
51
|
+
|
|
52
|
+
assert.deepEqual(outputFiles.sort(), [
|
|
53
|
+
'favicon.ico',
|
|
54
|
+
'index.html',
|
|
55
|
+
'script.hash.js',
|
|
56
|
+
'style.hash.css'
|
|
57
|
+
]);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should handle non-existent input directory', async () => {
|
|
61
|
+
const nonExistentDir = join(inputDir, 'non-existent');
|
|
62
|
+
|
|
63
|
+
await assert.rejects(
|
|
64
|
+
() =>
|
|
65
|
+
execFileAsync('node', [
|
|
66
|
+
join(process.cwd(), 'lib', 'index.mjs'),
|
|
67
|
+
'-i',
|
|
68
|
+
nonExistentDir,
|
|
69
|
+
'-o',
|
|
70
|
+
outputDir
|
|
71
|
+
]),
|
|
72
|
+
/Input directory does not exist/
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should handle empty input directory', async () => {
|
|
77
|
+
await assert.rejects(
|
|
78
|
+
() =>
|
|
79
|
+
execFileAsync('node', [
|
|
80
|
+
join(process.cwd(), 'lib', 'index.mjs'),
|
|
81
|
+
'-i',
|
|
82
|
+
inputDir,
|
|
83
|
+
'-o',
|
|
84
|
+
outputDir
|
|
85
|
+
]),
|
|
86
|
+
/An error has occurred/
|
|
87
|
+
);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
@@ -1,29 +1,32 @@
|
|
|
1
|
-
import { cp, readdir } from 'fs/promises';
|
|
2
|
-
import {
|
|
1
|
+
import { cp, readdir } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { EMOJI, EXCLUSIONS } from '../helpers/constants.mjs';
|
|
4
|
+
import Logger from '../helpers/logger.mjs';
|
|
3
5
|
|
|
4
6
|
const copyAssets = async ({ inputDir, outputDir }) => {
|
|
5
7
|
const assets = await readdir(inputDir);
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
const filteredAssets = assets.filter((asset) => !EXCLUSIONS.includes(asset));
|
|
9
|
+
|
|
10
|
+
if (!filteredAssets.length) {
|
|
11
|
+
return;
|
|
8
12
|
}
|
|
9
13
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
assets.length
|
|
18
|
-
})`,
|
|
19
|
-
true
|
|
20
|
-
);
|
|
21
|
-
await cp(`${inputDir}/${asset}`, `${outputDir}/${asset}`, {
|
|
14
|
+
Logger.message(
|
|
15
|
+
`${EMOJI.cardIndexDividers} Copying ${filteredAssets.length} assets…`
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
await Promise.all(
|
|
19
|
+
filteredAssets.map(async (asset) => {
|
|
20
|
+
await cp(join(inputDir, asset), join(outputDir, asset), {
|
|
22
21
|
recursive: true
|
|
23
22
|
});
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
})
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
Logger.message(
|
|
27
|
+
`${EMOJI.cardIndexDividers} Copied ${filteredAssets.length} assets\n`,
|
|
28
|
+
true
|
|
29
|
+
);
|
|
27
30
|
};
|
|
28
31
|
|
|
29
32
|
export default copyAssets;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { mkdir, readdir, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { describe, it } from 'node:test';
|
|
5
|
+
import { EMOJI } from '../helpers/constants.mjs';
|
|
6
|
+
import {
|
|
7
|
+
inputCSS,
|
|
8
|
+
inputDir,
|
|
9
|
+
inputHTML,
|
|
10
|
+
inputJS,
|
|
11
|
+
outputDir,
|
|
12
|
+
setUpTestHooks
|
|
13
|
+
} from '../helpers/tests.mjs';
|
|
14
|
+
import copyAssets from './copyAssets.mjs';
|
|
15
|
+
|
|
16
|
+
describe(`${EMOJI.cardIndexDividers} copyAssets()`, () => {
|
|
17
|
+
setUpTestHooks();
|
|
18
|
+
|
|
19
|
+
it('should copy all non-excluded assets', async () => {
|
|
20
|
+
await writeFile(join(inputDir, 'image.png'), '');
|
|
21
|
+
await writeFile(join(inputDir, 'document.pdf'), '');
|
|
22
|
+
await writeFile(join(inputDir, 'script.js'), inputJS);
|
|
23
|
+
|
|
24
|
+
await assert.doesNotReject(() => copyAssets({ inputDir, outputDir }));
|
|
25
|
+
|
|
26
|
+
const copiedFiles = await readdir(outputDir);
|
|
27
|
+
|
|
28
|
+
assert.deepEqual(copiedFiles.sort(), [
|
|
29
|
+
'document.pdf',
|
|
30
|
+
'image.png',
|
|
31
|
+
'script.js'
|
|
32
|
+
]);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should exclude files listed in EXCLUSIONS', async () => {
|
|
36
|
+
await mkdir(join(inputDir, 'scripts'), { recursive: true });
|
|
37
|
+
await mkdir(join(inputDir, 'styles'), { recursive: true });
|
|
38
|
+
await writeFile(join(inputDir, 'image.png'), '');
|
|
39
|
+
await writeFile(join(inputDir, 'index.html'), inputHTML);
|
|
40
|
+
await writeFile(join(inputDir, 'script.hash.js'), inputJS);
|
|
41
|
+
await writeFile(join(inputDir, 'style.hash.css'), inputCSS);
|
|
42
|
+
await writeFile(join(inputDir, 'scripts', 'app.js'), inputJS);
|
|
43
|
+
await writeFile(join(inputDir, 'styles', 'main.css'), inputCSS);
|
|
44
|
+
|
|
45
|
+
await assert.doesNotReject(() => copyAssets({ inputDir, outputDir }));
|
|
46
|
+
|
|
47
|
+
const copiedFiles = await readdir(outputDir);
|
|
48
|
+
|
|
49
|
+
assert.deepStrictEqual(copiedFiles, ['image.png']);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should handle empty input directory', async () => {
|
|
53
|
+
await assert.doesNotReject(() => copyAssets({ inputDir, outputDir }));
|
|
54
|
+
|
|
55
|
+
const copiedFiles = await readdir(outputDir);
|
|
56
|
+
|
|
57
|
+
assert.deepStrictEqual(copiedFiles, []);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should copy directories recursively', async () => {
|
|
61
|
+
await mkdir(join(inputDir, 'assets'), { recursive: true });
|
|
62
|
+
await mkdir(join(inputDir, 'assets', 'images'), { recursive: true });
|
|
63
|
+
await writeFile(join(inputDir, 'assets', 'file.txt'), '');
|
|
64
|
+
await writeFile(join(inputDir, 'assets', 'images', 'logo.png'), '');
|
|
65
|
+
|
|
66
|
+
await assert.doesNotReject(() => copyAssets({ inputDir, outputDir }));
|
|
67
|
+
|
|
68
|
+
const copiedFiles = await readdir(outputDir, { withFileTypes: true });
|
|
69
|
+
const assetsDir = copiedFiles.find((f) => f.name === 'assets');
|
|
70
|
+
const subFiles = await readdir(join(outputDir, 'assets'));
|
|
71
|
+
|
|
72
|
+
assert.ok(assetsDir.isDirectory());
|
|
73
|
+
assert.deepStrictEqual(subFiles.sort(), ['file.txt', 'images']);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should handle only excluded files', async () => {
|
|
77
|
+
await writeFile(join(inputDir, 'index.html'), inputHTML);
|
|
78
|
+
await writeFile(join(inputDir, 'script.hash.js'), inputCSS);
|
|
79
|
+
|
|
80
|
+
await assert.doesNotReject(() => copyAssets({ inputDir, outputDir }));
|
|
81
|
+
|
|
82
|
+
const copiedFiles = await readdir(outputDir);
|
|
83
|
+
|
|
84
|
+
assert.deepStrictEqual(copiedFiles, []);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
@@ -1,31 +1,34 @@
|
|
|
1
|
-
import { mkdir, readdir, rm } from 'fs/promises';
|
|
2
|
-
import { EMOJI
|
|
1
|
+
import { mkdir, readdir, rm } from 'node:fs/promises';
|
|
2
|
+
import { EMOJI } from '../helpers/constants.mjs';
|
|
3
|
+
import Logger from '../helpers/logger.mjs';
|
|
3
4
|
|
|
4
5
|
const preflight = async (outputDir) => {
|
|
5
6
|
try {
|
|
6
7
|
const files = await readdir(outputDir);
|
|
7
8
|
|
|
8
9
|
if (files.length) {
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
Logger.message(`${EMOJI.wastebasket} Removing old ${outputDir} files…`);
|
|
11
|
+
|
|
12
|
+
await rm(outputDir, { recursive: true, force: true });
|
|
13
|
+
await mkdir(outputDir);
|
|
14
|
+
|
|
15
|
+
Logger.message(
|
|
16
|
+
`${EMOJI.wastebasket} Removed old ${outputDir} files\n`,
|
|
17
|
+
true
|
|
11
18
|
);
|
|
12
|
-
for (const [index, file] of files.entries()) {
|
|
13
|
-
logMessage(
|
|
14
|
-
`${EMOJI.wastebasket} Removing old ${outputDir} files (${index + 1}/${
|
|
15
|
-
files.length
|
|
16
|
-
})`,
|
|
17
|
-
true
|
|
18
|
-
);
|
|
19
|
-
await rm(`${outputDir}/${file}`, { recursive: true, force: true });
|
|
20
|
-
}
|
|
21
|
-
logMessage('\n');
|
|
22
19
|
}
|
|
23
20
|
} catch (error) {
|
|
24
21
|
if (error.code === 'ENOENT') {
|
|
25
|
-
|
|
22
|
+
Logger.message(`${EMOJI.fileFolder} Creating ${outputDir} directory…`);
|
|
23
|
+
|
|
26
24
|
await mkdir(outputDir);
|
|
25
|
+
|
|
26
|
+
Logger.message(
|
|
27
|
+
`${EMOJI.fileFolder} Created ${outputDir} directory\n`,
|
|
28
|
+
true
|
|
29
|
+
);
|
|
27
30
|
} else {
|
|
28
|
-
|
|
31
|
+
Logger.error(`${error} \n`);
|
|
29
32
|
}
|
|
30
33
|
}
|
|
31
34
|
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { mkdir, readdir, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { describe, it } from 'node:test';
|
|
5
|
+
import { EMOJI } from '../helpers/constants.mjs';
|
|
6
|
+
import { outputDir, setUpTestHooks } from '../helpers/tests.mjs';
|
|
7
|
+
import preflight from './preflight.mjs';
|
|
8
|
+
|
|
9
|
+
describe(`${EMOJI.fileFolder} preflight()`, () => {
|
|
10
|
+
setUpTestHooks();
|
|
11
|
+
|
|
12
|
+
it('should create output directory if it does not exist', async () => {
|
|
13
|
+
const nonExistentDir = join(outputDir, 'non-existent');
|
|
14
|
+
await assert.doesNotReject(() => preflight(nonExistentDir));
|
|
15
|
+
|
|
16
|
+
const files = await readdir(nonExistentDir);
|
|
17
|
+
|
|
18
|
+
assert.ok(files !== undefined);
|
|
19
|
+
assert.deepEqual(files, []);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should remove all files and recreate output directory', async () => {
|
|
23
|
+
await mkdir(join(outputDir, 'subdir'), { recursive: true });
|
|
24
|
+
await writeFile(join(outputDir, 'file1.txt'), '');
|
|
25
|
+
await writeFile(join(outputDir, 'file2.txt'), '');
|
|
26
|
+
await writeFile(join(outputDir, 'subdir', 'file3.txt'), '');
|
|
27
|
+
|
|
28
|
+
const initialFiles = await readdir(outputDir, { withFileTypes: true });
|
|
29
|
+
|
|
30
|
+
assert.ok(initialFiles.length > 0);
|
|
31
|
+
await assert.doesNotReject(() => preflight(outputDir));
|
|
32
|
+
|
|
33
|
+
const finalFiles = await readdir(outputDir);
|
|
34
|
+
|
|
35
|
+
assert.deepEqual(finalFiles, []);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -1,30 +1,43 @@
|
|
|
1
1
|
import cssnanoPlugin from 'cssnano';
|
|
2
|
-
import { readFile, writeFile } from 'fs/promises';
|
|
2
|
+
import { readdir, readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
3
4
|
import postcss from 'postcss';
|
|
4
5
|
import atImport from 'postcss-import';
|
|
5
6
|
import postcssPresetEnv from 'postcss-preset-env';
|
|
6
7
|
import url from 'postcss-url';
|
|
7
|
-
import { EMOJI, OPTIONS
|
|
8
|
+
import { EMOJI, OPTIONS } from '../helpers/constants.mjs';
|
|
9
|
+
import Logger from '../helpers/logger.mjs';
|
|
10
|
+
|
|
11
|
+
const { cssnano, url: cssUrl } = OPTIONS.postcss;
|
|
12
|
+
|
|
13
|
+
const postcssProcessor = postcss()
|
|
14
|
+
.use(atImport())
|
|
15
|
+
.use(postcssPresetEnv())
|
|
16
|
+
.use(url(cssUrl))
|
|
17
|
+
.use(cssnanoPlugin(cssnano));
|
|
8
18
|
|
|
9
19
|
const processCSS = async ({ inputDir, outputDir }) => {
|
|
10
|
-
|
|
20
|
+
const assets = await readdir(inputDir);
|
|
11
21
|
const file = 'style.hash.css';
|
|
12
|
-
const input = `${inputDir}/${file}`;
|
|
13
|
-
const output = `${outputDir}/${file}`;
|
|
14
22
|
|
|
23
|
+
if (!assets.includes(file)) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Logger.message(`${EMOJI.artistPalette} Processing styles…`);
|
|
28
|
+
|
|
29
|
+
const input = join(inputDir, file);
|
|
30
|
+
const output = join(outputDir, file);
|
|
15
31
|
const data = await readFile(input, { encoding: 'utf8' });
|
|
16
32
|
const code = await _processData(input, data);
|
|
33
|
+
|
|
17
34
|
await writeFile(output, code);
|
|
18
|
-
|
|
35
|
+
|
|
36
|
+
Logger.message(`${EMOJI.artistPalette} Processed styles\n`, true);
|
|
19
37
|
};
|
|
20
38
|
|
|
21
39
|
async function _processData(input, data) {
|
|
22
|
-
const { css } = await
|
|
23
|
-
.use(atImport())
|
|
24
|
-
.use(postcssPresetEnv())
|
|
25
|
-
.use(url(OPTIONS.postcss.url))
|
|
26
|
-
.use(cssnanoPlugin(OPTIONS.postcss.cssnano))
|
|
27
|
-
.process(data, { from: input });
|
|
40
|
+
const { css } = await postcssProcessor.process(data, { from: input });
|
|
28
41
|
|
|
29
42
|
return css;
|
|
30
43
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { describe, it } from 'node:test';
|
|
5
|
+
import { EMOJI } from '../helpers/constants.mjs';
|
|
6
|
+
import {
|
|
7
|
+
inputCSS,
|
|
8
|
+
inputDir,
|
|
9
|
+
outputDir,
|
|
10
|
+
processedCSS,
|
|
11
|
+
setUpTestHooks
|
|
12
|
+
} from '../helpers/tests.mjs';
|
|
13
|
+
import processCSS from './processCSS.mjs';
|
|
14
|
+
|
|
15
|
+
describe(`${EMOJI.artistPalette} processCSS()`, () => {
|
|
16
|
+
setUpTestHooks();
|
|
17
|
+
|
|
18
|
+
it('should process CSS file and write output', async (sub) => {
|
|
19
|
+
await writeFile(join(inputDir, 'style.hash.css'), inputCSS);
|
|
20
|
+
|
|
21
|
+
await assert.doesNotReject(() => processCSS({ inputDir, outputDir }));
|
|
22
|
+
|
|
23
|
+
const output = await readFile(join(outputDir, 'style.hash.css'), 'utf8');
|
|
24
|
+
|
|
25
|
+
sub.test('minimized as a single line', () => {
|
|
26
|
+
assert.equal(output, processedCSS);
|
|
27
|
+
});
|
|
28
|
+
sub.test('with whitespace trimmed', () => {
|
|
29
|
+
assert.ok(output.trim().length < inputCSS.trim().length);
|
|
30
|
+
});
|
|
31
|
+
sub.test('with comments removed', () => {
|
|
32
|
+
assert.doesNotMatch(output, /\/\*\*/);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should handle CSS imports', async () => {
|
|
37
|
+
await writeFile(join(inputDir, 'style.hash.css'), '@import "base.css";');
|
|
38
|
+
await writeFile(join(inputDir, 'base.css'), inputCSS);
|
|
39
|
+
|
|
40
|
+
await assert.doesNotReject(() => processCSS({ inputDir, outputDir }));
|
|
41
|
+
|
|
42
|
+
const output = await readFile(join(outputDir, 'style.hash.css'), 'utf8');
|
|
43
|
+
|
|
44
|
+
assert.ok(output.includes(processedCSS));
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should handle empty CSS file', async () => {
|
|
48
|
+
await writeFile(join(inputDir, 'style.hash.css'), '');
|
|
49
|
+
|
|
50
|
+
await assert.doesNotReject(() => processCSS({ inputDir, outputDir }));
|
|
51
|
+
|
|
52
|
+
const output = await readFile(join(outputDir, 'style.hash.css'), 'utf8');
|
|
53
|
+
|
|
54
|
+
assert.equal(output, '');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should skip processing if CSS file does not exist', async () => {
|
|
58
|
+
await assert.doesNotReject(() => processCSS({ inputDir, outputDir }));
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -1,26 +1,42 @@
|
|
|
1
|
-
import { readFile, writeFile } from 'fs/promises';
|
|
2
1
|
import htmlnano from 'htmlnano';
|
|
2
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
3
4
|
import posthtml from 'posthtml';
|
|
4
5
|
import { hash } from 'posthtml-hash';
|
|
5
|
-
import { EMOJI, OPTIONS
|
|
6
|
+
import { EMOJI, OPTIONS } from '../helpers/constants.mjs';
|
|
7
|
+
import Logger from '../helpers/logger.mjs';
|
|
8
|
+
|
|
9
|
+
const { htmlnano: htmlnanoOptions } = OPTIONS.posthtml;
|
|
6
10
|
|
|
7
11
|
const processHTML = async ({ inputDir, outputDir }) => {
|
|
8
|
-
|
|
12
|
+
Logger.message(`${EMOJI.fileCabinet} Processing HTML…`);
|
|
9
13
|
const file = 'index.html';
|
|
10
|
-
const input =
|
|
11
|
-
const output =
|
|
14
|
+
const input = join(inputDir, file);
|
|
15
|
+
const output = join(outputDir, file);
|
|
12
16
|
|
|
13
17
|
const data = await readFile(input, { encoding: 'utf8' });
|
|
14
18
|
const code = await _processData(outputDir, data);
|
|
19
|
+
|
|
15
20
|
await writeFile(output, code);
|
|
16
|
-
|
|
21
|
+
|
|
22
|
+
Logger.message(`${EMOJI.fileCabinet} Processed HTML\n`, true);
|
|
17
23
|
};
|
|
18
24
|
|
|
19
|
-
async function _processData(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
async function _processData(path, data) {
|
|
26
|
+
let posthtmlInstance = posthtml().use(
|
|
27
|
+
htmlnano(htmlnanoOptions, htmlnano.presets.safe)
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
/* node:coverage disable */
|
|
31
|
+
// Skip hash replacement during tests
|
|
32
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
33
|
+
posthtmlInstance = posthtmlInstance.use(
|
|
34
|
+
hash({ path, pattern: new RegExp(/hash/) })
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
/* node:coverage enable */
|
|
38
|
+
|
|
39
|
+
const { html } = await posthtmlInstance.process(data);
|
|
24
40
|
|
|
25
41
|
return html;
|
|
26
42
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { describe, it } from 'node:test';
|
|
5
|
+
import { EMOJI } from '../helpers/constants.mjs';
|
|
6
|
+
import {
|
|
7
|
+
inputDir,
|
|
8
|
+
inputHTML,
|
|
9
|
+
outputDir,
|
|
10
|
+
processedHTML,
|
|
11
|
+
setUpTestHooks
|
|
12
|
+
} from '../helpers/tests.mjs';
|
|
13
|
+
import processHTML from './processHTML.mjs';
|
|
14
|
+
|
|
15
|
+
describe(`${EMOJI.fileCabinet} processHTML()`, () => {
|
|
16
|
+
setUpTestHooks();
|
|
17
|
+
|
|
18
|
+
it('should process HTML file and write output', async (sub) => {
|
|
19
|
+
await writeFile(join(inputDir, 'index.html'), inputHTML);
|
|
20
|
+
|
|
21
|
+
await assert.doesNotReject(() => processHTML({ inputDir, outputDir }));
|
|
22
|
+
|
|
23
|
+
const output = await readFile(join(outputDir, 'index.html'), 'utf8');
|
|
24
|
+
|
|
25
|
+
sub.test('minimized as a single line', () => {
|
|
26
|
+
assert.equal(output, processedHTML);
|
|
27
|
+
});
|
|
28
|
+
sub.test('with whitespace trimmed', () => {
|
|
29
|
+
assert.ok(output.trim().length < inputHTML.trim().length);
|
|
30
|
+
assert.ok(output.includes('Test Site'));
|
|
31
|
+
assert.ok(output.includes('Article Title'));
|
|
32
|
+
});
|
|
33
|
+
sub.test('with comments removed', () => {
|
|
34
|
+
assert.doesNotMatch(output, /<!--/);
|
|
35
|
+
});
|
|
36
|
+
sub.test('with boolean attributes handled correctly', () => {
|
|
37
|
+
assert.ok(output.includes('disabled'));
|
|
38
|
+
assert.doesNotMatch(output, /disabled="disabled"/);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should handle empty HTML file', async () => {
|
|
43
|
+
await writeFile(join(inputDir, 'index.html'), '');
|
|
44
|
+
await processHTML({ inputDir, outputDir });
|
|
45
|
+
|
|
46
|
+
const output = await readFile(join(outputDir, 'index.html'), 'utf8');
|
|
47
|
+
|
|
48
|
+
assert.equal(output, '');
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -1,31 +1,48 @@
|
|
|
1
1
|
import { transformFromAstAsync } from '@babel/core';
|
|
2
2
|
import { parse } from '@babel/parser';
|
|
3
|
-
import {
|
|
3
|
+
import { readdir, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { join } from 'node:path';
|
|
4
5
|
import { rollup } from 'rollup';
|
|
5
|
-
import { EMOJI, OPTIONS
|
|
6
|
+
import { EMOJI, OPTIONS } from '../helpers/constants.mjs';
|
|
7
|
+
import Logger from '../helpers/logger.mjs';
|
|
8
|
+
|
|
9
|
+
const { babel: babelOptions, rollup: rollupOptions } = OPTIONS;
|
|
6
10
|
|
|
7
11
|
const processJS = async ({ inputDir, outputDir }) => {
|
|
8
|
-
|
|
12
|
+
const assets = await readdir(inputDir);
|
|
9
13
|
const file = 'script.hash.js';
|
|
10
|
-
const input = `${inputDir}/${file}`;
|
|
11
|
-
const output = `${outputDir}/${file}`;
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
if (!assets.includes(file)) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
Logger.message(`${EMOJI.barChart} Processing scripts…`);
|
|
20
|
+
|
|
21
|
+
const input = join(inputDir, file);
|
|
22
|
+
const output = join(outputDir, file);
|
|
23
|
+
const bundledCode = await _bundleJS(input);
|
|
24
|
+
const code = await _processData(bundledCode);
|
|
25
|
+
|
|
16
26
|
await writeFile(output, code);
|
|
17
|
-
|
|
27
|
+
|
|
28
|
+
Logger.message(`${EMOJI.barChart} Processed scripts\n`, true);
|
|
18
29
|
};
|
|
19
30
|
|
|
20
|
-
async function _bundleJS(input
|
|
21
|
-
const bundle = await rollup({
|
|
22
|
-
|
|
31
|
+
async function _bundleJS(input) {
|
|
32
|
+
const bundle = await rollup({
|
|
33
|
+
input,
|
|
34
|
+
...rollupOptions
|
|
35
|
+
});
|
|
36
|
+
const { output } = await bundle.generate({ format: 'es' });
|
|
37
|
+
|
|
23
38
|
await bundle.close();
|
|
39
|
+
|
|
40
|
+
return output[0].code;
|
|
24
41
|
}
|
|
25
42
|
|
|
26
43
|
async function _processData(data) {
|
|
27
44
|
const ast = parse(data, { sourceType: 'module' });
|
|
28
|
-
const { code } = await transformFromAstAsync(ast, data,
|
|
45
|
+
const { code } = await transformFromAstAsync(ast, data, babelOptions);
|
|
29
46
|
|
|
30
47
|
return code;
|
|
31
48
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { describe, it } from 'node:test';
|
|
5
|
+
import { EMOJI } from '../helpers/constants.mjs';
|
|
6
|
+
import {
|
|
7
|
+
inputDir,
|
|
8
|
+
inputJS,
|
|
9
|
+
outputDir,
|
|
10
|
+
processedJS,
|
|
11
|
+
setUpTestHooks
|
|
12
|
+
} from '../helpers/tests.mjs';
|
|
13
|
+
import processJS from './processJS.mjs';
|
|
14
|
+
|
|
15
|
+
describe(`${EMOJI.barChart} processJS()`, () => {
|
|
16
|
+
setUpTestHooks();
|
|
17
|
+
|
|
18
|
+
it('should process JavaScript file and write output', async (sub) => {
|
|
19
|
+
await writeFile(join(inputDir, 'script.hash.js'), inputJS);
|
|
20
|
+
|
|
21
|
+
await assert.doesNotReject(() => processJS({ inputDir, outputDir }));
|
|
22
|
+
|
|
23
|
+
const output = await readFile(join(outputDir, 'script.hash.js'), 'utf8');
|
|
24
|
+
|
|
25
|
+
sub.test('minimized as a single line', () => {
|
|
26
|
+
assert.equal(output, processedJS);
|
|
27
|
+
});
|
|
28
|
+
sub.test('with whitespace trimmed', () => {
|
|
29
|
+
assert.ok(output.trim().length < inputJS.trim().length);
|
|
30
|
+
});
|
|
31
|
+
sub.test('with comments removed', () => {
|
|
32
|
+
assert.doesNotMatch(output, /\/\/ This is a comment/);
|
|
33
|
+
assert.doesNotMatch(output, /\/\*\*/);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should bundle ES modules', async () => {
|
|
38
|
+
await writeFile(
|
|
39
|
+
join(inputDir, 'script.hash.js'),
|
|
40
|
+
`
|
|
41
|
+
import sum from './input.js';
|
|
42
|
+
console.log(sum(2, 3));
|
|
43
|
+
`
|
|
44
|
+
);
|
|
45
|
+
await writeFile(join(inputDir, 'input.js'), inputJS);
|
|
46
|
+
|
|
47
|
+
await assert.doesNotReject(() => processJS({ inputDir, outputDir }));
|
|
48
|
+
|
|
49
|
+
const output = await readFile(join(outputDir, 'script.hash.js'), 'utf8');
|
|
50
|
+
|
|
51
|
+
assert.ok(output.includes('const sum=(a,b)=>{return a+b}'));
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should handle empty JavaScript file', async () => {
|
|
55
|
+
await writeFile(join(inputDir, 'script.hash.js'), '');
|
|
56
|
+
|
|
57
|
+
await assert.doesNotReject(() => processJS({ inputDir, outputDir }));
|
|
58
|
+
|
|
59
|
+
const output = await readFile(join(outputDir, 'script.hash.js'), 'utf8');
|
|
60
|
+
|
|
61
|
+
assert.equal(output, '');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should skip processing if JavaScript file does not exist', async () => {
|
|
65
|
+
await assert.doesNotReject(() => processJS({ inputDir, outputDir }));
|
|
66
|
+
});
|
|
67
|
+
});
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zulaica/site-bundler",
|
|
3
3
|
"author": "David Zulaica",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.7.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
7
|
-
"node": ">=
|
|
7
|
+
"node": ">=24.12.0"
|
|
8
8
|
},
|
|
9
9
|
"license": "UNLICENSED",
|
|
10
10
|
"bin": {
|
|
@@ -20,7 +20,9 @@
|
|
|
20
20
|
],
|
|
21
21
|
"scripts": {
|
|
22
22
|
"lint": "eslint \"lib/**\"",
|
|
23
|
-
"test": "
|
|
23
|
+
"test": "NODE_ENV=test node --test --test-concurrency=1 --require \"./lib/helpers/tests.mjs\"",
|
|
24
|
+
"test:watch": "npm run test -- --watch",
|
|
25
|
+
"test:coverage": "npm run test -- --experimental-test-coverage"
|
|
24
26
|
},
|
|
25
27
|
"repository": {
|
|
26
28
|
"type": "git",
|
|
@@ -31,30 +33,29 @@
|
|
|
31
33
|
},
|
|
32
34
|
"homepage": "https://github.com/zulaica/site-bundler#readme",
|
|
33
35
|
"dependencies": {
|
|
34
|
-
"@babel/core": "7.
|
|
35
|
-
"@babel/parser": "7.
|
|
36
|
-
"@babel/preset-env": "7.
|
|
37
|
-
"commander": "
|
|
38
|
-
"cssnano": "7.
|
|
39
|
-
"cssnano-preset-advanced": "7.0.
|
|
40
|
-
"htmlnano": "
|
|
41
|
-
"postcss": "8.
|
|
42
|
-
"postcss-import": "16.1.
|
|
43
|
-
"postcss-preset-env": "10.
|
|
36
|
+
"@babel/core": "7.28.5",
|
|
37
|
+
"@babel/parser": "7.28.5",
|
|
38
|
+
"@babel/preset-env": "7.28.5",
|
|
39
|
+
"commander": "14.0.2",
|
|
40
|
+
"cssnano": "7.1.2",
|
|
41
|
+
"cssnano-preset-advanced": "7.0.10",
|
|
42
|
+
"htmlnano": "3.0.0",
|
|
43
|
+
"postcss": "8.5.6",
|
|
44
|
+
"postcss-import": "16.1.1",
|
|
45
|
+
"postcss-preset-env": "10.5.0",
|
|
44
46
|
"postcss-url": "10.1.3",
|
|
45
|
-
"posthtml": "0.16.
|
|
47
|
+
"posthtml": "0.16.7",
|
|
46
48
|
"posthtml-hash": "1.2.2",
|
|
47
|
-
"rollup": "4.
|
|
49
|
+
"rollup": "4.54.0"
|
|
48
50
|
},
|
|
49
51
|
"devDependencies": {
|
|
50
|
-
"eslint": "9.
|
|
51
|
-
"eslint-config-prettier": "
|
|
52
|
-
"eslint-plugin-prettier": "5.
|
|
53
|
-
"globals": "
|
|
54
|
-
"prettier": "3.
|
|
52
|
+
"eslint": "9.39.2",
|
|
53
|
+
"eslint-config-prettier": "10.1.8",
|
|
54
|
+
"eslint-plugin-prettier": "5.5.4",
|
|
55
|
+
"globals": "16.5.0",
|
|
56
|
+
"prettier": "3.7.4"
|
|
55
57
|
},
|
|
56
58
|
"volta": {
|
|
57
|
-
"node": "
|
|
58
|
-
"npm": "10.8.2"
|
|
59
|
+
"node": "24.12.0"
|
|
59
60
|
}
|
|
60
61
|
}
|
package/lib/helpers/index.mjs
DELETED
package/lib/helpers/loggers.mjs
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { exit, stderr, stdout } from 'process';
|
|
2
|
-
import { cursorTo } from 'readline';
|
|
3
|
-
import { EMOJI } from './index.mjs';
|
|
4
|
-
|
|
5
|
-
export const logError = (error) => {
|
|
6
|
-
stderr.write(`\n${EMOJI.noEntry} An error has occurred\n`);
|
|
7
|
-
stderr.write(error.toString());
|
|
8
|
-
exit(1);
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export const logMessage = (message, update = false) => {
|
|
12
|
-
if (update) {
|
|
13
|
-
cursorTo(stdout, 0, null);
|
|
14
|
-
}
|
|
15
|
-
stdout.write(message);
|
|
16
|
-
};
|