Repository: mkdocs/mkdocs

Issue:
--no-livereload not usable in 1.5
Hello,

the option `--no-livereload` on `mkdocs serve` is no longer usable since version 1.5.
The livereload function is still active.

Discussion:

Patch:
diff --git a/mkdocs/__main__.py b/mkdocs/__main__.py
index bf589b75..77618fb2 100644
--- a/mkdocs/__main__.py
+++ b/mkdocs/__main__.py
@@ -251,8 +251,8 @@ def cli():
 
 @cli.command(name="serve")
 @click.option('-a', '--dev-addr', help=dev_addr_help, metavar='<IP:PORT>')
-@click.option('--livereload', 'livereload', flag_value='livereload', default=True, hidden=True)
-@click.option('--no-livereload', 'livereload', flag_value='no-livereload', help=no_reload_help)
+@click.option('--no-livereload', 'livereload', flag_value=False, help=no_reload_help)
+@click.option('--livereload', 'livereload', flag_value=True, default=True, hidden=True)
 @click.option('--dirtyreload', 'build_type', flag_value='dirty', hidden=True)
 @click.option('--dirty', 'build_type', flag_value='dirty', help=serve_dirty_help)
 @click.option('-c', '--clean', 'build_type', flag_value='clean', help=serve_clean_help)
diff --git a/mkdocs/commands/serve.py b/mkdocs/commands/serve.py
index 1797e815..c5ae98bf 100644
--- a/mkdocs/commands/serve.py
+++ b/mkdocs/commands/serve.py
@@ -1,6 +1,5 @@
 from __future__ import annotations
 
-import functools
 import logging
 import shutil
 import tempfile
@@ -22,17 +21,13 @@ log = logging.getLogger(__name__)
 
 
 def serve(
-    config_file=None,
-    dev_addr=None,
-    strict=None,
-    theme=None,
-    theme_dir=None,
-    livereload='livereload',
-    build_type=None,
-    watch_theme=False,
-    watch=[],
+    config_file: str | None = None,
+    livereload: bool = True,
+    build_type: str | None = None,
+    watch_theme: bool = False,
+    watch: list[str] = [],
     **kwargs,
-):
+) -> None:
     """
     Start the MkDocs development server
 
@@ -48,16 +43,15 @@ def serve(
     def mount_path(config: MkDocsConfig):
         return urlsplit(config.site_url or '/').path
 
-    get_config = functools.partial(
-        load_config,
-        config_file=config_file,
-        dev_addr=dev_addr,
-        strict=strict,
-        theme=theme,
-        theme_dir=theme_dir,
-        site_dir=site_dir,
-        **kwargs,
-    )
+    def get_config():
+        config = load_config(
+            config_file=config_file,
+            site_dir=site_dir,
+            **kwargs,
+        )
+        config.watch.extend(watch)
+        config.site_url = f'http://{config.dev_addr}{mount_path(config)}'
+        return config
 
     is_clean = build_type == 'clean'
     is_dirty = build_type == 'dirty'
@@ -70,12 +64,6 @@ def serve(
         if config is None:
             config = get_config()
 
-        # combine CLI watch arguments with config file values
-        config.watch.extend(watch)
-
-        # Override a few config settings after validation
-        config.site_url = f'http://{config.dev_addr}{mount_path(config)}'
-
         build(config, live_server=None if is_clean else server, dirty=is_dirty)
 
     host, port = config.dev_addr
diff --git a/mkdocs/livereload/__init__.py b/mkdocs/livereload/__init__.py
index 53837ed0..0bd544b1 100644
--- a/mkdocs/livereload/__init__.py
+++ b/mkdocs/livereload/__init__.py
@@ -155,10 +155,11 @@ class LiveReloadServer(socketserver.ThreadingMixIn, wsgiref.simple_server.WSGISe
         self.server_bind()
         self.server_activate()
 
-        self.observer.start()
+        if self._watched_paths:
+            self.observer.start()
 
-        paths_str = ", ".join(f"'{_try_relativize_path(path)}'" for path in self._watched_paths)
-        log.info(f"Watching paths for changes: {paths_str}")
+            paths_str = ", ".join(f"'{_try_relativize_path(path)}'" for path in self._watched_paths)
+            log.info(f"Watching paths for changes: {paths_str}")
 
         log.info(f"Serving on {self.url}")
         self.serve_thread.start()


Test patch:
diff --git a/mkdocs/tests/cli_tests.py b/mkdocs/tests/cli_tests.py
index ae60991a..6ce03db1 100644
--- a/mkdocs/tests/cli_tests.py
+++ b/mkdocs/tests/cli_tests.py
@@ -21,7 +21,7 @@ class CLITests(unittest.TestCase):
         self.assertEqual(result.exit_code, 0)
         mock_serve.assert_called_once_with(
             dev_addr=None,
-            livereload='livereload',
+            livereload=True,
             build_type=None,
             config_file=None,
             strict=None,
@@ -53,7 +53,7 @@ class CLITests(unittest.TestCase):
         self.assertEqual(result.exit_code, 0)
         mock_serve.assert_called_once_with(
             dev_addr='0.0.0.0:80',
-            livereload='livereload',
+            livereload=True,
             build_type=None,
             config_file=None,
             strict=None,
@@ -70,7 +70,7 @@ class CLITests(unittest.TestCase):
         self.assertEqual(result.exit_code, 0)
         mock_serve.assert_called_once_with(
             dev_addr=None,
-            livereload='livereload',
+            livereload=True,
             build_type=None,
             config_file=None,
             strict=True,
@@ -89,7 +89,7 @@ class CLITests(unittest.TestCase):
         self.assertEqual(result.exit_code, 0)
         mock_serve.assert_called_once_with(
             dev_addr=None,
-            livereload='livereload',
+            livereload=True,
             build_type=None,
             config_file=None,
             strict=None,
@@ -108,7 +108,7 @@ class CLITests(unittest.TestCase):
         self.assertEqual(result.exit_code, 0)
         mock_serve.assert_called_once_with(
             dev_addr=None,
-            livereload='livereload',
+            livereload=True,
             build_type=None,
             config_file=None,
             strict=None,
@@ -127,7 +127,7 @@ class CLITests(unittest.TestCase):
         self.assertEqual(result.exit_code, 0)
         mock_serve.assert_called_once_with(
             dev_addr=None,
-            livereload='livereload',
+            livereload=True,
             build_type=None,
             config_file=None,
             strict=None,
@@ -144,7 +144,7 @@ class CLITests(unittest.TestCase):
         self.assertEqual(result.exit_code, 0)
         mock_serve.assert_called_once_with(
             dev_addr=None,
-            livereload='livereload',
+            livereload=True,
             build_type=None,
             config_file=None,
             strict=None,
@@ -161,7 +161,7 @@ class CLITests(unittest.TestCase):
         self.assertEqual(result.exit_code, 0)
         mock_serve.assert_called_once_with(
             dev_addr=None,
-            livereload='no-livereload',
+            livereload=False,
             build_type=None,
             config_file=None,
             strict=None,
@@ -178,7 +178,7 @@ class CLITests(unittest.TestCase):
         self.assertEqual(result.exit_code, 0)
         mock_serve.assert_called_once_with(
             dev_addr=None,
-            livereload='livereload',
+            livereload=True,
             build_type='dirty',
             config_file=None,
             strict=None,
@@ -195,7 +195,7 @@ class CLITests(unittest.TestCase):
         self.assertEqual(result.exit_code, 0)
         mock_serve.assert_called_once_with(
             dev_addr=None,
-            livereload='livereload',
+            livereload=True,
             build_type=None,
             config_file=None,
             strict=None,