Poops vs webpack, Rollup & Parcel

The webpack config that nobody on the team can read is a genre. It starts as twenty lines, acquires a loader for Sass, a loader for the loader, a plugin to extract the CSS the loaders just inlined, a resolve.alias block, and a comment saying do not touch this, it took a day. Two years later the project is a landing page with a contact form, and the toolchain has more dependencies than the site has pages.

Poops is the reaction to that: in, out, options โ€” and no place for that config to grow into.

Where the three stand

All read from npm in August 2026:

Latest Notes
webpack 5.109.x actively maintained; the 2026 roadmap targets native CSS support, built-in TypeScript and a path to webpack 6
Rollup 4.62.x frequent releases; still the reference for library bundling, and the plugin API Rolldown kept
Parcel 2.16.x zero-config by design; last release six months before this page was written
Rspack 2.x not compared here โ€” a Rust, webpack-compatible bundler, and the thing to look at if the reason you are reading this page is webpack is slow

Feature by feature

Poops webpack Rollup Parcel
Config one JSON file webpack.config.js, loaders + plugins rollup.config.js, plugins none for the common case
Learning surface the keys in the config reference loaders, rules, plugins, resolve, optimization plugin lifecycle hooks its conventions, when you need to leave them
Escape hatch esbuild options pass through a loader or plugin a plugin a .parcelrc transformer
Sass built in sass-loader + css-loader + MiniCssExtractPlugin a plugin built in
PostCSS / Tailwind own config key postcss-loader a plugin built in
HTML pages, layouts, front matter built in, Nunjucks or Liquid html-webpack-plugin, one page at a time no entry HTML, no templating
Collections, taxonomies, RSS, sitemap, search index built in no no no
Content hashing + HTML rewriting no yes via plugins yes
Code splitting esbuild's splitting โ€” hashed chunks, but no manifest and no HTML rewriting yes, SplitChunksPlugin yes, and precise yes
Module federation no yes โ€” its own territory no no
Tree-shaken library output esbuild's, three entries for IIFE/ESM/CJS yes the best of the four for this yes
Dev experience rebuild + reload; CSS swapped in place dev server with HMR plugin-provided watch dev server with HMR
Dependencies you install 18 direct, 41 packages webpack + cli + loaders + plugins rollup + plugins parcel

The same job, spelled out

Bundle a TypeScript entry, compile SCSS beside it, minify both, keep sourcemaps on the unminified twin. In webpack that is ts-loader (or babel-loader plus a preset), sass-loader โ†’ css-loader โ†’ MiniCssExtractPlugin.loader, a rules array to wire them to extensions, the plugin in plugins, and optimization.minimizer for the CSS half. In Poops it is the file itself:

{
  "scripts": [{
    "in": "src/js/main.ts",
    "out": "dist/js/main.js",
    "options": { "minify": true, "sourcemap": true, "format": "iife", "target": "es2019" }
  }],
  "styles": [{
    "in": "src/scss/index.scss",
    "out": "dist/css/styles.css",
    "options": { "minify": true, "sourcemap": true }
  }]
}

Both emit main.js + main.min.js and styles.css + styles.min.css. The difference is that the second one has no loader order to get wrong, and the $schema reference at the top of the file makes the editor complete every key โ€” a typo is caught as you type it rather than at build time.

Add "markup" and the same file also builds the pages, which is the part webpack, Rollup and Parcel were never trying to do.

The part Poops refuses

There is no plugin API and there will not be one. A feature that fits in a few lines of config does not get an extension point, and one that does not fit gets argued about in an issue instead. That refusal is the whole design: it is why the dependency list is boring, why the config is JSON, and why there is no version of this project where you write a poops.config.js that imports four packages.

The cost is real and it is exactly webpack's strength: when Poops does not do something, you cannot bolt it on. A custom transform for a file type nobody has heard of is a loader in webpack and a fork in Poops โ€” or a markup engine, which is the one interface left open, because a template language is a whole job rather than a hook.

Use webpack, Rollup or Parcel when

If Use Why
You need module federation or a micro-frontend split webpack Nothing else here does it
You publish a library and want the smallest, cleanest ESM output with precise external control Rollup It has been the reference for a decade, and Poops' esbuild output is fine but blunter
You want zero config for an app with many asset types Parcel Its conventions cover more file types than Poops does
The existing config works and nobody is fighting it leave it A migration you do not need is a bug you introduce
webpack is only slow Rspack, or Vite Both are drop-in-ish and Rust-fast; Poops is a different tool, not a faster webpack

Use Poops when

  • The project is a site with a front end: pages, SCSS and TypeScript in one config, one command, plain files out.
  • The build should be readable by whoever picks the project up next year โ€” including you. JSON, no imports, with $schema completing the keys in the editor.
  • You want the toolchain to be one dependency instead of a bundler plus five loaders plus three plugins that have to agree on versions.
  • Nobody on the team wants to own a webpack.config.js again.

The size of the JavaScript is not the deciding factor โ€” esbuild handles large bundles fine. What decides it is whether you need managed chunks, a manifest and federation, or whether you need the config to stay small enough to read.