A small, readable static-site pipeline — HTML partials, Tailwind CSS 4, live reload, and a production build that actually works.
Not every site needs a framework. This is the build layer for the ones that
don't: write plain HTML with reusable partials, style it with Tailwind, and get
a minified, optimized dist/ folder you can drop on any host.
- HTML partials —
@@include('./partials/header.html'), no templating language to learn - Tailwind CSS 4 — configured in CSS, no
tailwind.config.js - Live reload — Browsersync reloads on save, and injects CSS without a refresh
- Real production build — minified CSS and JS, images re-encoded with
sharp - Zero runtime dependencies — output is plain HTML, CSS, JS and images
git clone https://github.com/rahmanow/gulp-starter-pack.git my-site
cd my-site
npm install
npm run devThen open http://localhost:9050. Edit anything in src/ and the browser
updates itself.
Requires Node.js 20.19+, 22.13+ or 24+. Run
nvm useto pick up the version in.nvmrc.
Using this as a template? Click Use this template on GitHub, or delete the git history and start fresh:
rm -rf .git && git init| Command | What it does |
|---|---|
npm run dev |
Build to .tmp/, serve on port 9050, watch and live-reload |
npm run build |
Optimized production build into dist/ |
npm run zip |
Build, then archive it to release/gulp-starter-pack-<version>.zip |
npm run deploy |
Build, then publish to surge.sh (needs configuring) |
npm run clean |
Delete .tmp/, dist/ and release/ |
npm run lint |
ESLint over the build config and src/js/ |
npm run format |
Format everything with Prettier |
npm run check |
Lint + format check + build — the same suite CI runs |
Every script maps to a Gulp task, so npx gulp build works too.
src/ Everything you edit
├── index.html A page. Add more alongside it.
├── partials/ Fragments pulled in with @@include — never emitted
│ ├── header.html
│ └── footer.html
├── css/
│ └── main.css Tailwind entry point and design tokens
├── js/
│ ├── main.js Your code — bundled into js/main.js
│ ├── libs/ Bundled first, ahead of your code
│ └── vendor/ Copied verbatim, never bundled or minified
└── img/ Optimized during production builds
config.js Paths, dev-server port, deploy target
gulpfile.js The pipeline itself
.tmp/ Development output (gitignored, scratch)
dist/ Production output (gitignored)
release/ Zipped builds (gitignored)
.tmp/ is the fast, unminified development build that Browsersync serves. It is
scratch space, which is why it is hidden — you never deploy it. dist/ is the
optimized build you ship. Both are regenerated from scratch, so never edit them
directly.
Any .html file in src/ becomes a page. Anything in src/partials/ is a
fragment: it is included into pages but never emitted on its own.
@@include('./partials/header.html')
<h1>Hello</h1>
@@include('./partials/footer.html')Includes can pass data, which is handy for per-page titles:
@@include('./partials/header.html', { "title": "About us" })Then in the partial, @@title is substituted. See
gulp-file-include for the full
syntax.
Tailwind CSS 4 is configured in CSS, not JavaScript. Open
src/css/main.css:
@import "tailwindcss" source(none);
@source "../*.html";
@source "../partials/**/*.html";
@source "../js/**/*.js";
@theme {
--color-brand-500: oklch(0.68 0.16 155);
--radius-card: 0.875rem;
}Tokens in @theme become utilities automatically — --color-brand-500 gives
you bg-brand-500, text-brand-500, border-brand-500, and
--radius-card gives you rounded-card. There is no config file to keep in
sync.
source(none) turns off automatic file scanning so the build never walks
node_modules/ or your own output. The trade-off is that new template folders
need an @source line, or their classes will not be generated.
Reusable component classes go in @layer components:
@layer components {
.btn {
@apply rounded-card bg-brand-500 px-4 py-2 font-medium text-white;
}
}Coming from 1.x? Sass has been removed — Tailwind 4 is built to replace preprocessors and advises against pairing the two. Nesting and
@applystill work; see CHANGELOG.md to migrate.
Files in src/js/libs/ are concatenated first, then everything directly in
src/js/, producing a single minified js/main.js.
Anything in src/js/vendor/ is copied through untouched — use it for pre-built
libraries you want to load with their own <script> tag.
There is no Babel step. Output targets modern browsers, which is the same baseline Tailwind 4 requires (Safari 16.4+, Chrome 111+, Firefox 128+).
Development copies images as-is to keep the watch loop fast. Production re-encodes them with sharp — the sample cover image drops by about 86%. Anything sharp cannot process (SVG, video) passes through untouched instead of failing the build.
Everything lives in config.js:
export default {
port: 9050, // dev server port
open: false, // open a browser on start
src: "./src",
dev: "./.tmp", // development output (scratch)
dist: "./dist", // production output
surgeDomain: "", // set to enable `npm run deploy`
// ...paths and image options
};Adding a folder of templates? Add its glob to paths.html and an @source
line in src/css/main.css, so Tailwind sees the classes you use there.
dist/ is a static folder — host it anywhere.
GitHub Pages is already wired up. Enable it under
Settings → Pages → Source: GitHub Actions and every push to master
publishes automatically via .github/workflows/pages.yml.
Netlify / Vercel — build command npm run build, publish directory dist.
Cloudflare Workers — add a wrangler.jsonc pointing at the build output,
then run npx wrangler deploy:
A purely static site needs no Worker script — just the assets block.
Cloudflare recommends Workers over Pages for new projects;
Pages still works, but new features are going to Workers.
surge.sh — set your domain in config.js, then npm run deploy:
surgeDomain: "my-site.surge.sh",It refuses to run while that is empty rather than guessing a target.
Issues and pull requests are welcome — see CONTRIBUTING.md.
Run npm run check before opening a PR; it runs exactly what CI runs.
Working with an AI assistant? AGENTS.md documents the repo's conventions and invariants in a form agents can follow.
MIT © Azat Rahmanov
{ "name": "gulp-starter-pack", "compatibility_date": "2026-08-28", "assets": { "directory": "./dist" } }