Skip to content

Release v2.4.0

Latest

Choose a tag to compare

@digreatbrian digreatbrian released this 27 Oct 19:56

Here is what changed?

Checkout the changelog at: https://github.com/duckframework/duck/blob/main/CHANGELOG.md#240---october-27-2026

[2.4.0] - October 27, 2026

Added

  • Added method set_webmanifest to the Page component.
  • Added duck native command for management of native apps.
  • Added ensure_browser_state_synced to Lively WebSocket to easily and securely sync cookies, etc with the browser.
  • Added support for excluding extensions e.g., Button(exclude_extensions=[HighlightExtension])
  • Added new HTML component extensions at duck.html.components.extensions.clickable. Extensions include RippleExtension and HighlightExtension.
  • Added LinkButton component to duck.html.components.link.
  • Added IconButton component to duck.html.components.icon.
  • Added register_default_extension to duck.html.components.extensions module, you can now register an extension globally by component class.
  • read_chunked(), write_chunked() and their async counterparts async_read_chunked(), async_write_chunked() helpers.
  • First stage towards Duck Native.
  • File duck.toml now supports packages with versions.
  • Added argument failsafe to duck.utils.email.collection.collect_email. This logs the exception but doesn't really raise it.
  • Added Spacemail provider to duck.utils.email module for easy sending of emails through spacemail.
  • Added duck.html.html_minify module and enabled html minify by default for HTML components that accept inner HTML.
  • Added HTML components text property support newline character \n, this will be rendered as <b> element as HTML.
  • Select component's options prop now accepts a tuple/list of values (in addition to the existing mapping form), rendering each as an <option> with matching value/label.
  • FileIOStream.etag and FileIOStream.last_modified — derived from st_size/st_mtime_ns via a single os.stat() call, letting HTTP responses expose stable cache validators without reading file content.
  • Conditional request handling (If-None-Match, If-Modified-Since) with automatic 304 Not Modified downgrading for cacheable GET/HEAD responses, using the new FileIOStream validators.
  • If-Range support for byte-range (Range) requests — a range is only honored when it matches the resource's current strong ETag (or Last-Modified as fallback); otherwise the full resource is served, preventing corrupted partial downloads against a changed file.

Changed

Component JS, CSS, and HTML minification is now enabled by default only in production mode. Configure COMPONENTS_MINIFY_JS, COMPONENTS_MINIFY_CSS, and COMPONENTS_MINIFY_HTML in your settings file to control minification. To force minification in debug mode, use the COMPONENTS_FORCE_ prefix, e.g., COMPONENTS_FORCE_MINIFY_JS.

  • All page components automatically refresh when they expire or are no longer registered, ensuring pages always serve fresh, up-to-date content.
  • All clickable components are now automatically extended with the HighlightExtension.
  • Refactored the Code component to CodeBlock and added support for filename and collapsible arguments.
  • Changed HTML components add_to_registry to be not strict about request for ownership assignment. If not provided, the error will lazily be flagged on Lively event dispatch.
  • Improved Footer component positioning for mobile responsiveness and improved the whole footer UI logic.
  • Changed FileIOStream to use os.stat(...).mtime_ns instead of os.stat(...).mtime for caching modification timestamp.

Fixed

  • Fixed infinite session expired states upon components/page auto recovery.
  • Fixed issues scrolling to element for Lively navigation of URLs with hashes.
  • FileIOStream.read() / AsyncFileIOStream.read() now honor the requested size. Reads larger than chunk_size are collected chunk by chunk until size bytes or EOF. Previously they returned at most one chunk, and that short result was cached under the full-size key.
  • FileIOStream.write() / AsyncFileIOStream.write() now write in chunk_size pieces until all data is written. The cache is patched and on_write hooks fire with the bytes actually written, so a short write can no longer leave the cache holding data that never reached the file.
  • A write that fails after some chunks were written now returns the partial byte count, so stream position and cache stay accurate. A failure on the first chunk still raises OSError.
  • Negative size values now read the whole file, matching Python's file API. Previously only -1 did.
  • Fixed MCPView's run() bug.
  • Fixed BasicExtension linebreak replace bug in property inner_html setter.
  • Fixed StreamingRangeHttpResponse not correctly parsing range header - leading to slightly wrong data.