v2.0.0
Poops 2.0 has no new features. It is the release where the core loop β watch,
build, reload β stops carrying old dependencies and old spellings, and where the
compat shims that survived the whole 1.x line finally go.
Changed
-
Poops now requires Node.js 22 or newer. Node 20 reached end of life in
April 2026, and the dependencies the dev loop is built on β the file watcher,
esbuild β assume a modern runtime anyway. CI tests on Node 22 and 24, on both
Ubuntu and Windows. -
Live reload is now served by Poops itself, on the server port. The
livereloadpackage is gone, and with it a second port, an old websocket
stack, and the snippet you had to paste into your templates."livereload": truealongside"serve"is all it takes. Poops answers
/__poops_reloadas a server-sent events stream and appends a small client
script to each HTML page it serves β appends it to the response, so nothing
lands in your build output. Behaviour is unchanged otherwise: one reload per
save once the build settles, CSS-only builds swap stylesheets in place
instead of reloading, and the browser reconnects by itself after a restart.Migrating: delete the
livereload.jssnippet from your templates (a leftover
one is harmless β it will 404 quietly), and droplivereload.port,
livereload.exclude,livereload.extraExtsandlivereload.extsfrom your
config. The last three had already stopped doing anything when the reload
server stopped watching files in 1.5.1. -
The file watcher moved from chokidar 3 to chokidar 5. Two majors of
watcher fixes, and one fewer legacy dependency tree undernode_modules.
Nothing in your config changes:watchhas always been a list of directories,
never globs, so chokidar 4 dropping glob support costs nothing here. Watch
mode behaves as before β one rebuild per save, CSS still hot-swaps, deletions
still remove their output. -
esbuild moved from 0.25 to 0.28, and the default
targetfromes2019to
es2020. esbuild is pre-1.0, so its minor bumps shift output by design;
absorbing that is what a major of ours is for. Expect small differences in
your bundles β the CommonJS interop helper is more careful around a throwing
module, andSymbol.forcalls are annotated as side-effect free, which makes
minified output slightly smaller.The new default target is the visible half: optional chaining (
?.) and
nullish coalescing (??) are ES2020, and compiling them down for browsers
that have shipped them since 2020 only made bundles bigger. Entries that set
their owntargetare untouched. -
timeDateFormatis nowdateFormat. It sets the default format for the
datefilter; the old name said the same thing twice. Deprecated and still
read through 2.x, gone in 3.0.Engines see the rename too:
registerFilters({ timeDateFormat, markupOut })
is nowregisterFilters({ dateFormat, markupOut }). This is a hard rename β
it lands before the engine interface becomes public API in this same release,
so a custom engine must update its parameter name for 2.0. -
outputis nowoutin the markup sub-features.llms,nav,feed,
searchIndex,sitemapandrobotsname their output file without, the
same word every entry in the config already uses:{ "nav": { "out": "nav.json", "root": "docs" } }outputis deprecated but still honoured through 2.x, warning once per
feature, and stops working in 3.0. The string shorthand ("nav": "nav.json")
is unaffected. -
Markup settings belong under
markup.options.markupnow has the shape
every other entry has βin,out, and everything else inoptions:{ "markup": { "in": "src/markup", "out": "dist", "options": { "engine": "nunjucks", "site": { "title": "My Site" }, "searchIndex": "search-index.json" } } }1.x read
engine,site,data,includePaths,timeDateFormat,
collections,searchIndex,sitemap,llms,robots,feed,nav,
baseURLandautoescapeat themarkup.level as well. That placement is
deprecated but still honoured through 2.x β each stray key logs a warning
naming its new home β and stops working in 3.0. Where both are set,options
wins.
Added
-
The markup engine interface is public API as of 2.0.
markup.options.engine
has always accepted any importable module, and
poops-shopify ships a production
engine against it β but nothing said the interface was stable, so a rename in
a patch release could have broken it silently. It is documented in
the engine API reference, semver applies to it from here on,
and a contract test asserts both builtin engines still expose the shape β a
failing test is a breaking change caught before it ships. -
serve.basedefaults to the markupoutdirectory. Nearly every config
set it to the path it had just built into. Set it only when the server should
serve somewhere else; an explicit value still wins, and a project with no
markupstill serves the working directory.
Removed
-
The
ssgconfig key. It has been an alias forreactorsince the rename,
and it was the last compatibility shim in the codebase. A config still using
it now gets told what to call it instead:[info] Config key "ssg" is renamed to "reactor" in 2.0 β ignored.
Internal
- Dependency bumps.
book-of-spells1.3 β 1.4 and apostcsspatch, both
routine. Dev-only:neostandard0.12 β 0.13, andsulphuris2 β 4 for the
example site's styles. ESLint stays on 9 β neostandard 0.13 still declares a
peer ofeslint@^9, so 10 has to wait for it.
Fixed
-
"Edit this page on GitHub" links work for collection items on Windows. A
collection item'sfilePathkept native separators while a regular page's was
posix, so on Windows the link for a post came out as
β¦/edit/main/src/posts\hello.md. Both are posix now. -
The image cache is read correctly across platforms. Its lookups all key on
posix paths, so a cache written on Windows β committed next to the images it
describes, or built in CI β matched nothing and galleries came up empty. Keys
and variant paths are normalized on read. The output-directory containment
check also no longer accepts a sibling directory whose name merely starts with
the output dir's (dist-oldfordist). -
A style edit hot-swaps the stylesheet the page actually links. With
minifyon, the reload chain was told aboutsite.csswhile the page linked
site.min.cssβ no stylesheet matched, so every style edit reloaded the whole
page instead of swapping the CSS. Both spellings are now reported (and with
justMinified, only the minified one, since the other is deleted).
Full Changelog: v1.9.8...v2.0.0