Poops vs Vite

Vite is the default answer, and for an app it usually still is. The reason to look elsewhere shows up on the other kind of project: a marketing site, a blog, a docs site, a WordPress theme. There the work is SCSS, a bit of TypeScript, some pages with front matter โ€” and Vite gives you a JavaScript config file, a plugin for Markdown, another for the sitemap, and a framework on top to turn any of it into HTML.

Poops covers that project with one JSON file. It does not cover Vite's project โ€” see the bottom of this page before you migrate anything.

What each one is

Vite 8 shipped in March 2026 with Rolldown, a Rust bundler, replacing the old esbuild-in-dev, Rollup-in-prod split โ€” one bundler for both, with the plugin API preserved. It is a dev server and a build tool for applications; HTML output beyond index.html is a job for a framework or a plugin.

Poops is a bundler (esbuild), a Sass compiler (Dart Sass), a PostCSS pipeline and a Jekyll-inspired site generator, all driven from poops.json. Eighteen direct dependencies, forty-one packages installed, Node โ‰ฅ 22.

Feature by feature

Poops Vite
Config poops.json โ€” no JS, no imports, no plugin objects vite.config.ts โ€” JavaScript you run
Dev server static files + SSE; CSS is swapped in place, everything else is a full page reload native ESM, HMR with module-level updates
Dev/prod parity one code path โ€” dev serves what the build wrote dev is unbundled ESM, prod is bundled; differences are rare but real
Bundler esbuild Rolldown (Rust)
Build speed not benchmarked here Rolldown is Vite's headline number โ€” InfoQ reports builds up to 30ร— faster; that figure is Vite's own, measured against Vite, not against Poops
Sass built in, plus design-token JSON imports install sass, Vite handles the rest
PostCSS / Tailwind a separate postcss key, so it does not run twice built in
Markdown, front matter, layouts built in โ€” Nunjucks or Liquid plugin, or a framework
Collections, taxonomies, pagination, RSS built in no
Sitemap, robots.txt, llms.txt, search index, nav tree, JSON-LD built in plugins, if they exist
Hashed filenames, asset manifest, HTML rewriting no โ€” you write the paths, they stay as written yes, automatic
Code splitting esbuild's own: "splitting": true with "format": "esm" and a directory out, which emits a hashed chunk per dynamic import โ€” nothing rewrites your HTML or emits preload hints managed, with preload directives
Plugin ecosystem none very large โ€” the strongest reason to pick Vite
Framework SPAs (React, Vue, Svelte) React via scripts and reactor; no framework HMR first-class for all of them
Library builds (IIFE + ESM + CJS from one source) yes, three entries in the config yes, build.lib

The same site, in each

A blog with SCSS, a bit of TypeScript, Markdown posts, a feed and a sitemap. In Poops that is the whole config:

{
  "markup": { "in": "src/markup", "out": "dist", "options": {
    "sitemap": "sitemap.xml",
    "feed": { "collection": "blog", "out": "feed.rss" }
  }},
  "styles": [{ "in": "src/scss/index.scss", "out": "dist/css/styles.css", "options": { "minify": true } }],
  "scripts": [{ "in": "src/js/main.ts", "out": "dist/js/main.js", "options": { "minify": true, "format": "iife" } }],
  "watch": ["src"],
  "livereload": true
}

In Vite it is vite.config.ts plus a Markdown plugin, a front-matter convention, a sitemap plugin and an RSS script โ€” or a framework on top that brings all four and its own model with them. Vite's answer is better once the site becomes an app; it is more moving parts while the site is a site.

The honest losses

No HMR. Poops' live reload is an EventSource that swaps a changed stylesheet in place โ€” the page does not reload for CSS, and scroll and state survive. Any other change reloads the page. Editing a React component with a filled-in form ten fields deep is exactly as annoying as that sounds.

No content hashing, no managed chunk graph. Nothing rewrites your HTML, so styles.css stays styles.css. Cache-bust with a query string, a versioned directory, or your CDN's rules. Splitting itself works โ€” esbuild's splitting option passes through and emits hashed chunks for dynamic imports โ€” but you get chunks in a directory, not a manifest, preload hints or <script> tags written for you. Size is not the constraint here; wiring is.

No plugin API, ever. CONTRIBUTING.md says a feature that can be a few lines of config does not get an extension point. That keeps the dependency list boring and the config learnable in an afternoon; it also means when Poops does not do a thing, you cannot add it from outside. You can, however, write a markup engine โ€” the one interface that is deliberately open.

Use Poops when

  • The output is a site. Size is not the line โ€” esbuild bundles thousands of lines as happily as fifty; what you give up is HMR and a managed chunk graph, not headroom.
  • The pages, the styles and the scripts should be one config, one command, plain files at the end.
  • You are bolting a front end onto WordPress, Laravel or Rails and want asset paths and nothing else โ€” no dev-server middleware, no manifest to read from PHP.
  • Config in JSON is a feature: nothing executes to tell you what your build does, and the $schema makes the editor complete it.

Use Vite when

  • You are building an application, not a site โ€” HMR while you work on component state is worth more than any of this.
  • You want hashed assets and a manifest without thinking about it.
  • You depend on a plugin nobody is going to reimplement โ€” MDX, legacy browser polyfills, an image pipeline you already tuned.
  • Your framework's toolchain is Vite (SvelteKit, Nuxt, Astro, Remix). Fighting that costs more than it saves.