Repository navigation
Warlock.js 5.39.0
Released 2026-10-26.
Keep every family package (@warlock.js/* and create-warlock) on the same version.
There are no breaking changes in this release. Two changes alter behaviour without a
type error; review them before upgrading (section 1).
1. Breaking changes
- None. 5.39.0 has no breaking changes.
Behaviour changes to review
--versionand-vprint the Warlock version only when no command is given. A
command can take its own--versionoption (core).- Core-level refusals on page hosts now render the site's page for HTML requests
(core,web). AGETorHEADrequest that namestext/htmlinAcceptgets the
page for a refused path such as/public/../x(403) or a malformed URL (400). API clients
keep the JSON answer.
2. Standalone builds and fewer files (core, web)
-
Single bundle for web pages.
build.singleBundlenow works with web pages. The server
pages and routes are inlined into onedist/app.js, andnode dist/app.jsstarts from a
copy ofdist/with nonode_modulesabove it. A copy ofdist/also works from any
working directory, because its client folder is found next to the running bundle. -
Native addons are staged automatically. A package with a
.nodebinary stays external
and is copied intodist/node_modules/<package>with only what it needs to load. The build
report names each one. -
Optional integrations are detected. A lazy
import()orrequire()of an optional peer
or optional dependency that a framework package lists, and the app does not declare, stays a
lazy runtime import that never runs. The build report names it, so no hand-written
externallist is needed. An import the app makes, or a package the app declares, is still
bundled or fails the build. -
Build-time tools are left out. Vite, the development server, the page scanner and the
Babel parser are not in the production bundle, and the server never loads Vite. The native
parseroxc-parseris replaced by a module that throws if it is ever called. -
Production React. A
singleBundlebuild setsprocess.env.NODE_ENVto"production"
insidereact,react-domandscheduleronly, so React's development build is dropped.
Aprocess.env.NODE_ENVentry inbuild.defineturns this off. -
Client build options.
webConnector({ build: { chunks, precompress } })controls the
client output:chunks: "split"(the default) writes a React vendor chunk, the entry, a lazy chunk per
page and shared chunks.chunks: "merged"keeps the same lazy page loading and packs small shared chunks together
by size, which gives far fewer files.chunks: "single"writes one JavaScript entry and one stylesheet, with dynamic imports
inlined. It is for single-site apps only.precompress: falseskips the.brand.gzcopies of each client asset (defaulttrue).
Final-bytes chunk names, dedupe, the integrity check, preload lists and payload budgets work
in every mode. -
Desktop and offline recipe. The desktop and offline app recipe sets both
chunksand
precompress.build.singleBundlealone does not change them. -
Dist file summary.
warlock buildprints the number of files and the total size of
dist/when it finishes.
3. Release notes in every install (core)
warlock release-notesprints the family release summaries that ship inside the package
(releases/<version>-summary.md, from 5.30.0 onward). It reads files only, so it needs no
network and no booted app.- With no arguments it prints the installed version's summary.
--from <version>(optionally with--to <version>) prints every later release, oldest
first, led by a combined list of breaking changes.--version <v>prints one release,--listlists the versions with dates, and--json
prints the same data as JSON.- A version the package does not ship is reported with its GitHub release URL.
- Pointers from upgrade and update.
warlock upgrade,warlock upgrade --checkand
warlock updateend withWhat's new: npx warlock release-notes --from <old>. TheAGENTS.md
section thatwarlock agents-mdgenerates names the installed version and the command. - Agent skills. The
update-packages,deploy-releaseandupgrade-from-5-29skills tell
agents to runnpx warlock release-notes --from <current>before upgrading.
4. Tests and tooling (core, web)
- Config files no longer walk the app graph. Loading config registered each config file
together with its whole import graph, so a config that imported an application service made
every test worker spend minutes in setup (about 480 seconds for a 3,000-module graph, measured).
Config files now register with their direct import edges only. The dev server still builds the
full graph from its own scan. onPageError(hook)(web, from@warlock.js/web/connector) registers a server
error-report hook at runtime, from a module'smain.ts. It receives the same
(error, context)asweb.errors.report, runs through the same bounded queue, and returns a
function that removes it. Use it instead of importing application code intosrc/config/web.ts.
The typesPageErrorHook,PageErrorInfoandPageErrorKindare exported.warlock doctorcheckconfig-app-importswarns when a file undersrc/configimports,
statically or withimport(), anything undersrc/app. The message names the file and the
import. Type-only imports are not reported.warlock upgrade --checknpm fix. npm 10.9 crashed on the family's lockfile with
Cannot read properties of null (reading 'edgesOut'), which skipped every later step. When the
npm on PATH is older than 11.6.2, the scratch install now runsnpx -y npm@11.6.2, and--from
is inferred from the installed@warlock.js/core.- WL9024 text.
WL9024applies to any integration spec: a*.spec.tsor*.test.tsfile
that is not*.unit.*, or any file undertests/. Its fix text now says to rename the file to
<name>.unit.spec.tsoutsidetests/. The 5.38.0 note said*.test.tsto*.spec.ts, which
was wrong.
5. Models (cascade)
- System columns in typed
get()andset(). On a model declared with a schema type, these
columns are accepted without being declared:id(number),_id,created_atand
updated_at(Date),deleted_at(Date | null), and their camelCase spellings. A column the
schema declares keeps its own type, so a renamed timestamp or a stringidbelongs in the schema. - Clearer
set()errors. A wrong value type is reported as a value mismatch, not as a
misleading error about dot paths. - Typed runtime key. A column named at runtime is set with a key typed
K extends ModelKey<Schema>. The newModelSystemColumnsandModelColumnstypes are exported.
6. Web UX (web)
- Refusal pages. For a
GETorHEADrequest that namestext/htmlinAccept, a 401 or
403 renders the site'sforbidden.page.tsx. Any other refusal renderserror.page.tsx, and
then the framework fallback page, with the refused status. In multi-site mode the site is
chosen by host, as for any page. API clients keep the JSON answer.
7. New apps (create-warlock)
- Installs on npm 10.9. A fresh scaffold no longer crashes on npm 10.9 (the npm bundled with
Node 22) withCannot read properties of null (reading 'edgesOut'). The template pins Vitest
5.0.5, because the Vitest releases before it trigger that npm bug on their own. TheedgesOut
hint stays as a last resort.
8. Upgrade notes
- Rehearse first. Run
npx warlock upgrade --check. It runs the upgrade on a scratch copy and
never writes the real project. It reports the breaking changes that affect the app and the
outcome of each step. - Update the family. Run
npx warlock update. It ends with a pointer to the release notes. - Read what changed. Run
npx warlock release-notes --from 5.38.0to print the summaries of
every release after 5.38.0, with the combined breaking-changes list first. - Review the two behaviour changes in section 1:
--versionand-vwith a command, and
browser requests refused by core on a page host. - Opt in to the standalone build (optional). Set
build: { singleBundle: true }in the app's
warlock.config.ts, then runnpx warlock build. Read the build report for the native addons,
optional integrations and React notes, and check the file count and size that the build prints.
Test the output by runningnode dist/app.jsfrom a copy ofdist/. - Choose the client chunk mode (optional). Set
webConnector({ build: { chunks, precompress } })
in the web connector to pick"split","merged"or"single"chunks, and whether to write
compressed copies. For a desktop or offline app, follow the desktop and offline recipe, which sets
both options. - Use
onPageErrorfor error reporting (optional). Ifsrc/config/web.tsimports application
code only to report errors, register the hook withonPageError(hook)frommain.tsinstead and
remove the import. Runwarlock doctorto check forconfig-app-importswarnings. - Rename integration specs (if flagged). A
WL9024warning names an integration spec that
imports nothing needing the app. Rename it to<name>.unit.spec.tsoutsidetests/. - Update typed model code (if needed). Columns that the schema does not declare are now
accepted only when they are system columns (section 5). Other columns still need a schema entry or a dot path.