0.59.0 (2024-01-26)


0.58.0 (2024-01-13)


A new function reblocks/response:status-code was added as a replacement to reblocks/response:get-code. The new function is setfable. Now you can change HTTP status code of the currently rendered page. This is especially helpful when rendering \"Not found\" or error pages.

0.57.0 (2024-01-08)


0.56.0 (2024-01-01)


0.55.0 (2023-12-05)


0.54.0 (2023-10-22)


Function reblocks/request:get-remote-ip was added.


Now function reblocks/actions:make-action-url removed old action argument if it is present in the current URL. This fixes the case when you want to make an action url from the callback processing another action.

JavaScript function initiateFormAction now does not overwrites whole options.args object, but only replaces the keys corresponding to a form data fields.

0.53.0 (2023-06-20)


Now all commands added using reblocks/response:send-script or reblocks/commands:add-command during the call to reblocks/widget:update generic-function, are added after the command for updating DOM node on the frontend. This fixes a problem happened when you attach some JS handlers to the DOM node, but after the update these handlers are deleted.

0.52.0 (2023-06-08)


0.51.0 (2023-05-27)



0.50.0 (2022-12-03)


Fixed a bug when session lock was written into the session itself instead of into the inner hash table.

Fixed error handling when debug-mode is off. Previously, the debugger was invoked before showing 500 error page to the user.

Now every response has \"Cache-Control: no-cache, no-store, must-revalidate\" header to prevent caching of dynamic content in the browser. This fixes the issue when you did some changes using actions then went to another page and returned using \"Back\" button in the browser. Previously browser was able to show you an old content of the page.


Current page abstraction

Added a notion of the current page. Now all actions are bound to some page and pages can expire, clearing actions from the memory. This should prevent memory leak leading to posible DoS attack. Page expiration is controlled by two values:

Also, you can use reblocks/page:extend-expiration-time function to extend current page's expiration time.

When all pages in the session are expired, session is removed from the memory too.

Generic-function reblocks/page:on-page-refresh was added.

Cached widget dependencies

Another interesting feature is mixin class reblocks/cached-dependencies-mixin:cached-dependencies-mixin.


These functions were moved to separate package REBLOCKS/PAGE-DEPENDENCIES:

New generic-function reblocks/session:init-session was introduced. Define a method if you need to add something into the user's session when it is initialized. This function will be called once per user.

Generic function REBLOCKS/SESSION:INIT was replaced with reblocks/page:init-page and it will be called each time a user opens site in a new browser window or tab. When user refreshes the page it will not be called.

Function reblocks/debug:reset-latest-session now provides a convenient restart to enable debug mode.


Function reblocks/widgets/root:get was deleted. Use (page-root-widget (current-page)) instead. Also root-widget-key and corresponding package reblocks/widgets/root were removed.

0.49.0 (2022-11-26)

New functional was added which allows to control how does HTTP middlewares list is generated for the server. You might define your own reblocks/server:server class and a method for reblocks/server:make-middlewares generic-function. Inside this method, you might inject additional middlewares using reblocks/server:insert-middleware function.

Also, a variable reblocks/server:*default-samesite-policy* was introdiced, to control default value of the SameSite HTTP header.

As a bonus, loading of reblocks-docs system was fixed.

0.48.0 (2022-11-07)


Now Reblocks remembers which dependencies are already loaded into the page and will not fetch them again. This fixes issue when it fetched jQuery and broke it's extensions making further action calls made via GET instead of Ajax.

0.47.0 (2022-11-04)


Added ability to set cookie in response handler. You can do it in any render method.

Here is an example how to expire a cookie right now:

     (list :name "auth_token"
           :value ""
           :path "/"
           :expires (get-universal-time)
           :secure t
           :samesite :lax))

0.46.1 (2022-09-16)


0.46.0 (2022-07-03)



0.45.3 (2022-06-25)


0.45.2 (2022-06-06)


0.45.1 (2022-06-02)



0.45.0 (2022-02-14)


0.44.0 (2022-02-09)



0.43.0 (2022-02-07)


0.42.0 (2022-02-06)



0.41.0 (2022-01-05)


0.40.0 (2022-01-03)


New Functions


Also removed:

Other changes

If local dependency can't be found relative to the given ASDF system, we try to search the same path relative to the current directory and throw error if file can't be found. This could happen if you've compiled the webserver into a binary and moved it to another container or machine.

reblocks/server:start function now accepts SAMESITE-POLICY argument which should be one of keywords: :LAX, :STRICT or :NONE. This parameter modifies SameSite part of the cookies sent to the client.

Hooks API was refactored in a backward incompatible manner. reblocks/hooks:defhook macro now requires to specify hook's arguments and all macros generated by the reblocks/hooks:defhook also require arguments specification.

jQuery was upgraded from 1.8.2 to 3.6.0. It's plugins and jquery-seq.js were turned off.

0.39.1 (2020-01-20)


Now Woo does not parses numeric headers and Weblocks has to do it itself.

0.39.0 (2019-09-16)


It defines a handler for a given route. By default route should return a serialized JSON:

(defroute (app /api/data)
    "{\"my-data\": [1, 2, 3]}")

but you can redefine the content type:

(defroute (app /api/data :content-type "application/xml")

each route is associate with application class and these routes are added to the mapper when you call a start method.

0.38.1 (2019-08-02)

0.38.0 (2019-07-07)

All of them are fixed now.

0.37.0 (2019-06-01)

0.36.0 (2019-05-03)

0.35.3 (2019-03-31)

For example, calling:

(add-retpath-to "/login" :retpath

  Will return:


Argument :retpath is optional. By default, function will take an URL of the current web page.

0.35.2 (2019-03-21)

0.35.1 (2019-02-02)

This was fixed now.

0.35.0 (2019-01-22)

Request handling pipeline was refactored.

The idea of this refactoring, is to separate roles of the functions which process requests. Now weblocks/server:handle-http-request prepares data received from the Clack and calls weblocks/request-handler:handle-request to do the real job.

In it's turn, weblocks/request-handler:handle-request should return an object of type weblocks/response:response containing a content, HTTP status code and headers of the response. Any error signal, thrown from the handle-request is considered by handle-http-request as an "unhandled error" and returned with 500 HTTP status code.

Here is a list of changes:

0.34.0 (2019-01-19)




0.33.2 (2018-12-06)


0.33.1 (2018-11-24)




For example:

  connect-to-database ()

  (let ((success nil))
    (unwind-protect (progn (setup-transaction)
                           (setf success t))
      (if success

Before this fix, rollback always called, because execution never hitted (setf success t). Now this is fixed.

0.33.0 (2018-11-22)


Use weblocks/response:make-uri instead.


0.32.1 (2018-08-13)



The error was raised during code loading:

;;; > Error: There is no applicable method for the generic function: > #<STANDARD-GENERIC-FUNCTION WEBLOCKS/JS/BASE:MAKE-JS-BACKEND #x3020027E292F> > when called with arguments: > (:JQUERY)

Now it is fixed and package weblocks/js/jquery is a dependency of weblocks/server and always loads.

0.32.0 (2018-06-26)

0.31.1 (2018-06-16)

0.31.0 (2018-05-29)

0.30.1 (2018-05-20)

However, it does not work with Woo server, because C library libev crashes with error:

Assertion failed: (("libev: a signal must not be attached to two different loops", !signals [w->signum - 1].loop || signals [w->signum - 1].loop == loop)), function ev_signal_start, file ev.c, line 4082

0.30.0 (2018-05-19)

0.29.0 (2018-05-05)

Backward incompatibilities

Class weblocks/dependencies:dependency now requires that type attribute shoulde be of type (member :css :js :png :jpg :gif)

Also, functions make-local-js-dependency, make-local-css-dependency, make-local-image-dependency, make-remote-js-dependency and make-remote-css-dependency were removed from package weblocks/dependencies. Use make-dependency function, it will figure out which dependency type to create itself.


A new function weblocks/debug:get-session-value was added. It can be used to get values from the last session seen by weblocks.

0.28.0 (2018-04-23)

Error handling was fixed. Previously it aborted Woo's worker thread and break the server.

Variable weblocks/variables::*catch-errors-p* was renamed to weblocks/variables::*invoke-debugger-on-error* and it's value was inverted. If this variable is True, then debugger will be invoked. Otherwise - Weblocks will return 500 error page.

Argument :invoke-debugger-on-errors of weblocks/debug:on function was renamed to :invoke-debugger-on-error.

Method weblocks/error-handler:on-error now is called when you abort request processing from the debugger. It is called with current app as the first argument and the nil instead of condition.

0.27.2 (2018-04-09)

Fixed a typo in string-widget and funcall-widget package definitions.

0.27.1 (2018-04-09)

Now string-widget and funcall-widget depends on weblocks/widgets/base instead of weblocks/widget.

0.27.0 (2018-03-11)

Reloading of the defapp definition now does not tries to restart an application. Previously, restart caused the problem – when there is only one application, whole Weblocks server was shut down. So, I've removed this implicit action.

Code which logs action result on the client-side was improved.

0.26.0 (2018-02-20)

Symbols add-application-hook, add-request-hook, add-session-hook, prepare-hooks and call-hook aren't exported from weblocks/hooks anymore. Use new macro defhook instead.

Here is how it works:

You use defhook as the toplevel form of your file if you want to define a new hook. This macro will create few other macroses in weblocks/hooks package and will export them. For example:

(defhook database-opened
   "This hook is called when your application opens a database.")

This code will add these macroses into the weblocks/hooks package: on-session-hook-database-opened, on-request-hook-database-opened, on-application-hook-database-opened, with-database-opened-hook and call-database-opened-hook.

You need to wrap code, which opens a database, with with-database-opened-hook:

(weblocks/hooks:with-database-opened-hook ()

And in any other piece of code, you can define callbacks, using one of other three macroses:

    log-database-opening ()

  (log:info "Database was opened"))

Usage of defhook macro gives more transparency to all defined hooks, because all of them now visible as external symbols in weblocks/hooks package.

0.25.2 (2018-02-04)

System weblocks/hooks now depends on log4cl and metatilities, because previously sometimes it was impossible to load weblocks.

0.25.1 (2018-02-04)

Old tests for widgets, removed from core framework were removed.

Tests for widget's MOP methods were ported to Rove.

Package weblocks/utils/close now loaded with main :weblocks system.

Few old widget tests were removed.

Added function weblocks/session:reset which resets current session.

0.25.0 (2018-01-31)

Good news, everyone!

Quickstart tutorial was fixed!

Function render-widget was replaced with weblocks/widget:render :around method. Method implementation were moved to weblocks/widgets/render-methods.

Funcall-widget's package was refactored to conform package inferred requirements.

Actions processing

Function make-js-action was moved to weblocks/actions package.

Application and server restarting

Package weblocks/app now exports functions stop and restart. Previously they were internal and were called like stop-webapp and restart-webapp.

Package weblocks/server does not export start-weblocks and stop-weblocks functions. They were replaced with just start and stop. Also, it's internal generics start and stop were renamed and transformed to start-server and stop-server functions.

Session initialization changes

File default-application.lisp was removed, because now every application has default session initialization method.

File default-init.lisp was refactored. Now it provides default method for weblocks/session:init generic and :around method for same generic, which allows end user just to return a string or a function from his init method.

Now user can return any string or function from his method weblocks/session:init and it will be passed to a new generic weblocks/widget:create-widget-from to create a root widget. You can also define create-widget-from for you custom types.


Function weblocks/debug:on now turns on mode when Weblocks does not intercept unhandled conditions, but calls an interactive debugger.


0.24.0 (2018-01-29)

All rendering code was refactored.

Macroses with-html and with-html-to-string replaced with weblocks.html:with-html and weblocks.html:with-html-string. Stream *weblocks-output-stream* was moved to weblocks.html::*stream* and is not external anymore. Please, don't use it directly.

Widget refactorings

Procedure update-widget-tree was removed and not widgets can't change html header's tags, description, title, etc. If you need this, change them in the render method.

Macro root-widget was removed and replaced with function weblocks.widgets.root:get.

Request level

Functions post-action-redirect, post-render-redirect and initial-request-p were removed from weblocks package.

Function pure-request-p was moved to weblocks.request package.

Variable *json-content-type* was removed.

Variable *latest-request* was moved to weblocks.debug:*latest-request*.

Functions parse-location-hash, ajax-request-p were moved to weblocks.request package.

Function redirect was moved to weblocks.response:redirect. Functionality, related to opening another window instead of redirection or deferring redirection until the end of action or rendering was removed.

Request handler

Functions remove-duplicate-dirty-widgets, update-location-hash-dependents and update-widget-tree were removed.

Call to weblocks::update-dialog-on-request from handle-client-request was commented.

Error handler

Generic method weblocks/error-handler:on-error now accepts two arguments - application object and condition.

Application level

All code from uri-parameters-slotmap.lisp was removed.

All code, related to application class, was moved to the package Base aplication class was renamed to, and macro for definition of the new application was renamed to

All code related to application's metaclass, was moved to the package Metaclass was renamed to

Application's slot html-indent-p and corresponding accessor weblocks-webapp-html-indent-p were removed because now spinneret generates non indented code.

Slot init-user-session was completely removed and replace with a generic weblocks.session:init.

These dependency related slots and accessors were removed:

And macro for defining a special readers for them was removed as well: def-debug-p-slot-readers.

Also, these arguments to defapp was removed: :ignore-default-dependencies, :dependencies

Function update-thread-status and method webapp-update-thread-status were removed.

Function get-webapps-for-class was renamed to app-active-p and now returns t if application of given class is already active.

Function start-webapp was renamed to

Function get-webapp was renamed to get-active-app and optional argument error-p was renamed to keyword argument signal-error.

Function find-app was removed.

Function in-webapp was moved to weblocks.debug:in-app.

Variable *default-webapp* was removed.

Variable *active-webapps* was renamed to*active-apps* and made internal. Use function.

Reader weblocks-webapp-prefix was renamed to

Slot default-store-name and its accessor webapp-default-store-name were removed.

Variable *current-webapp* was moved to weblocks.variables::*current-app*.

Functions compute-webapp-public-files-uri-prefix, compute-webapp-public-files-uri-prefix, compute-webapp-public-files-path, make-webapp-public-file-uri, weblocks-webapp-public-files-cache-time and variable *default-public-files-path* were removed because now there is another way to serve static.

Function webapp-serves-hostname was renamed to and now accepts app as the first argument and hostname as the second.

Variable *uri-tokens* was removed and weblocks does not set 'last-request-uri session value to all uri tokens anymore.

Macro with-webapp was moved to

Function webapp-permanent-action was moved to

Function add-webapp-permanent-action was moved to and remove-webapp-permanent-action to

Macroses define-permanent-action and define-permanent-action/cc were moved to and

Function make-webapp-uri was removed, use weblocks/response:make-uri instedad.

Accessor webapp-js-backend was renamed to get-js-backend

These functions were moved into the separate package weblocks.current-app and renamed:

Actions and commands

Function weblocks.actions:add-command was moved to weblocks.commands.

Function weblocks:get-request-action was moved to weblocks/actions:get-request-action

Keyword argment :action was removed from action calls.


Package weblocks.js was renamed to weblocks/js/base.

Functions escape-script-tags, %js and macroses with-javascript, with-javascript-to-string were moved to the package weblocks/js/base.


These variables were moved from weblocks package to weblocks/variables:

Symbols moved from :weblocks to other packages

To :weblocks/widgets/dom

To :weblocks/utils/uri

To :weblocks/linguistic/grammar

To weblocks/utils/warn

To weblocks/actions


To make Weblocks core smaller, many files were removed: views, widgets, html-parts, utilities.

Systems weblocks-util, weblocks-testutils were removed.

Accessor dom-class and generic function dom-classes were removed and replaced with generic function weblocks/widget:get-css-classes.

Generic function weblocks:handle-error-condition was removed.

Variable *dirty-widgets* was removed along with render-dirty-widgets function.


Rendering of remote (non cached) dependencies was fixed.

0.23.0 (2018-01-11)

0.22.2 (2018-01-07)

0.22.1 (2018-01-07)

0.22.0 (2018-01-06)

Most functions from weblocks.request were refactored and renamed:

All these function now accept keyword argument :request. Previously it was &optional.

Another change is a new function weblocks.response:make-uri. It can be used to build new uri, based on the uri of the current request. This can be useful when embedding links into emails, for example.

Warning! These changes require a newer version of Lack.

I've made a pull request it is not merged yet, so, alternative version of Lack can be used, by installing it using Qlot, from here:

0.21.0 (2018-01-01)

0.20.1 (2017-12-20)

0.20.0 (2017-12-15)

   (asdf:system-relative-pathname :app "favicon.png"))

0.19.2 (2017-11-29)

0.19.1 (2017-11-23)

0.19.0 (2017-11-13)

0.18.0 (2017-11-12)

Warning! Probably parent/children handling code will be removed soon.

0.17.2 (2017-11-11)

0.17.1 (2017-11-11)

0.17.0 (2017-11-11)

0.16.0 (2017-11-04)

Undefined function WEBLOCKS:WEBAPP-SESSION-KEY called with arguments (#<APP::APP #x3020052F01DD>)

Now Content-Type is text/plain.

0.15.0 (2017-11-03)

lisp (assert-hooks-called (:fact-created contact "") (:fact-removed contact ""))

Also, a new macro catch-hooks was added to check if some hooks were called during a unittest. * Now weblocks does not open a new tab or window on 500 error during an action execution.

0.14.4 (2017-10-07)

0.14.3 (2017-09-23)

0.14.2 (2017-09-22)

0.14.1 (2017-09-22)

0.14.0 (2017-09-20)

0.13.11 (2017-09-12)

0.13.10 (2017-09-06)

Called when weblocks.request:*request* and weblocks.session:*session* are already bound.

0.13.10 (2017-09-06)

Called when weblocks.request:*request* and weblocks.session:*session* are already bound.

0.13.9 (2017-09-02)

0.13.8 (2017-09-02)

0.13.7 (2017-04-15)