Skip to content

fix: 更新依赖项版本并修复 CSS 加载逻辑 - #650

Merged
wess09 merged 2 commits into
masterfrom
dev
Jul 28, 2026
Merged

fix: 更新依赖项版本并修复 CSS 加载逻辑#650
wess09 merged 2 commits into
masterfrom
dev

Conversation

@wess09

@wess09 wess09 commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Summary by Sourcery

优化 WebUI 启动流程、静态资源加载和 HTTP 内容投递,以提升性能、缓存效果和可配置性,并更新相关依赖。

New Features:

  • 添加批量 CSS 注入和共享样式加载机制,通过跟踪每个会话中已注入的样式,避免重复工作。
  • 引入使用空闲回调(idle callbacks)的延迟客户端资源加载,用于分析脚本和辅助 JS,并支持从存储状态中恢复之前的侧边栏视图。
  • 为大型世界模拟器添加惰性初始化机制,只对已渲染的控件动态绑定配置监听器。
  • 为 FastAPI 应用提供的静态资源启用 GZip 压缩,并使用更智能的 Cache-Control 响应头。
  • 暴露一个辅助方法,用于在一次浏览器往返中获取多个 localStorage 键,并从初始 HTML 传递预加载 CSS 提示信息。

Bug Fixes:

  • 通过按会话和每个 DOM 元素 id 去重样式和客户端资源,修复重复注入 CSS 和脚本的问题。
  • 确保登录和导航逻辑可以正确复用 localStorage 中存储的侧边栏和密码值,而无需重复的同步请求。
  • 防止为同一个 pin 多次注册配置监听回调。

Enhancements:

  • 调整 Web 字体加载策略,使用 font-display: optional 以减少布局阻塞。
  • 优化 WebUI 初始化流程,在登录与首页/管理入口之间复用 localStorage 值,并将非关键工作延迟到首屏绘制之后。
  • 更新 Python 与 uv 版本要求,并微调对不带内容哈希的静态资源的 HTTP 缓存行为。

Build:

  • 将 Python 运行时要求更新为 >=3.14.6,并将 uv 依赖升级至 0.11.32。
Original summary in English

Summary by Sourcery

Refine WebUI startup, asset loading, and HTTP delivery for better performance, caching, and configurability, while updating dependencies.

New Features:

  • Add batched CSS injection and shared style loading that tracks per-session injected styles to avoid duplicate work.
  • Introduce deferred client asset loading for analytics scripts and helper JS using idle callbacks, and support restoring previous aside views from stored state.
  • Add lazy initialization for the large world simulator and dynamic binding of config watchers only for rendered controls.
  • Enable GZip compression and smarter Cache-Control headers for static assets served by the FastAPI app.
  • Expose a helper to fetch multiple localStorage keys in one browser round-trip and pass preloaded CSS hints from initial HTML.

Bug Fixes:

  • Fix duplicate CSS and script injection issues by deduplicating styles and client assets per session and per DOM element id.
  • Ensure login and navigation logic correctly reuses stored aside and password values from localStorage without repeated synchronous requests.
  • Prevent config watcher callbacks from being registered multiple times for the same pin.

Enhancements:

  • Adjust web font loading to use font-display optional to reduce layout blocking.
  • Refine WebUI initialization flow to reuse localStorage values across login and home/manage entrypoints and to delay non-critical work until after first paint.
  • Update Python and uv version requirements and tweak HTTP cache behavior for static assets without content hashes.

Build:

  • Update Python runtime requirement to >=3.14.6 and bump uv dependency to 0.11.32.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@wess09
wess09 merged commit 0f60377 into master Jul 28, 2026
8 checks passed
@sourcery-ai

sourcery-ai Bot commented Jul 28, 2026

Copy link
Copy Markdown

审阅者指南

重构 WebUI 的 CSS 与客户端资源加载逻辑,使其具备幂等性并基于会话作用域;优化 localStorage 访问与初始页面恢复;延迟加载体量较大的模拟器依赖;为静态资源引入 HTTP 缓存与 gzip 压缩;同时更新依赖版本与字体配置以提升性能。

更新后的 WebUI 启动、登录和延迟资源加载的时序图

sequenceDiagram
    actor User
    participant Browser
    participant index
    participant _run_gui
    participant load_webui_styles
    participant get_localstorage_values
    participant login
    participant AlasGUI_run as AppHome.run
    participant _load_deferred_client_assets

    User->>Browser: open / (home)
    Browser->>index: HTTP request
    index->>_run_gui: index()
    _run_gui->>load_webui_styles: load_webui_styles(theme, is_mobile, preloaded_styles)
    _run_gui->>get_localstorage_values: get_localstorage_values(keys)
    get_localstorage_values-->>_run_gui: localstorage dict
    alt webui password set
        _run_gui->>login: login(password, stored_password)
        login-->>_run_gui: success or failure
        alt login failure
            _run_gui->>Browser: run_js(location.reload())
            _run_gui->>_run_gui: return
        end
    end
    _run_gui->>AlasGUI_run: gui.run(initial_page, localstorage)
    AlasGUI_run->>AlasGUI_run: load_webui_styles(theme, is_mobile)
    AlasGUI_run->>AlasGUI_run: decide restore_instance, show_clarity_notice
    AlasGUI_run->>AlasGUI_run: mount_shell()
    alt restore_instance
        AlasGUI_run->>AlasGUI_run: ui_alas(aside)
    else show home or manage
        AlasGUI_run->>AlasGUI_run: ui_manage() or show_home()
    end
    alt show_clarity_notice
        AlasGUI_run->>Browser: set_localstorage(clarity_notice_shown)
        AlasGUI_run->>Browser: toast()
    end
    AlasGUI_run->>_load_deferred_client_assets: _load_deferred_client_assets()
    _load_deferred_client_assets->>Browser: run_js(inject clarity, manifest, alas-utils.js)
    AlasGUI_run->>AlasGUI_run: task_handler.start()
Loading

文件级变更

变更 详情 文件
重构 CSS 注入逻辑,以支持批量处理、避免同一会话内重复加载,并追踪预加载样式。
  • 引入会话本地存储(local.webui_injected_styles)来追踪已注入的 CSS 文件。
  • 新增 add_css_files(),在单次 run_js 调用中批量注入 CSS 样式,并跳过已注入的文件。
  • 更新 load_webui_styles(),使其接受 preloaded_styles,并在加载其余样式前先用其初始化已注入集合。
  • 修改调用方,使用 add_css_files() 替代多次调用 add_css()。
module/webui/utils.py
module/webui/app.py
优化登录流程与 localStorage 使用,减少往返请求,并让首屏行为更可预测。
  • 新增 get_localstorage_values(),在浏览器端一次性获取多个 localStorage 键。
  • 扩展 login(),支持可选的 stored_password 参数,以避免额外的 localStorage 调用。
  • 更新 app_home.AppHome.run() 和 AlasGUI._run_gui(),预取相关 localStorage 键并在调用链中传递。
  • 将 aside 和 clarity_notice_shown 存储在实例中,以避免重复的客户端查找,并驱动初始页面恢复逻辑。
module/webui/utils.py
module/webui/app_home.py
module/webui/app.py
module/webui/app_dependencies.py
延迟加载非关键客户端脚本和 manifest,以提升首屏渲染速度,同时确保每个会话仅注入一次。
  • 提取 _load_deferred_client_assets(),用于在每个会话中仅一次性注入 Microsoft Clarity、manifest 链接以及 alas-utils.js。
  • 使用 requestIdleCallback 或 setTimeout,在初始 UI 渲染之后再加载这些资源。
  • 将 _load_deferred_client_assets() 接入 AppHome.run(),使其在 OOBE 或主 shell 初始化完成后、任务处理器启动前执行。
  • 确保 Clarity 提示(toast)在 UI 就绪后按条件显示,并在显示后更新 localStorage。
module/webui/app_home.py
将配置变更监听改为增量且基于控件,而非全局,并确保控件渲染时才添加监听器。
  • 移除全局的 _init_alas_config_watcher() 以及对 get_alas_config_listen_path() 的依赖。
  • 追踪哪些配置路径会生成交互式组件,并在 set_group() 中构建 watcher_paths。
  • 新增 _bind_config_watcher(),为每个 pin 仅注册一次 pin_on_change,并将变更加入 modified_config_queue 队列。
  • 在渲染分组输出之后调用 _bind_config_watcher(),以将监听器绑定到实际控件上。
module/webui/app_task_config.py
module/webui/app_shell.py
module/webui/app_dependencies.py
对 OSSimulator 及其重量级依赖进行延迟加载,避免在未使用模拟器时支付性能开销。
  • 从 app_dependencies 中移除对 OSSimulator 的提前导入,并从 AppShellMixin.init() 中移除直接实例化。
  • 新增 simulator 属性,在首次访问时导入并构造 OSSimulator。
  • 在加载 OSSimulator 之前,仅在当前加载的 PIL 为“假” PIL 时才移除该模块,避免从缓存中删除真正的 PIL 模块。
module/webui/app_shell.py
module/webui/app_dependencies.py
为静态资源引入 HTTP cache-control,并启用 gzip 响应压缩以提升性能。
  • 在 HeaderMiddleware 中加入逻辑,用于区分静态资源路径,并根据路径和 HTTP 方法应用长效缓存或禁用缓存策略。
  • 定义 cache-control 值和 gzip 配置的常量。
  • 在 Starlette 应用中,将 GZipMiddleware 插入到 HeaderMiddleware 之前,以压缩符合条件的 HTTP 响应。
module/webui/fastapi.py
调整初始 CSS 与字体加载行为,以提升感知性能并更好地与 pywebio webconfig 集成。
  • 新增 INITIAL_WEBUI_CSS 常量,并为 index/manage 端点添加 webconfig(css_file=INITIAL_WEBUI_CSS) 装饰器,使基础 CSS 随初始 HTML 一并提供。
  • 更新 load_webui_styles() 的调用,将 'alas' 视为已预加载,从而避免通过 WebSocket 再次注入。
  • 修改 alas.css 中的 font-face 声明,对 MiSans-Demibold 使用 font-display: optional,以减少布局阻塞。
module/webui/app.py
assets/gui/css/alas.css
更新 Python 与依赖版本到更新的补丁版本,并为 zh-MIAO 新增配置。
  • 在 pyproject.toml 中将 requires-python 的最小版本提升到 3.14.6,并将 uv 从 0.10.2 更新到 0.11.32。
  • 在 module/config 下新增 zh-MIAO.json 配置文件,用于新的本地化或配置档案。
pyproject.toml
module/config/zh-MIAO.json

提示与命令

与 Sourcery 交互

  • 触发新的审阅: 在 pull request 上评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审阅评论。
  • 从审阅评论生成 GitHub Issue: 在审阅评论下回复,要求 Sourcery 从该评论创建 issue。你也可以回复 @sourcery-ai issue,从该评论创建 issue。
  • 生成 pull request 标题: 在 pull request 标题任意位置写入 @sourcery-ai,即可随时生成标题。你也可以在 pull request 中评论 @sourcery-ai title 来(重新)生成标题。
  • 生成 pull request 摘要: 在 pull request 正文任意位置写入 @sourcery-ai summary,即可在对应位置生成 PR 摘要。你也可以在 pull request 中评论 @sourcery-ai summary 来(重新)生成摘要。
  • 生成审阅者指南: 在 pull request 中评论 @sourcery-ai guide,即可(重新)生成审阅者指南。
  • 解决所有 Sourcery 评论: 在 pull request 中评论 @sourcery-ai resolve,可一次性解决所有 Sourcery 评论。适用于你已处理所有评论且不希望再看到它们的情况。
  • 撤销所有 Sourcery 审阅: 在 pull request 中评论 @sourcery-ai dismiss,可撤销所有现有 Sourcery 审阅。尤其适用于你希望在新审阅中“从零开始”的场景——别忘了之后再评论 @sourcery-ai review 触发新审阅!

自定义你的体验

访问你的 控制面板 来:

  • 启用或禁用审阅功能,例如 Sourcery 生成的 pull request 摘要、审阅者指南等。
  • 更改审阅语言。
  • 添加、删除或编辑自定义审阅指令。
  • 调整其他审阅设置。

获取帮助

Original review guide in English

Reviewer's Guide

Refactors WebUI CSS and client asset loading to be idempotent and session-scoped, optimizes localStorage access and initial page restoration, lazily loads heavy simulator dependencies, introduces HTTP caching and gzip for static assets, and updates dependency versions and fonts for better performance.

Sequence diagram for updated WebUI startup, login, and deferred asset loading

sequenceDiagram
    actor User
    participant Browser
    participant index
    participant _run_gui
    participant load_webui_styles
    participant get_localstorage_values
    participant login
    participant AlasGUI_run as AppHome.run
    participant _load_deferred_client_assets

    User->>Browser: open / (home)
    Browser->>index: HTTP request
    index->>_run_gui: index()
    _run_gui->>load_webui_styles: load_webui_styles(theme, is_mobile, preloaded_styles)
    _run_gui->>get_localstorage_values: get_localstorage_values(keys)
    get_localstorage_values-->>_run_gui: localstorage dict
    alt webui password set
        _run_gui->>login: login(password, stored_password)
        login-->>_run_gui: success or failure
        alt login failure
            _run_gui->>Browser: run_js(location.reload())
            _run_gui->>_run_gui: return
        end
    end
    _run_gui->>AlasGUI_run: gui.run(initial_page, localstorage)
    AlasGUI_run->>AlasGUI_run: load_webui_styles(theme, is_mobile)
    AlasGUI_run->>AlasGUI_run: decide restore_instance, show_clarity_notice
    AlasGUI_run->>AlasGUI_run: mount_shell()
    alt restore_instance
        AlasGUI_run->>AlasGUI_run: ui_alas(aside)
    else show home or manage
        AlasGUI_run->>AlasGUI_run: ui_manage() or show_home()
    end
    alt show_clarity_notice
        AlasGUI_run->>Browser: set_localstorage(clarity_notice_shown)
        AlasGUI_run->>Browser: toast()
    end
    AlasGUI_run->>_load_deferred_client_assets: _load_deferred_client_assets()
    _load_deferred_client_assets->>Browser: run_js(inject clarity, manifest, alas-utils.js)
    AlasGUI_run->>AlasGUI_run: task_handler.start()
Loading

File-Level Changes

Change Details Files
Refactor CSS injection to support batching, avoid duplicate loads per session, and track preloaded styles.
  • Introduce session-local storage (local.webui_injected_styles) to track injected CSS files.
  • Add add_css_files() to batch-inject CSS styles in a single run_js call and skip already-injected files.
  • Update load_webui_styles() to accept preloaded_styles and seed the injected set before loading the rest.
  • Change callers to use add_css_files() instead of repeated add_css().
module/webui/utils.py
module/webui/app.py
Optimize login and localStorage usage to reduce round trips and make first-page behavior deterministic.
  • Add get_localstorage_values() to fetch multiple localStorage keys at once in the browser.
  • Extend login() to accept an optional stored_password to avoid extra localStorage calls.
  • Update app_home.AppHome.run() and AlasGUI._run_gui() to prefetch relevant localStorage keys and pass them through.
  • Store aside and clarity_notice_shown in the instance to avoid repeated client lookups and drive initial page restoration.
module/webui/utils.py
module/webui/app_home.py
module/webui/app.py
module/webui/app_dependencies.py
Defer non-critical client scripts and manifest loading to improve first paint while still ensuring single injection per session.
  • Extract _load_deferred_client_assets() to inject Microsoft Clarity, manifest link, and alas-utils.js only once per session.
  • Use requestIdleCallback or setTimeout to load these assets after initial UI render.
  • Wire _load_deferred_client_assets() into AppHome.run() so it executes after OOBE or main shell setup and before task handler start.
  • Ensure clarity toast is shown conditionally and only after UI is ready, updating localStorage once shown.
module/webui/app_home.py
Make configuration change watching incremental and per-control instead of global, and ensure watchers are added when controls are rendered.
  • Remove global _init_alas_config_watcher() and dependency on get_alas_config_listen_path().
  • Track which config paths produce interactive widgets and build watcher_paths during set_group().
  • Introduce _bind_config_watcher() that registers pin_on_change only once per pin and enqueues changes into modified_config_queue.
  • Call _bind_config_watcher() after rendering group outputs to attach watchers to actual controls.
module/webui/app_task_config.py
module/webui/app_shell.py
module/webui/app_dependencies.py
Lazy-load OSSimulator and its heavyweight dependencies to avoid paying the cost unless the simulator is used.
  • Remove eager OSSimulator import from app_dependencies and direct instantiation from AppShellMixin.init().
  • Add a simulator property that imports and constructs OSSimulator on first access.
  • Before loading OSSimulator, remove the fake PIL module only if the currently loaded PIL is the fake one, avoiding deleting a real PIL module from cache.
module/webui/app_shell.py
module/webui/app_dependencies.py
Introduce HTTP cache-control for static assets and gzip compression for responses to improve performance.
  • Add HeaderMiddleware logic to distinguish static asset paths and apply either long-lived cache or no-cache based on path and method.
  • Define constants for cache-control values and gzip configuration.
  • Insert GZipMiddleware before HeaderMiddleware in the Starlette app to compress eligible HTTP responses.
module/webui/fastapi.py
Adjust initial CSS and font loading behavior for better perceived performance and integration with pywebio webconfig.
  • Add INITIAL_WEBUI_CSS constant and decorate index/manage endpoints with webconfig(css_file=INITIAL_WEBUI_CSS) so base CSS is provided in initial HTML.
  • Update load_webui_styles() calls to treat 'alas' as preloaded and avoid reinjecting it via WebSocket.
  • Change font-face declarations in alas.css to use font-display: optional for MiSans-Demibold to reduce layout blocking.
module/webui/app.py
assets/gui/css/alas.css
Update Python and dependency versions to newer patch releases and add new configuration for zh-MIAO.
  • Bump requires-python minimum to 3.14.6 and update uv from 0.10.2 to 0.11.32 in pyproject.toml.
  • Add new configuration file zh-MIAO.json under module/config for a new locale or profile.
pyproject.toml
module/config/zh-MIAO.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了 1 个问题

面向 AI 代理的提示
请根据本次代码审查中的评论进行修改:

## 单独评论

### 评论 1
<location path="module/webui/utils.py" line_range="406-415" />
<code_context>
+def add_css_files(filepaths):
</code_context>
<issue_to_address>
**issue (bug_risk):** 仅使用 basename 作为 style_id 可能导致冲突,并阻止后续样式加载

这里依然是通过 `os.path.basename(filepath)` 来生成 `style_id`,并且现在如果已经存在具有该 id 的元素就会提前返回。之前,当第二次调用 `add_css()` 且传入的文件与已有文件同名(basename 相同)但内容不同的时候,新样式会替换旧样式;而现在会被跳过,从而保留旧样式。如果你可能会提供文件名相同但路径不同的 CSS 文件,这是行为上的改变,可能会导致旧样式残留生效。请考虑使用更独特的 id(例如包含哈希或相对路径),或者以其他方式显式处理这种冲突。
</issue_to_address>

Sourcery 对开源项目免费——如果你喜欢我们的审查,请考虑分享 ✨
帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据你的反馈改进后续审查。
Original comment in English

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="module/webui/utils.py" line_range="406-415" />
<code_context>
+def add_css_files(filepaths):
</code_context>
<issue_to_address>
**issue (bug_risk):** Using basename-only for style_id can cause collisions and prevent later styles from loading

This still derives `style_id` from `os.path.basename(filepath)` and now early-returns if an element with that id already exists. Previously, a second `add_css()` call with a different file sharing the same basename would replace the old style; now it will be skipped, leaving the old styles in place. If you may serve CSS files that share a filename but differ by path, this is a behavior change and can leave stale styles active. Please consider using a more unique id (e.g., including a hash or relative path) or otherwise handling this collision explicitly.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread module/webui/utils.py
Comment on lines +406 to +415
def add_css_files(filepaths):
"""将多份 CSS 合并为一次会话命令,保持传入顺序注入。"""
injected_styles = getattr(local, "webui_injected_styles", None)
if injected_styles is None:
injected_styles = set()
local.webui_injected_styles = injected_styles

使用 document.createElement + 文本节点的方式,确保包含引号或 </style> 的 CSS
不会破坏 JS/HTML 解析。
"""
with open(filepath, "r", encoding="utf-8") as f:
css = f.read()
styles = []
loaded_paths = []
for filepath in filepaths:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): 仅使用 basename 作为 style_id 可能导致冲突,并阻止后续样式加载

这里依然是通过 os.path.basename(filepath) 来生成 style_id,并且现在如果已经存在具有该 id 的元素就会提前返回。之前,当第二次调用 add_css() 且传入的文件与已有文件同名(basename 相同)但内容不同的时候,新样式会替换旧样式;而现在会被跳过,从而保留旧样式。如果你可能会提供文件名相同但路径不同的 CSS 文件,这是行为上的改变,可能会导致旧样式残留生效。请考虑使用更独特的 id(例如包含哈希或相对路径),或者以其他方式显式处理这种冲突。

Original comment in English

issue (bug_risk): Using basename-only for style_id can cause collisions and prevent later styles from loading

This still derives style_id from os.path.basename(filepath) and now early-returns if an element with that id already exists. Previously, a second add_css() call with a different file sharing the same basename would replace the old style; now it will be skipped, leaving the old styles in place. If you may serve CSS files that share a filename but differ by path, this is a behavior change and can leave stale styles active. Please consider using a more unique id (e.g., including a hash or relative path) or otherwise handling this collision explicitly.

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.

1 participant