Upgrade from 1.0 to 1.1
1.1 is a minor release: code written for 1.0 still works and new features (component tags, events, models, snippets, refs, <script server>, data composables, generic components…) are optional. Still, some changes are noticeable when upgrading. This guide collects them and what you should review for each. The complete list of additions and fixes is in the CHANGELOG; compatibility commitments are in the stability policy.
Recommended order#
- Update
@meekojs/meekoto exact version1.1.0and recompile or rebuild: generated code and runtime must have the same version. If you use the VS Code extension or Meeko DevTools, update them too. - Run
meeko check. The most likely new errors are extra component props (see Stricter component props) and reserved template names. - Review top-level setup code in pages and layouts with data or dynamic components (see Navigation's preliminary render).
- Replace the
useSocketimport from@meekojs/meeko/frameworkwithuseSocketClient. If you have a custom WebSocket client or Socket adapter, review the new handshake closes (see Socket:4401and4403handshake closes). - If a tool reads CLI or
meeko checkoutput, make it use codes rather than message text.
Type checking#
Stricter component props#
meeko check and the editor check each tag's props (<Etiqueta> or <component is>) only against those declared by the child:
- An unknown prop is an error even alongside valid ones on the same tag. In
1.0it passed checking and was ignored at runtime. bind:variant="'secondary'"retains its literal type against a union ("primary" | "secondary") instead of widening tostring.- A missing required prop is flagged on the tag with
TS2345instead ofTS2769.
An extra prop did not fail at runtime, so this change is an approved exception to stability policy. To fix it, remove the prop or declare it in the child's defineProps:
<!-- Before: "size" is not in Card's props and 1.0 accepted it -->
<component is="Card" bind:title="title" bind:size="'lg'"></component>
<!-- After -->
<component is="Card" bind:title="title"></component>If a tool filtered diagnostics by TS2769, add TS2345.
meeko check checks imported .ts files with their auto-imports#
The .ts files imported by a .meeko are checked with their scope's auto-imports and generated routes, as in .meeko/'s tsconfig.* projects. You may see new errors already shown by the editor, such as href("/ruta-inexistente"). False TS2304 errors for auto-imported composables, stores or utilities in those files disappear.
ErrorSource includes "mounted"#
Failures in an onMounted callback and a setup's browser continuation after await reach provideErrorHandler and the application's onError with source "mounted". An exhaustive switch on ErrorSource without a default branch stops compiling: add a "mounted" branch or a default.
Template#
ref, model and html are directives#
ref:nombreis a directive.ref="x"andbind:refbehave as in1.0.- On a custom element (a hyphenated tag, such as
<x-markdown html="intro">or<my-input model="query">),htmlandmodelremain literal HTML attributes, as in1.0: no changes needed. The following applies to standard HTML elements, wherehtmlandmodelare not valid attributes. model="..."on an element no longer writes themodelHTML attribute: it binds a signal to a form control (see Form controls withmodel). On an unsupported element, it producesMEEK065.html="..."on an element no longer writes thehtmlHTML attribute: it inserts the value as unescaped HTML (see Unescaped HTML withhtml). On an unsupported element, it producesMEEK095.
If you need the literal attribute, write it with bind:model or bind:html, which still write the attribute:
<!-- Before: atributo HTML model="draft" -->
<div model="draft"></div>
<!-- After -->
<div bind:model="'draft'"></div>On a component tag, is, ref and html are not static props (MEEK032).
Retired diagnostics#
MEEK005 (missing <script lang="ts">), MEEK023 (missing each:key) and MEEK049 (content inside a component tag) are no longer emitted because that code is now valid. A tool expecting them will no longer receive them.
Lifecycle and navigation#
Navigation's preliminary render#
Before committing navigation, the browser renders the new page without displaying it to load its awaited data, with useNavigation().pending as true. This is a dry run: it runs neither effect, onMounted nor the browser continuation, and useSocket does not connect.
What does run again is the page's and new layouts' top-level setup code, with provisional state that is discarded. Thus, in pages whose tree contains awaited data or a runtime-selected component (<component is> with a variable, an each: item or snippet parameter), that code runs twice per navigation. If the tree cannot await data, the pass is skipped and setup runs only once, as in 1.0.
Review top-level setup in those pages and layouts: an api.* request, external store write or counter increment there repeats. Move them to onMounted, a handler or an effect:
<script lang="ts">
// Before: also runs in the render before each navigation
void api.analytics.post({ body: { page: "users" } });
// After: only in the browser, once the page is mounted
onMounted(() => {
void api.analytics.post({ body: { page: "users" } });
});
</script>See Navigation and render: "client".
onMounted ordering#
onMounted is new in 1.1. When replacing an effect or queueMicrotask waiting for the DOM, consider its order: callbacks run at the end of the current hydration or mount operation, when later siblings and parent bindings already exist, and children run theirs before the parent. It never runs in SSR or navigation's preliminary render. See Lifecycle.
Navigation error pages and the Error title#
- A client navigation whose data request responds with
404(throughnotFound()or a loader404ApiError) displays the nearest+error.meeko, orapp/error.meeko, with{ status: 404, message }, like the SSR document. In1.0, navigation failed with an error. - Error pages use the
Errortitle in SSR and navigation, includingapp/error.meeko's404for a URL without a route. Update tests expecting anotherdocument.titleon those pages. - When navigating to a page without
title,document.titlereturns to the host title or no title, like SSR; previously it retained the previous page's title. - A new navigation starts at the top or its fragment's element; previously it retained the previous page's scroll position. A link to a fragment of the current page no longer rerenders it.
Layer and module pages inside the project shell#
app/app.meeko and the project's root layout now wrap extends and modules pages, with the layer's +layout.meeko nested inside. If the project has app.meeko or a root layout, they replace the layer's. Previously those pages rendered alone in #app. Review layer pages' appearance if your root layout assumed it did not wrap them.
Framework and CLI#
useSocket from @meekojs/meeko/framework becomes useSocketClient#
useSocket(url, contract, options) from @meekojs/meeko/framework is deprecated and will be removed in 2.0. It is the same function as useSocketClient, with the same signature and types, so simply change the import:
// Before
import { useSocket } from "@meekojs/meeko/framework";
const chat = useSocket("wss://example.com/_meeko/socket/chat", chatContract);
// After
import { useSocketClient } from "@meekojs/meeko/framework";
const chat = useSocketClient("wss://example.com/_meeko/socket/chat", chatContract);The editor strikes through alias uses. Generated clients' useSocket("canal", opciones) auto-import is unchanged and not deprecated.
Socket: 4401 and 4403 handshake closes#
In 1.0, a Socket handshake without a session on an auth: "required" channel received HTTP 401, and one rejected by authorize received 403, without upgrading. The browser's WebSocket does not expose that status, so the client saw it as a network failure and retried endlessly. Since 1.1, Node, Bun, Deno and Cloudflare adapters complete the upgrade and immediately close with 4401 (“Autenticación requerida”) or 4403 (“Acceso denegado”), without calling handlers or delivering messages. The Meeko client then enters terminal "unauthorized" state. A hub reauthorizing an accepted connection, such as a room's Durable Object on wake, also closes with 4401 or 4403, no longer 1008 (“Unauthorized”).
Other rejections are unchanged: disallowed Origin (403 INVALID_ORIGIN), nonexistent channel (404), invalid name or request (400) and limits still respond over HTTP.
What to review:
- Custom WebSocket client (another library, a native app or tests expecting
401/403during handshake, for example throughws'sunexpected-responseevent): the handshake now opens and closes immediately. Treat4401and4403closes as final rejection and do not retry. - Custom adapter over
createSocketUpgradeHandler: still works unchanged, responding with HTTPstatus, like1.0. To provide new behavior, handle therejectaction'sclosefield: upgrade and close withclose.codeandclose.reasonwithout callingopen.
const upgrade = await handleUpgrade(request);
if (upgrade.action === "pass") return app.fetch(request);
if (upgrade.action === "reject" && !upgrade.close) return new Response(null, { status: upgrade.status });
const { socket, response } = Deno.upgradeWebSocket(request);
socket.onopen = () => {
// Deno drops the connection without a close frame if it reads a message while closing: close after one tick.
if (upgrade.action === "reject") { setTimeout(() => socket.close(upgrade.close?.code, upgrade.close?.reason), 0); return; }
const session = upgrade.open({ send: (message) => socket.send(message), close: (code, reason) => socket.close(code, reason) });
socket.onmessage = (event) => session.receive(event.data);
socket.onclose = () => session.closed();
};
return response;createNodeSocketUpgradeHandlerwith customreject: those two rejections no longer reachreject, butupgradefollowed by closing. Disallowed Origin and other rejections still reachreject.
Spanish messages#
CLI text (help, success, errors and meeko clean output), Meeko diagnostics from the compiler, meeko check and framework, and the language server's own hovers, logs and diagnostics are in Spanish. Codes (MEEK0xx, MEEK1xx, MEEK_*) do not change. A tool reading output must use the code rather than text, which is not part of the contract.
An unknown CLI command or option now identifies the problem (Comando desconocido: …, Opción desconocida para dev: --port) before usage, still printed to stderr with exit code 1.
meeko dev registers new files without restarting#
Creating or deleting pages, layouts, app/app.meeko, app/error.meeko, middleware or server/api, server/rpc and server/socket modules rediscovers routes and recreates the application. Recreation closes Socket connections and calls server/runtime.ts again, so in-memory store sessions are lost.
Build outputs#
meeko buildno longer copiespublic/to the server output root (.meeko/output/node/, Bun and Deno), where nothing served it: it exists only inclient/. If a deployment script read those files from the root, read them fromclient/.- SSR and prerendered documents include CSS for every component they render in
<head>, not only the page and layouts.