A (primarily) zero-config bundler for HTML files. The idea is to use HTML as Single File Components, because HTML can already include <style>
and <script>
elements.
- 🦾 TypeScript (reference it as .js or write inline TS)
- 📦 Automatic Package Installation
- 💨 HMR and automatic reconnect
- ⚡ ESBuild
- 🦔 Critical CSS
- 🚋 Watcher on PostCSS and Tailwind CSS and TS Config
- 🛡️ Almost no need to restart
$ npm install -D html-bundle
Add an entry to script in package.json (see flags below).
{
"scripts": {
"build": "html-bundle"
}
}
Add a postcss.config.js
file and run the build command.
If you do not create this config file, a minimal in-memory config file will be created with cssnano
as plugin.
$ npm run build
--hmr
: boots up a static server and enables Hot Module Replacement. This generates a development build and works best when not triggered from the main index.html
--secure
: creates a secure HTTP2 over HTTPS instance. This requires the files localhost.pem
and localhost-key.pem
in the root folder. You can generate them with mkcert for instance.
--isCritical
: uses critical to extract and inline critical-path CSS to HTML.
--handler
: path to your custom handler. Here, you can handle all non-supported files. You can get the filename via process.argv[2]
.
The CLI flags can also be set by the config. Flags set by the CLI will override the config. Generate the config in the root and call it "bundle.config.js"
src: input path. Default to "src"
build: output path. Defaults to "build"
port: For the HMR Server. Defaults to 5000
deletePrev: Whether to delelte the build folder. Defaults to true
esbuild: Your additional config
html-minifier-terser: Your additional config
critical: Your additional config
Example:
/** @type {import('html-bundle').Config} */
export default {
secure: true,
handler: "utils/staticFiles.js",
esbuild: {
external: ["images"],
},
};
The bundler always globs all HTML, CSS and TS/JS files from the src
(config) directory and processes them to the build
(config) directory. PostCSS is being used for CSS files and inline styles, html-minifier-terser for HTML and esbuild to bundle, minify, etc. for inline and referenced TS/JS. Server-sent events and hydro-js are used for HMR. In order to trigger SPA Routers, the popstate event is being triggered after HMR Operations.
Get the idea from hydro-starter.
Set "jsxFactory": "h"
in tsconfig.json
for JSX.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Example</title>
<meta name="Description" content="Example for html-bundle" />
<script type="module">
import { render, h, reactive } from "hydro-js";
function Example({ name }) {
return <main id="app">Hi {name}</main>;
}
const name = reactive("Tester");
render(<Example name={name} />, "#app");
</script>
<style>
body {
background-color: whitesmoke;
}
</style>
</head>
<body>
<main id="app"></main>
</body>
</html>
Set "jsxFactory": "h"
in tsconfig.json
.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vue Example</title>
</head>
<script type="module">
import { createApp, h } from "vue";
const App = {
data() {
return {
name: "Fabian",
};
},
render() {
return <p>{this.name}</p>;
},
};
createApp(App).mount("#app");
</script>
<body>
<div id="app"></div>
</body>
</html>
Set "jsxFactory": "React.createElement"
in tsconfig.json
.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>React Example</title>
</head>
<script type="module">
import React, { useState } from "react";
import { createRoot } from "react-dom/client";
function Example() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
createRoot(document.getElementById("app")).render(<Example />);
</script>
<body>
<div id="app"></div>
</body>
</html>