Skip to content

Fix livereload default broken by Click 8.3+#4111

Open
zf-unity wants to merge 1 commit into
mkdocs:masterfrom
zf-unity:fix/click-8.3-livereload-default
Open

Fix livereload default broken by Click 8.3+#4111
zf-unity wants to merge 1 commit into
mkdocs:masterfrom
zf-unity:fix/click-8.3-livereload-default

Conversation

@zf-unity
Copy link
Copy Markdown

@zf-unity zf-unity commented May 8, 2026

Summary

mkdocs serve (with no flags) silently runs without livereload when Click ≥ 8.3 is installed. Symptoms:

  • No Watching paths for changes: log line at startup.
  • Edits to docs files do not trigger a rebuild — no Detected file changes / Building documentation....
  • Served HTML does not contain the livereload poller <script>, so the browser never refreshes.

Root cause

The serve command declares the livereload flag with two separate @click.option decorators sharing the same parameter name and using flag_value:

@click.option('--no-livereload', 'livereload', flag_value=False, help=no_reload_help)
@click.option('--livereload',    'livereload', flag_value=True, default=True, hidden=True)

Up to Click 8.2.1 this resolved the parameter's default to True. Click 8.3 (pallets/click#3084) changed the resolution rules so the first decorator wins the default, leaving livereload=False when no flag is passed. serve.py then skips the entire if livereload: block (no server.watch(), no observer, no <script> injection).

Reproduction:

import click
from click.testing import CliRunner

@click.command()
@click.option('--no-livereload', 'livereload', flag_value=False)
@click.option('--livereload',    'livereload', flag_value=True, default=True, hidden=True)
def cmd(livereload):
    print('livereload =', livereload)

CliRunner().invoke(cmd, [])
# Click 8.2.1 → livereload = True
# Click 8.3.x → livereload = False

Fix

Collapse the two flag_value options into a single boolean option:

@click.option('--livereload/--no-livereload', 'livereload', default=True, help=no_reload_help)

This is the canonical Click way to express a "yes/no" boolean flag and is robust to the 8.3 resolution change. Both --livereload and --no-livereload continue to work; the help text remains attached to the visible secondary form.

Fixes #4032
Fixes #4055

Test plan

  • mkdocs serve (no flags) shows Watching paths for changes: 'docs', 'mkdocs.yml' on startup.
  • Editing a docs file emits FileModifiedEventDetected file changesBuilding documentation....
  • Served HTML contains the livereload(epoch, request_id) <script>.
  • mkdocs serve --no-livereload continues to disable the watcher and skip script injection.
  • mkdocs serve --livereload (explicit) behaves the same as the new default.
  • mkdocs serve --help documents --livereload / --no-livereload with the existing help string.
  • Verified end-to-end on Click 8.3.3, MkDocs installed from this branch, mkdocs-ivory theme.

Click 8.3 changed how `default=` is resolved when the same parameter is
declared with two `flag_value` options. The previous form left the
effective default as `False`, so `mkdocs serve` (no flags) silently ran
without livereload — no `server.watch()` calls, no rebuild on edit, and
no script injection into served HTML.

Replace the dual-decorator pair with a single `--livereload/--no-livereload`
boolean option carrying `default=True`. Both flag names continue to work
and the help text is preserved on the visible `--no-livereload` form.

Fixes mkdocs#4032
Fixes mkdocs#4055
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Live reload does not trigger automatically unless '--livereload' is explicitly passed mkdocs does not watch for file changes when using click>8.2.1

1 participant