html-bundle 6.1.7 → 6.2.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/README.md CHANGED
@@ -12,7 +12,7 @@ A (primarily) zero-config bundler for HTML files. The idea is to use HTML as Sin
12
12
  - 📦 Automatic Package Installation
13
13
  - 💨 HMR and automatic reconnect
14
14
  - ⚡ [ESBuild](https://github.com/evanw/esbuild)
15
- - 🦔 [Critical CSS](https://www.npmjs.com/package/critters)
15
+ - 🦔 [Critical CSS](https://www.npmjs.com/package/beasties)
16
16
  - 🚋 Watcher on PostCSS and Tailwind CSS and TS Config
17
17
  - 🛡️ Almost no need to restart
18
18
 
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+ import type { Router } from "express-serve-static-core";
3
+ import { type BuildOptions } from "esbuild";
4
+ import { type Options } from "beasties";
5
+ import { type Options as MinifyOptions } from "html-minifier-terser";
6
+ declare let router: Router | undefined;
7
+ export default router;
8
+ export type Config = {
9
+ build: string;
10
+ src: string;
11
+ port: number;
12
+ secure: boolean;
13
+ esbuild?: BuildOptions;
14
+ "html-minifier-terser"?: MinifyOptions;
15
+ critical?: Options;
16
+ deletePrev?: boolean;
17
+ isCritical?: boolean;
18
+ hmr?: boolean;
19
+ handler?: string;
20
+ host?: string;
21
+ key?: Buffer;
22
+ cert?: Buffer;
23
+ };
package/dist/bundle.mjs CHANGED
@@ -7,7 +7,7 @@ import { sep } from "path";
7
7
  import { glob } from "glob";
8
8
  import postcss from "postcss";
9
9
  import esbuild from "esbuild";
10
- import Critters from "critters";
10
+ import Beasties from "beasties";
11
11
  import { minify } from "html-minifier-terser";
12
12
  import { watch } from "chokidar";
13
13
  import { serialize, parse, parseFragment } from "parse5";
@@ -16,7 +16,7 @@ import awaitSpawn from "await-spawn";
16
16
  import { fileCopy, createDefaultServer, getPostCSSConfig, getBuildPath, createDir, bundleConfig, serverSentEvents, addHMRCode, } from "./utils.mjs";
17
17
  const isHMR = process.argv.includes("--hmr") || bundleConfig.hmr;
18
18
  const isCritical = process.argv.includes("--isCritical") || bundleConfig.isCritical;
19
- const critters = new Critters({
19
+ const beasties = new Beasties({
20
20
  path: bundleConfig.build,
21
21
  logLevel: "silent",
22
22
  ...bundleConfig.critical,
@@ -29,7 +29,7 @@ process.env.NODE_ENV = isHMR ? "development" : "production"; // just in case oth
29
29
  let timer = performance.now();
30
30
  let { plugins, options, file: postcssFile } = await getPostCSSConfig();
31
31
  let CSSprocessor = postcss(plugins);
32
- let fastify;
32
+ let router;
33
33
  const inlineFiles = new Set();
34
34
  const TEMPLATE_LITERAL_MINIFIER = /\n\s+/g;
35
35
  const INLINE_BUNDLE_FILE = /-bundle-\d+.tsx$/;
@@ -79,8 +79,9 @@ async function build(files, firstRun = true) {
79
79
  }
80
80
  console.log(`🚀 Build finished in ${(performance.now() - timer).toFixed(2)}ms ✨`);
81
81
  if (isHMR && firstRun) {
82
- fastify = await createDefaultServer(isSecure);
83
- await fastify.listen({ port: bundleConfig.port, host: bundleConfig.host });
82
+ const [dynamicRouter, server] = await createDefaultServer(isSecure);
83
+ router = dynamicRouter;
84
+ server.listen({ port: bundleConfig.port, host: bundleConfig.host });
84
85
  console.log(`💻 Server listening on http${isSecure ? "s" : ""}://${bundleConfig.host === "::" ? "localhost" : bundleConfig.host}:${bundleConfig.port} and is shared in the local network.`);
85
86
  console.log(`⌛ Waiting for file changes ...`);
86
87
  const chokidarOptions = { awaitWriteFinish: false };
@@ -336,8 +337,8 @@ async function minifyHTML(file, buildFile) {
336
337
  if (isCritical) {
337
338
  try {
338
339
  const isPartical = !fileText.startsWith("<!DOCTYPE html>");
339
- fileText = await critters.process(fileText);
340
- // fix critters jsdom
340
+ fileText = await beasties.process(fileText);
341
+ // fix beasties jsdom
341
342
  if (isPartical) {
342
343
  fileText = fileText.replace(/<\/?(html|head|body)>/g, "");
343
344
  }
@@ -368,3 +369,4 @@ catch (err) {
368
369
  console.error(err);
369
370
  process.exit(1);
370
371
  }
372
+ export default router;
@@ -0,0 +1,22 @@
1
+ import type { Config } from "./bundle.mjs";
2
+ import type { Router } from "express-serve-static-core";
3
+ import { type Server } from "http";
4
+ import { type Server as HTTPSServer } from "https";
5
+ import postcssrc from "postcss-load-config";
6
+ import cssnano from "cssnano";
7
+ import { parse, parseFragment } from "parse5";
8
+ export declare const bundleConfig: Config;
9
+ export declare function fileCopy(file: string): Promise<void>;
10
+ export declare function createDir(file: string): Promise<string | undefined>;
11
+ export declare function getBuildPath(file: string): string;
12
+ export declare let serverSentEvents: undefined | (({ file, html }: {
13
+ file: string;
14
+ html?: string;
15
+ }) => void);
16
+ export declare function createDefaultServer(isSecure: boolean): Promise<[Router, Server | HTTPSServer]>;
17
+ export declare function getPostCSSConfig(): Promise<postcssrc.Result | {
18
+ plugins: (typeof cssnano)[];
19
+ options: {};
20
+ file: string;
21
+ }>;
22
+ export declare function addHMRCode(html: string, file: string, ast?: ReturnType<typeof parse | typeof parseFragment>): string;
package/dist/utils.mjs CHANGED
@@ -1,7 +1,8 @@
1
1
  import { copyFile, mkdir, readFile } from "fs/promises";
2
2
  import path from "path";
3
- import Fastify from "fastify";
4
- import fastifyStatic from "@fastify/static";
3
+ import http from "http";
4
+ import https from "https";
5
+ import express from "express";
5
6
  import postcssrc from "postcss-load-config";
6
7
  import cssnano from "cssnano";
7
8
  import { parse, parseFragment, serialize } from "parse5";
@@ -21,32 +22,15 @@ export function getBuildPath(file) {
21
22
  const CONNECTIONS = []; // In order to send the HMR information
22
23
  export let serverSentEvents;
23
24
  export async function createDefaultServer(isSecure) {
24
- const fastify = Fastify(isSecure
25
- ? {
26
- http2: true,
27
- https: {
28
- key: bundleConfig.key ||
29
- (await readFile(path.join(process.cwd(), "localhost-key.pem"))),
30
- cert: bundleConfig.cert ||
31
- (await readFile(path.join(process.cwd(), "localhost.pem"))),
32
- },
33
- }
34
- : void 0);
35
- fastify.setNotFoundHandler(async (_req, reply) => {
36
- reply.type("text/html");
37
- const file = await readFile(path.join(process.cwd(), bundleConfig.build, "/index.html"), {
38
- encoding: "utf-8",
39
- });
40
- return reply.send(file);
41
- });
42
- fastify.register(fastifyStatic, {
43
- root: path.join(process.cwd(), bundleConfig.build),
44
- });
45
- fastify.get("/hmr", (_req, reply) => {
46
- reply.raw.setHeader("Content-Type", "text/event-stream");
47
- reply.raw.setHeader("Cache-Control", "no-cache");
48
- !isSecure && reply.raw.setHeader("Connection", "keep-alive");
49
- CONNECTIONS.push(reply.raw);
25
+ const router = express.Router();
26
+ const app = express();
27
+ app.use(router);
28
+ app.use(express.static(path.join(process.cwd(), bundleConfig.build)));
29
+ router.get("/hmr", (_req, reply) => {
30
+ reply.setHeader("Content-Type", "text/event-stream");
31
+ reply.setHeader("Cache-Control", "no-cache");
32
+ !isSecure && reply.setHeader("Connection", "keep-alive");
33
+ CONNECTIONS.push(reply);
50
34
  serverSentEvents = (data) => {
51
35
  if (/\.(jsx?|tsx?)$/.test(data.file)) {
52
36
  data.file = data.file.replace(".ts", ".js").replace(".jsx", ".js");
@@ -56,7 +40,24 @@ export async function createDefaultServer(isSecure) {
56
40
  });
57
41
  };
58
42
  });
59
- return fastify;
43
+ app.use(async (_req, res) => {
44
+ res.setHeader("Content-Type", "text/html");
45
+ const file = await readFile(path.join(process.cwd(), bundleConfig.build, "index.html"), {
46
+ encoding: "utf-8",
47
+ });
48
+ res.send(file);
49
+ });
50
+ return [
51
+ router,
52
+ isSecure
53
+ ? https.createServer({
54
+ key: bundleConfig.key ||
55
+ (await readFile(path.join(process.cwd(), "localhost-key.pem"))),
56
+ cert: bundleConfig.cert ||
57
+ (await readFile(path.join(process.cwd(), "localhost.pem"))),
58
+ }, app)
59
+ : http.createServer({}, app),
60
+ ];
60
61
  }
61
62
  export async function getPostCSSConfig() {
62
63
  try {
package/package.json CHANGED
@@ -1,50 +1,56 @@
1
- {
2
- "name": "html-bundle",
3
- "version": "6.1.7",
4
- "description": "A very simple bundler for HTML SFC",
5
- "bin": "./dist/bundle.mjs",
6
- "types": "./src/config.d.ts",
7
- "scripts": {
8
- "start": "tsc",
9
- "update": "npx npm-check-updates -u && npx typesync && npm i && npm outdated"
10
- },
11
- "keywords": [
12
- "bundler",
13
- "SFC",
14
- "HTML",
15
- "TypeScript",
16
- "esbuild",
17
- "hydro-js"
18
- ],
19
- "author": "Fabian Klingenberg <klingenberg.fabian@gmx.de> (https://klingenberg.netlify.app/)",
20
- "license": "MIT",
21
- "devDependencies": {
22
- "@types/cssnano": "^5.1.0",
23
- "@types/glob": "^8.1.0",
24
- "@types/html-minifier-terser": "^7.0.2",
25
- "@types/parse5": "^7.0.0",
26
- "@types/postcss-load-config": "^3.0.1",
27
- "typescript": "^5.6.2"
28
- },
29
- "repository": {
30
- "type": "git",
31
- "url": "git+https://github.com/Krutsch/html-bundle.git"
32
- },
33
- "bugs": "https://github.com/Krutsch/html-bundle/issues",
34
- "dependencies": {
35
- "@fastify/static": "^8.0.1",
36
- "@web/parse5-utils": "^2.1.0",
37
- "await-spawn": "^4.0.2",
38
- "chokidar": "^4.0.1",
39
- "critters": "^0.0.24",
40
- "cssnano": "^7.0.6",
41
- "esbuild": "^0.24.0",
42
- "fastify": "^5.0.0",
43
- "glob": "^11.0.0",
44
- "html-minifier-terser": "^7.2.0",
45
- "hydro-js": "^1.5.21",
46
- "parse5": "^7.1.2",
47
- "postcss": "^8.4.47",
48
- "postcss-load-config": "^6.0.1"
49
- }
50
- }
1
+ {
2
+ "name": "html-bundle",
3
+ "version": "6.2.0",
4
+ "description": "A very simple bundler for HTML SFC",
5
+ "bin": "./dist/bundle.mjs",
6
+ "main": "./dist/bundle.mjs",
7
+ "module": "./dist/bundle.mjs",
8
+ "exports": {
9
+ "import": "./dist/bundle.mjs",
10
+ "default": "./dist/bundle.mjs"
11
+ },
12
+ "types": "./dist/bundle.d.mts",
13
+ "scripts": {
14
+ "start": "tsc",
15
+ "update": "npx npm-check-updates -u && npx typesync && npm i && npm outdated"
16
+ },
17
+ "keywords": [
18
+ "bundler",
19
+ "SFC",
20
+ "HTML",
21
+ "TypeScript",
22
+ "esbuild",
23
+ "hydro-js"
24
+ ],
25
+ "author": "Fabian Klingenberg <klingenberg.fabian@gmx.de> (https://klingenberg.works/)",
26
+ "license": "MIT",
27
+ "devDependencies": {
28
+ "@types/cssnano": "^5.1.3",
29
+ "@types/express": "~5.0.2",
30
+ "@types/glob": "^8.1.0",
31
+ "@types/html-minifier-terser": "^7.0.2",
32
+ "@types/parse5": "^7.0.0",
33
+ "@types/postcss-load-config": "^3.0.1",
34
+ "typescript": "^5.8.3"
35
+ },
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/Krutsch/html-bundle.git"
39
+ },
40
+ "bugs": "https://github.com/Krutsch/html-bundle/issues",
41
+ "dependencies": {
42
+ "@web/parse5-utils": "^2.1.0",
43
+ "await-spawn": "^4.0.2",
44
+ "beasties": "^0.3.4",
45
+ "chokidar": "^4.0.3",
46
+ "cssnano": "^7.0.7",
47
+ "esbuild": "^0.25.5",
48
+ "express": "^5.1.0",
49
+ "glob": "^11.0.2",
50
+ "html-minifier-terser": "^7.2.0",
51
+ "hydro-js": "^1.8.8",
52
+ "parse5": "^7.3.0",
53
+ "postcss": "^8.5.4",
54
+ "postcss-load-config": "^6.0.1"
55
+ }
56
+ }
package/src/bundle.mts CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  import type { Node, TextNode } from "@web/parse5-utils";
4
4
  import type { AcceptedPlugin } from "postcss";
5
+ import type { Router } from "express-serve-static-core";
5
6
  import { performance } from "perf_hooks";
6
7
  import { readFile, rm, writeFile, readdir, lstat } from "fs/promises";
7
8
  import { execFile } from "child_process";
@@ -9,9 +10,10 @@ import { promisify } from "util";
9
10
  import { sep } from "path";
10
11
  import { glob } from "glob";
11
12
  import postcss from "postcss";
12
- import esbuild from "esbuild";
13
- import Critters from "critters";
14
- import { minify } from "html-minifier-terser";
13
+ import express from "express";
14
+ import esbuild, { type BuildOptions } from "esbuild";
15
+ import Beasties, { type Options } from "beasties";
16
+ import { minify, type Options as MinifyOptions } from "html-minifier-terser";
15
17
  import { watch } from "chokidar";
16
18
  import { serialize, parse, parseFragment } from "parse5";
17
19
  import { getTagName, findElements } from "@web/parse5-utils";
@@ -30,7 +32,7 @@ import {
30
32
  const isHMR = process.argv.includes("--hmr") || bundleConfig.hmr;
31
33
  const isCritical =
32
34
  process.argv.includes("--isCritical") || bundleConfig.isCritical;
33
- const critters = new Critters({
35
+ const beasties = new Beasties({
34
36
  path: bundleConfig.build,
35
37
  logLevel: "silent",
36
38
  ...bundleConfig.critical,
@@ -44,7 +46,7 @@ process.env.NODE_ENV = isHMR ? "development" : "production"; // just in case oth
44
46
  let timer = performance.now();
45
47
  let { plugins, options, file: postcssFile } = await getPostCSSConfig();
46
48
  let CSSprocessor = postcss(plugins as AcceptedPlugin[]);
47
- let fastify;
49
+ let router: Router | undefined;
48
50
  const inlineFiles = new Set<string>();
49
51
  const TEMPLATE_LITERAL_MINIFIER = /\n\s+/g;
50
52
  const INLINE_BUNDLE_FILE = /-bundle-\d+.tsx$/;
@@ -96,8 +98,9 @@ async function build(files: string[], firstRun = true) {
96
98
  );
97
99
 
98
100
  if (isHMR && firstRun) {
99
- fastify = await createDefaultServer(isSecure);
100
- await fastify.listen({ port: bundleConfig.port, host: bundleConfig.host });
101
+ const [dynamicRouter, server] = await createDefaultServer(isSecure);
102
+ router = dynamicRouter;
103
+ server.listen({ port: bundleConfig.port, host: bundleConfig.host });
101
104
  console.log(
102
105
  `💻 Server listening on http${isSecure ? "s" : ""}://${
103
106
  bundleConfig.host === "::" ? "localhost" : bundleConfig.host
@@ -398,8 +401,8 @@ async function minifyHTML(file: string, buildFile: string) {
398
401
  if (isCritical) {
399
402
  try {
400
403
  const isPartical = !fileText.startsWith("<!DOCTYPE html>");
401
- fileText = await critters.process(fileText);
402
- // fix critters jsdom
404
+ fileText = await beasties.process(fileText);
405
+ // fix beasties jsdom
403
406
  if (isPartical) {
404
407
  fileText = fileText.replace(/<\/?(html|head|body)>/g, "");
405
408
  }
@@ -431,3 +434,22 @@ try {
431
434
  console.error(err);
432
435
  process.exit(1);
433
436
  }
437
+
438
+ export default router;
439
+
440
+ export type Config = {
441
+ build: string;
442
+ src: string;
443
+ port: number;
444
+ secure: boolean;
445
+ esbuild?: BuildOptions;
446
+ "html-minifier-terser"?: MinifyOptions;
447
+ critical?: Options;
448
+ deletePrev?: boolean;
449
+ isCritical?: boolean;
450
+ hmr?: boolean;
451
+ handler?: string;
452
+ host?: string;
453
+ key?: Buffer;
454
+ cert?: Buffer;
455
+ };
package/src/utils.mts CHANGED
@@ -1,12 +1,11 @@
1
- import type { Options as HTMLOptions } from "html-minifier-terser";
2
- import type { Options } from "critters";
3
- import type { BuildOptions } from "esbuild";
4
1
  import type { Node } from "@web/parse5-utils";
5
- import type { FastifyServerOptions } from "fastify";
2
+ import type { Config } from "./bundle.mjs";
3
+ import type { Router } from "express-serve-static-core";
6
4
  import { copyFile, mkdir, readFile } from "fs/promises";
7
5
  import path from "path";
8
- import Fastify from "fastify";
9
- import fastifyStatic from "@fastify/static";
6
+ import http, { type Server } from "http";
7
+ import https, { type Server as HTTPSServer } from "https";
8
+ import express from "express";
10
9
  import postcssrc from "postcss-load-config";
11
10
  import cssnano from "cssnano";
12
11
  import { parse, parseFragment, serialize } from "parse5";
@@ -16,7 +15,6 @@ import {
16
15
  findElement,
17
16
  appendChild,
18
17
  } from "@web/parse5-utils";
19
- import { Config } from "./config";
20
18
 
21
19
  export const bundleConfig = await getBundleConfig();
22
20
 
@@ -38,42 +36,19 @@ const CONNECTIONS: Array<any> = []; // In order to send the HMR information
38
36
  export let serverSentEvents:
39
37
  | undefined
40
38
  | (({ file, html }: { file: string; html?: string }) => void);
41
- export async function createDefaultServer(isSecure: boolean) {
42
- const fastify = Fastify(
43
- isSecure
44
- ? ({
45
- http2: true,
46
- https: {
47
- key:
48
- bundleConfig.key ||
49
- (await readFile(path.join(process.cwd(), "localhost-key.pem"))),
50
- cert:
51
- bundleConfig.cert ||
52
- (await readFile(path.join(process.cwd(), "localhost.pem"))),
53
- },
54
- } as FastifyServerOptions)
55
- : void 0
56
- );
57
- fastify.setNotFoundHandler(async (_req, reply) => {
58
- reply.type("text/html");
59
- const file = await readFile(
60
- path.join(process.cwd(), bundleConfig.build, "/index.html"),
61
- {
62
- encoding: "utf-8",
63
- }
64
- );
65
- return reply.send(file);
66
- });
67
- fastify.register(fastifyStatic, {
68
- root: path.join(process.cwd(), bundleConfig.build),
69
- });
70
- fastify.get("/hmr", (_req, reply) => {
71
- reply.raw.setHeader("Content-Type", "text/event-stream");
72
- reply.raw.setHeader("Cache-Control", "no-cache");
73
- !isSecure && reply.raw.setHeader("Connection", "keep-alive");
74
-
75
- CONNECTIONS.push(reply.raw);
39
+ export async function createDefaultServer(
40
+ isSecure: boolean
41
+ ): Promise<[Router, Server | HTTPSServer]> {
42
+ const router = express.Router();
43
+ const app = express();
44
+ app.use(router);
45
+ app.use(express.static(path.join(process.cwd(), bundleConfig.build)));
76
46
 
47
+ router.get("/hmr", (_req, reply) => {
48
+ reply.setHeader("Content-Type", "text/event-stream");
49
+ reply.setHeader("Cache-Control", "no-cache");
50
+ !isSecure && reply.setHeader("Connection", "keep-alive");
51
+ CONNECTIONS.push(reply);
77
52
  serverSentEvents = (data) => {
78
53
  if (/\.(jsx?|tsx?)$/.test(data.file)) {
79
54
  data.file = data.file.replace(".ts", ".js").replace(".jsx", ".js");
@@ -83,7 +58,34 @@ export async function createDefaultServer(isSecure: boolean) {
83
58
  });
84
59
  };
85
60
  });
86
- return fastify;
61
+
62
+ app.use(async (_req, res) => {
63
+ res.setHeader("Content-Type", "text/html");
64
+ const file = await readFile(
65
+ path.join(process.cwd(), bundleConfig.build, "index.html"),
66
+ {
67
+ encoding: "utf-8",
68
+ }
69
+ );
70
+ res.send(file);
71
+ });
72
+
73
+ return [
74
+ router,
75
+ isSecure
76
+ ? https.createServer(
77
+ {
78
+ key:
79
+ bundleConfig.key ||
80
+ (await readFile(path.join(process.cwd(), "localhost-key.pem"))),
81
+ cert:
82
+ bundleConfig.cert ||
83
+ (await readFile(path.join(process.cwd(), "localhost.pem"))),
84
+ },
85
+ app
86
+ )
87
+ : http.createServer({}, app),
88
+ ];
87
89
  }
88
90
 
89
91
  export async function getPostCSSConfig() {
package/tsconfig.json CHANGED
@@ -6,6 +6,7 @@
6
6
  "outDir": "./dist",
7
7
  "rootDir": "./src",
8
8
  "strict": true,
9
+ "declaration": true,
9
10
  "skipLibCheck": true,
10
11
  "moduleResolution": "node",
11
12
  "esModuleInterop": true,
package/src/config.d.ts DELETED
@@ -1,16 +0,0 @@
1
- export type Config = {
2
- build: string;
3
- src: string;
4
- port: number;
5
- secure: boolean;
6
- esbuild?: BuildOptions;
7
- "html-minifier-terser"?: HTMLOptions;
8
- critical?: Options;
9
- deletePrev?: boolean;
10
- isCritical?: boolean;
11
- hmr?: boolean;
12
- handler?: string;
13
- host?: string;
14
- key?: Buffer;
15
- cert?: Buffer;
16
- };