inventor96/inertia-offline 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

inventor96/inertia-offline

Composer 安装命令:

composer require inventor96/inertia-offline

包简介

Framework-agnostic backend primitives for Inertia offline support.

README 文档

README

Framework-agnostic backend primitives for discovering which Inertia routes should be available offline.

Beta: offline read-only layer for Inertia.js apps, focused on safe cached content and navigation fallback.

This package is intentionally small: it provides the core algorithm and extension points, while each framework (Laravel, Mako, Symfony, Slim, etc.) supplies route inspection, action invocation, and pagination URL expansion.

This PHP backend package is designed to work with inertia-offline (the JS/TS frontend service worker library). Both the frontend and the backend aspects are required for an Inertia.js app.

Why This Exists

Offline-first Inertia apps usually need a server endpoint that returns a list of URLs to precache, often with TTL metadata. The hard part is generating that list in a reliable and maintainable way.

inventor96/inertia-offline solves this by:

  • Marking cacheable actions with a PHP attribute.
  • Scanning routes and reflecting on their actions.
  • Expanding dynamic routes via a parameter generator.
  • Optionally expanding pagination URLs.
  • Returning normalized entries: { url, ttl }.

⚠️ This is (Probably) Not the Package You're Looking For

This package is not a drop-in solution for your framework. Instead, it's a core engine that you can build an adapter on top of for your specific framework. Below is a list of known adapters for popular frameworks.

Don't see yours? The core is designed to be adaptable to a wide range of frameworks with different routing and action paradigms. If you build an adapter for a framework, please consider opening a PR to add it to the list below!

Core Concepts

1. OfflineCacheable attribute

The #[OfflineCacheable(...)] attribute is used in individual projects on controller methods or functions that should be considered for offline caching.

<?php

use inventor96\InertiaOffline\OfflineCacheable;

final class PostController
{
    #[OfflineCacheable(ttl: 3600)]
    public function index(): mixed
    {
        // ...
    }
}

Attribute options:

  • ttl (int, default 86400): route TTL in seconds.
  • param_generator (callable|array|string|Closure|null): returns iterable parameter sets for dynamic route expansion.
  • pagination_resolver (mixed|null): value or action that indicates pagination metadata.
  • access_control (callable|array|string|Closure|null): action that decides if route should be included for current context/user.

2. AbstractOfflineRouteList

This abstract class contains the full generation pipeline (generateRoutes()):

  1. Iterate framework routes (getRoutes()).
  2. Resolve each route action (getRouteAction()), normalize format, and build reflection.
  3. Keep routes whose reflected action has #[OfflineCacheable].
  4. Evaluate access_control when configured.
  5. Build URL entries:
    • Single URL from route pattern, or
    • Multiple URLs from param_generator.
  6. Expand paginated URLs when pagination_resolver is configured.
  7. Deduplicate and return array{ array{url: string, ttl: int} }.

3. Action normalization and supported action types

The core supports common action formats:

  • Function/closure/callable.
  • Class::method string.
  • Class@method string.
  • [ClassName, 'method'] or [$instance, 'method'].

If reflection or invocation is not possible for an action, that route is skipped.

4. URL building strategy

Route URL creation is done from a route pattern and parameter set:

  • Placeholder replacement: /posts/{id} + ['id' => 42] => /posts/42
  • Optional placeholders are removed when missing: {slug?}
  • Extra params become query string values.
  • If required placeholders are unresolved, the entry is skipped.

Contracts

  • inventor96\InertiaOffline\Contracts\OfflineRouteListInterface
    • generateRoutes(): array
  • inventor96\InertiaOffline\Contracts\PaginationUrlExpanderInterface
    • expand(string $baseUrl, mixed $pagination, mixed $route, OfflineCacheable $attribute, array $routeParams = []): array

Built-in Implementations

QueryPaginationUrlExpander

A ready-to-use implementation of PaginationUrlExpanderInterface that generates paginated URLs by appending a configurable query parameter (e.g. ?page=2) to the base URL.

<?php

use inventor96\InertiaOffline\Pagination\QueryPaginationUrlExpander;

$expander = new QueryPaginationUrlExpander(pageKey: 'page');

It resolves page count from the value returned by pagination_resolver in three ways:

Resolver return type Resolution strategy
int Used directly as the page count.
Object with numberOfPages() method Calls numberOfPages() and casts to int.
Array with 'pages' key Reads $pagination['pages'] and casts to int.

Given a base URL and a resolved page count n, it produces URLs for pages 1 through n.

Usage in an adapter

This expander is intentionally framework-agnostic, so it can serve as the default in any adapter. It's recommended that adapters accept an optional PaginationUrlExpanderInterface argument and fall back to QueryPaginationUrlExpander when none is provided, allowing projects to inject their own expander:

<?php

use inventor96\InertiaOffline\AbstractOfflineRouteList;
use inventor96\InertiaOffline\Contracts\PaginationUrlExpanderInterface;
use inventor96\InertiaOffline\OfflineCacheable;
use inventor96\InertiaOffline\Pagination\QueryPaginationUrlExpander;

final class OfflineRoutes extends AbstractOfflineRouteList
{
    public function __construct(
        // ...
        private readonly ?PaginationUrlExpanderInterface $paginationUrlExpander = null,
    ) {}

    protected function expandPaginationUrls(
        string $baseUrl,
        mixed $pagination,
        mixed $route,
        OfflineCacheable $attribute,
        array $routeParams = [],
    ): array {
        $expander = $this->paginationUrlExpander ?? new QueryPaginationUrlExpander();
        return $expander->expand($baseUrl, $pagination, $route, $attribute, $routeParams);
    }

    // ...
}

This pattern lets the adapter provide a sensible default while giving individual projects the flexibility to substitute a custom expander for pagination schemes that use path segments, cursor tokens, or other non-standard formats.

If your framework has a DI container, you can also consider making the expander a dependency of the adapter and letting projects bind their preferred implementation in the container.

Building a Framework Adapter

To implement this package for your framework, create a class extending AbstractOfflineRouteList and implement the abstract methods.

<?php

namespace Acme\InertiaOfflineYourFramework;

use inventor96\InertiaOffline\AbstractOfflineRouteList;
use inventor96\InertiaOffline\OfflineCacheable;

final class OfflineRoutes extends AbstractOfflineRouteList
{
    protected function getRoutes(): iterable
    {
        // Return the entire set of routes from your framework's router.
    }

    protected function getRoutePattern(mixed $route): string
    {
        // Return route pattern, e.g. /posts/{id}.
        // `$route` is a single item from the iterable returned by `getRoutes()`
    }

    protected function getRouteAction(mixed $route): mixed
    {
        // Return route action in any supported format.
        // `$route` is a single item from the iterable returned by `getRoutes()`
    }

    protected function invokeAction(mixed $action, array $parameters = []): mixed
    {
        // Use your framework or DI container/invoker to resolve dependencies
        // and call an action.
        // `$action` is the normalized action from `getRouteAction()`.
    }

    protected function expandPaginationUrls(
        string $baseUrl, // from route pattern + params, e.g. /posts/42
        mixed $pagination, // pagination metadata from `pagination_resolver` action
        mixed $route, // the original route item from `getRoutes()`
        OfflineCacheable $attribute, // the attribute instance from the reflected action
        array $routeParams = [], // the parameter set used to generate the base URL, e.g. ['id' => 42]
    ): array {
        // Convert pagination metadata into concrete URLs
        // e.g. /posts?page=1, /posts?page=2, ...
    }

    protected function logWarning(string $message): void
    {
        // Optional: send warnings to framework logger
    }
}

Recommended Adapter Methodology

  1. Route selection

    • Return all routes from your framework's router in getRoutes().
    • Let the core filter down to cacheable routes via the presence of #[OfflineCacheable] in individual projects.
  2. Stable action invocation

    • Ensure invokeAction() can call class methods, closures, and container-resolved callables.
  3. Pagination normalization

    • Treat pagination resolver output as adapter-specific and convert to URLs via one expander implementation.
    • Feel free to use QueryPaginationUrlExpander as the default inside expandPaginationUrls() if it covers the common case for your framework.
    • Accept an optional PaginationUrlExpanderInterface in your adapter constructor so projects can supply a custom expander for non-standard pagination (path-segment pages, cursor tokens, etc.).
  4. Observability

    • Implement logWarning() so unsupported actions or malformed generators are visible in logs.
  5. Deterministic output

    • Keep route generation deterministic for the same user/context to improve cache behavior and debugging.
  6. ETag support (optional)

    • The frontend library supports the use of ETags and If-None-Match headers for caching the route list and inertia requests. If your framework does not have built-in support for ETags, consider implementing a simple ETag middleware that projects can use.

Example: Dynamic Route + Pagination

<?php

use inventor96\InertiaOffline\OfflineCacheable;

final class PostController
{
    #[OfflineCacheable(
        ttl: 1800,
        param_generator: [PostOfflineParams::class, 'recent'],
        pagination_resolver: [PostOfflinePagination::class, 'resolve'],
        access_control: [PostOfflineAccess::class, 'canUseOffline']
    )]
    public function show(int $id): mixed
    {
        // ...
    }
}

Possible flow:

  • Route pattern: /posts/{id}
  • Param generator returns: [['id' => 10], ['id' => 11]]
  • Base URLs: /posts/10, /posts/11
  • Pagination resolver for each base URL returns 3 pages
  • Final entries include:
    • /posts/10
    • /posts/10?page=1
    • /posts/10?page=2
    • /posts/10?page=3
    • /posts/11
    • etc.

(all with configured TTL of 1800 seconds)

Package Boundaries

This package does not:

  • Register framework routes/controllers.
  • Provide auth/session integration.
  • Decide your endpoint payload format beyond route entry generation.

Those concerns belong in your framework adapter or host application.

inventor96/inertia-offline 适用场景与选型建议

inventor96/inertia-offline 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 11 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 04 月 03 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「php」 「offline」 「inertia」 「service worker」 「precaching」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 inventor96/inertia-offline 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 inventor96/inertia-offline 我们能提供哪些服务?
定制开发 / 二次开发

基于 inventor96/inertia-offline 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 11
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 27
  • 依赖项目数: 1
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-04-03