Claude-skill-registry Laravel Package Specialist
Laravel and Nova package development, forked package management, VCS path repositories, webpack configuration, and package integration workflows. Triggers include "package", "nova field", "nova tool", "webpack.mix.js", "pcrcard/nova-*", "packages/".
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/laravel-package-specialist" ~/.claude/skills/majiayu000-claude-skill-registry-laravel-package-specialist && rm -rf "$T"
skills/data/laravel-package-specialist/SKILL.mdLaravel Package Specialist
Expert assistance for Laravel and Nova package development, forked package management, and package integration workflows.
When to Use
- Creating or modifying Laravel Nova fields
- Developing Nova resources, tools, or lenses
- Managing forked packages (pcrcard/nova-*)
- Building and deploying package assets
- Configuring webpack for Nova packages
- Package versioning and git workflows
- Troubleshooting package integration issues
- Syncing with upstream package forks
Quick Commands
# Package management ./scripts/dev.sh pkg:list # List all forked packages ./scripts/dev.sh pkg:status # Show package status ./scripts/dev.sh pkg:clone [package-name] # Clone packages ./scripts/dev.sh pkg:update [package-name] # Update from remote ./scripts/dev.sh pkg:build <package-name> # Build and reinstall # Package development workflow cd packages/<package-name>/ npm install npm run dev # Development build npm run prod # Production build git add . git commit -m "feat: description" git push origin master composer update pcrcard/<package-name> # Update main app
PCR Card Package Architecture
Forked Packages
1. pcrcard/nova-menus - Hierarchical menu management
- Path:
packages/nova-menus/ - Remote: https://github.com/hackur/nova-menus
- Upstream: skylark-team/nova-menus
- Purpose: Database-driven Nova sidebar menus
2. pcrcard/nova-medialibrary-bounding-box-field - Media + damage assessment
- Path:
packages/nova-medialibrary-bounding-box-field/ - Remote: https://github.com/hackur/nova-medialibrary-bounding-box-field
- Upstream: dmitrybubyakin/nova-medialibrary-field
- Purpose: Spatie MediaLibrary management + canvas-based bounding box editor
- Fields:
,MedialibraryBoundingBoxField
Package Structure
packages/ ├── nova-menus/ │ ├── src/ # PHP source (Fields, Tools, Resources) │ ├── resources/ # Vue components, CSS │ │ └── js/ │ ├── dist/ # Compiled assets (committed) │ ├── composer.json # Package metadata │ ├── package.json # npm dependencies │ └── webpack.mix.js # Laravel Mix configuration └── nova-medialibrary-bounding-box-field/ ├── src/ │ └── Fields/ # Nova field classes ├── resources/ │ └── js/components/ # Vue 3 components ├── dist/ # Compiled assets ├── docs/ # Package documentation ├── composer.json ├── package.json └── webpack.mix.js
Composer Configuration
{ "repositories": { "nova-menus": { "type": "path", "url": "packages/nova-menus" }, "nova-medialibrary-field": { "type": "path", "url": "packages/nova-medialibrary-bounding-box-field" } }, "require": { "pcrcard/nova-menus": "@dev", "pcrcard/nova-medialibrary-bounding-box-field": "@dev" } }
Package Development Patterns
1. Creating New Nova Field
PHP Field Class (
src/Fields/MyField.php):
namespace Vendor\Package\Fields; use Laravel\Nova\Fields\Field; class MyField extends Field { public $component = 'my-field'; public function __construct($name, $attribute = null, callable $resolveCallback = null) { parent::__construct($name, $attribute, $resolveCallback); } // Custom methods for field configuration public function withConfig(array $config): self { return $this->withMeta(['config' => $config]); } }
Vue Component Registration (
resources/js/field.js):
import IndexField from './components/IndexField' import DetailField from './components/DetailField' import FormField from './components/FormField' Nova.booting((app, store) => { app.component('index-my-field', IndexField) app.component('detail-my-field', DetailField) app.component('form-my-field', FormField) })
Component Template (
resources/js/components/FormField.vue):
<template> <DefaultField :field="field" :errors="errors" :show-help-text="showHelpText" > <template #field> <div class="my-field-wrapper"> <!-- Your field UI --> </div> </template> </DefaultField> </template> <script> import { DependentFormField, HandlesValidationErrors } from 'laravel-nova' export default { mixins: [DependentFormField, HandlesValidationErrors], props: ['resourceName', 'resourceId', 'field'], methods: { fill(formData) { formData.append(this.field.attribute, this.value || '') } } } </script>
2. Webpack Configuration (Nova 5.x)
Standard webpack.mix.js for Nova Packages:
let mix = require('laravel-mix') mix .setPublicPath('dist') .js('resources/js/field.js', 'js') .vue({ version: 3 }) .css('resources/css/field.css', 'css') .webpackConfig({ externals: { vue: 'Vue', 'laravel-nova': 'LaravelNova', 'laravel-nova-ui': 'LaravelNovaUi', }, output: { uniqueName: 'vendor/package', }, }) .version()
Key Points:
- Output directorysetPublicPath('dist')
- Vue 3 for Nova 5.xvue({ version: 3 })- Externals - Don't bundle Vue/Nova (provided by Nova)
- Prevents webpack conflictsuniqueName
- Cache busting with mix-manifest.jsonversion()
3. Service Provider Registration
namespace Vendor\Package; use Laravel\Nova\Nova; use Laravel\Nova\Events\ServingNova; use Illuminate\Support\ServiceProvider; class FieldServiceProvider extends ServiceProvider { public function boot() { Nova::serving(function (ServingNova $event) { Nova::script('my-field', __DIR__.'/../dist/js/field.js'); Nova::style('my-field', __DIR__.'/../dist/css/field.css'); }); } public function register() { // } }
Alternative (Laravel Mix manifest):
public function boot() { Nova::serving(function (ServingNova $event) { Nova::mix('my-field', __DIR__.'/../dist/mix-manifest.json'); }); }
4. Package composer.json
{ "name": "pcrcard/my-nova-field", "description": "My Nova field description", "keywords": ["laravel", "nova", "field"], "license": "MIT", "require": { "php": "^8.2", "laravel/nova": "^5.0" }, "autoload": { "psr-4": { "Pcrcard\\MyNovaField\\": "src/" } }, "extra": { "laravel": { "providers": [ "Pcrcard\\MyNovaField\\FieldServiceProvider" ] } }, "minimum-stability": "dev", "prefer-stable": true }
Development Workflows
Package Development Workflow
Complete workflow for modifying a package:
# 1. Navigate to package directory cd packages/nova-medialibrary-bounding-box-field/ # 2. Make code changes # Edit src/Fields/BoundingBoxField.php # Edit resources/js/components/FormField.vue # 3. Build assets npm run dev # Development build (faster) npm run prod # Production build (minified) # 4. Test in main app cd ../.. composer update pcrcard/nova-medialibrary-bounding-box-field # 5. Commit to package repo cd packages/nova-medialibrary-bounding-box-field/ git add . git commit -m "feat: Add new feature to bounding box editor" git push origin master # 6. Update main app (optional) cd ../.. composer update pcrcard/nova-medialibrary-bounding-box-field
Creating New Forked Package
# 1. Fork upstream package on GitHub # 2. Clone into packages/ directory cd packages/ git clone https://github.com/hackur/new-package.git # 3. Update composer.json namespace cd new-package/ # Edit composer.json: Change namespace to "pcrcard/*" # 4. Add to main app composer.json cd ../.. # Add repository and require to composer.json # 5. Install package composer install # 6. Update package management script # Edit scripts/lib/packages.sh - add to get_forked_packages()
Best Practices
Git Workflow
- ✅ ALWAYS commit to package repo first, then main app
- ✅ Use semantic versioning tags (v1.0.0, v2.0.0)
- ✅ Keep package and app commits separate
- ✅ Reference package commits in app commit messages
- ✅ Push to fork remote (origin), not upstream
Asset Building
- ✅ Build in package directory (not main app)
- ✅ Use
for production buildsnpm run prod - ✅ COMMIT dist/ files to package repo (required for Nova)
- ❌ Never commit node_modules/
- ✅ Test builds locally before committing
Dependencies
- ✅ External packages in externals config (Vue, Nova, etc.)
- ❌ Don't bundle Nova or Vue in package assets
- ✅ Use @dev version constraint for local development
- ✅ Lock upstream versions in package.json
Symlinks
- ✅ Composer creates symlinks automatically
- ✅ vendor/pcrcard/* → packages/*
- ❌ Don't modify symlinks manually
- ✅ Rebuild symlinks:
composer install
Troubleshooting
Package Changes Not Reflected
Symptom: Modified package code doesn't appear in Nova
Solution:
cd packages/<package>/ npm run dev # Rebuild assets cd ../.. composer update pcrcard/<package> # Update main app php artisan nova:publish # Republish Nova assets php artisan cache:clear # Clear cache
Webpack Errors (Cannot Find Module)
Symptom:
Module not found: Error: Can't resolve 'laravel-nova'
Solution: Check externals configuration
// webpack.mix.js .webpackConfig({ externals: { vue: 'Vue', // ✅ Must be externalized 'laravel-nova': 'LaravelNova', // ✅ Must be externalized 'laravel-nova-ui': 'LaravelNovaUi', // ✅ Must be externalized }, })
Vue Component Not Rendering
Symptom: Nova field shows blank or error in console
Solution:
- Check component registration in field.js
- Verify
property matches registration name$component - Check browser console for errors
- Verify Vue 3 syntax (Composition API vs Options API)
// ✅ CORRECT: Registration matches field $component Nova.booting((app) => { app.component('index-my-field', IndexField) // matches $component = 'my-field' })
Symlink Broken
Symptom:
vendor/pcrcard/<package> missing or broken
Solution:
rm -rf vendor/pcrcard/<package> composer install # Recreates symlinks
Asset Build Fails
Symptom:
npm run dev or npm run prod fails
Solution:
rm -rf node_modules/ rm package-lock.json npm install npm run dev
Package Not Found After Installation
Symptom: Composer can't find package
Solution: Verify composer.json configuration
{ "repositories": { "my-package": { "type": "path", "url": "packages/my-package" // ✅ Correct path } }, "require": { "pcrcard/my-package": "@dev" // ✅ Correct constraint } }
Nova 5.x Specific Patterns
Vue 3 Component Structure
<script setup> import { ref, computed } from 'vue' const props = defineProps({ resourceName: String, resourceId: [String, Number], field: Object, }) const value = ref(props.field.value || '') const fill = (formData) => { formData.append(props.field.attribute, value.value) } defineExpose({ fill }) </script>
Field Meta Data
// Pass data to Vue component MyField::make('Name') ->withMeta([ 'config' => [ 'option1' => true, 'option2' => 'value', ], ]);
Access in Vue:
// this.field.config (Options API) // props.field.config (Composition API)
Nova Mixins (Options API)
import { DependentFormField, HandlesValidationErrors } from 'laravel-nova' export default { mixins: [DependentFormField, HandlesValidationErrors], // ... }
Documentation References
Package Documentation
- Package fork integration:
docs/development/PACKAGE-FORK-INTEGRATION-PLAN.md - BoundingBox field:
packages/nova-medialibrary-bounding-box-field/README.md - Nova menus:
packages/nova-menus/README.md - Package scripts:
scripts/lib/packages.sh
Related Guides
- Nova Admin Guide:
docs/development/NOVA-ADMIN-GUIDE.md - Nova Resource Builder skill:
.claude/skills/nova-resource/SKILL.md
External Resources
- Laravel Nova Docs: https://nova.laravel.com/docs/5.0
- Laravel Mix Docs: https://laravel-mix.com/docs/6.0
- Vue 3 Docs: https://vuejs.org/guide/
- Webpack Docs: https://webpack.js.org/
Common Tasks Checklist
Creating New Nova Field Package
- Fork upstream package (if applicable)
- Clone into
directorypackages/ - Update
withcomposer.json
namespacepcrcard/* - Create PHP field class in
src/Fields/ - Create Vue components in
resources/js/components/ - Set up component registration in
resources/js/field.js - Configure
with externalswebpack.mix.js - Create service provider with Nova::serving()
- Add package to main
composer.json - Add to
get_forked_packages()scripts/lib/packages.sh - Run
composer install - Build assets:
npm run prod - Commit dist/ files
- Test in Nova admin
Modifying Existing Package
- Navigate to package directory
- Create feature branch (optional)
- Make code changes
- Build assets:
npm run dev - Test in main app
- Build production assets:
npm run prod - Commit changes (including dist/)
- Push to remote fork
- Update main app:
composer update pcrcard/<package>
Syncing with Upstream
- Add upstream remote:
git remote add upstream <url> - Fetch upstream:
git fetch upstream - Review changes:
git log upstream/master - Merge or rebase:
git merge upstream/master - Resolve conflicts
- Rebuild assets
- Test thoroughly
- Commit and push
Last Updated: October 2025 Package Count: 2 (nova-menus, nova-medialibrary-bounding-box-field) Nova Version: 5.x (Vue 3, Laravel Mix 6.x)