Skip to content

Stop registering view paths the bundle never ships - #346

Merged
shanerbaner82 merged 5 commits into
NativePHP:mainfrom
trailhead-labs:fix/drop-unshipped-view-registrations
Aug 24, 2026
Merged

Stop registering view paths the bundle never ships#346
shanerbaner82 merged 5 commits into
NativePHP:mainfrom
trailhead-labs:fix/drop-unshipped-view-registrations

Conversation

@gwleuverink

@gwleuverink gwleuverink commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Fixes #322.

Every debug boot runs view:cache on the device, and it walks every registered view path with a Symfony Finder that throws when a path is missing. Two of the provider's registrations point at directories no bundle ever contains, because all three packers strip vendor/nativephp/mobile/resources (11MB of project templates the runtime never reads). So every cold boot logs this and dies:

The ".../vendor/nativephp/mobile/src/../resources/views" directory does not exist.

The two registrations are ->hasViews() and the jump namespace. Neither serves a purpose at runtime. hasViews() registers the package root resources/views, which contains a single .gitkeep, and its publish tag (nativephp-mobile-views) is never published by native:install. As far as I can tell it's scaffolding from the Spatie package skeleton: the .gitkeep-only views dir and the provider call both match the template, unchanged since the Init commit. The empty dir is deleted here as well. The real component views went to src/resources/views instead, under a separate registration that ships fine and stays. The jump:: namespace has zero view() references anywhere, the jump server reads those blades as raw text with file_get_contents on the host.

I checked whether anything contributes files into those two directories in a userland project before deleting the registrations. Nothing does: my test project symlinks the package into vendor, so any runtime write would show up in git status, and after many install, plugin-register and build cycles the tree is clean. mobile-ui registers no view namespace and every plugin write path resolves into the native build tree.

I actually went the other way first, shipping the two dirs as empty entries from every packer. It worked, but it put the burden on three different packers forever, and once it was clear the registrations are unused skeleton there was nothing left to ship around. Two deleted lines in the provider instead.

While hardening the regression test I found a third leg of the same crash: the provider also registers resources/views/native as a view location for every app, and only native:make-component ever creates that dir. An app that never scaffolded a native component hits the same view:cache crash, after view:clear has already run, so it's left with no compiled views at all. That location is genuinely wanted (it's where an app's own native views live), so this leg is fixed the way the issue originally suggested: resources/views/native joins BundleExclusions::REQUIRED_DIRECTORIES and ships as an empty entry, which every packer already honors.

The provider has a comment documenting a deliberate choice to register view paths unconditionally so IDE plugins that scan providers statically can index them. That argument holds for resources/views/native and the src/resources/views namespace, both of which stay exactly as they are, but an IDE gains nothing from indexing a .gitkeep or a namespace no code references. If I'm missing a reason either registration needs to stay, @simonhamp @shanerbaner82, happy to hear it.

Verification

  • A new test locks the invariant down: every view path the package registers must exist and must survive the bundle excludes. Paths are normalized lexically (Flysystem's path normalizer), because Spatie registers the raw src/../resources/views string when the dir is missing and realpath()-based checks go blind on it. Proven red for both regression shapes: re-adding hasViews() and re-adding the jump registration.
  • A second test pins nativephp-mobile::components.native-element-with-children staying resolvable, since it rides the registration that stays. The release bundle test additionally asserts resources/views/native/ ships.
  • Full suite green, pint clean, and view:cache on the host exits clean.
  • Android emulator, fresh build and forced cold boot: the bundle contains no vendor/nativephp/mobile/resources entries, logcat shows view:cache running post-extraction and producing 66 compiled views, and the DirectoryNotFoundException count in the persisted log stayed frozen at the 5 pre-fix entries. The app renders normally.
  • The third leg, proven in the failing shape: built the test app with resources/views/native deleted from its source. The bundle ships it as an empty entry, the dir lands on device, view:cache runs clean, and the exception count stays frozen. That exact build crashed on every boot before this change.
  • iOS simulator: app.zip contains no vendor resources entries, ships resources/views/native/, and the app boots and renders.
  • Ran native:jump against the branch: the QR page renders and serves normally, since the jump server reads its blades directly off disk and never used the removed namespace.

@shanerbaner82 shanerbaner82 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks good. view:cache crash on missing package view paths is real, and dropping the unused hasViews()/jump:: registrations is the right fix instead of shipping empty dirs forever. Shipping empty resources/views/native covers apps that never ran native:make-component. Tests lock both shapes. Jump still reads those blades off disk, so the namespace drop is safe.

@shanerbaner82
shanerbaner82 merged commit ab4e70a into NativePHP:main Aug 24, 2026
3 checks passed
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.

view:cache crashes on every debug cold boot — package excludes a folder it still registers as a view path

2 participants