genericmilk/cooker
| Install | |
|---|---|
composer require genericmilk/cooker |
|
| Latest Version: | 10.0.0 |
| PHP: | >=8.3 |
| License: | MIT |
| Last Updated: | Apr 29, 2026 |
| Links: | GitHub · Packagist |
Table of contents
- Why Cooker?
- Requirements
- Installation
- Concepts
- Adding a stack
- Adding npm packages
- The
@cookerdirective - Building & watching
- Configuration
- Upgrading from Cooker 8
Why Cooker?
If you've worked with Laravel + Vite or Laravel Mix you'll be familiar with the Node-shaped hole in your project: a package.json, a giant node_modules, a lockfile, and a separate dev server. Cooker replaces all of that with one Composer package and a small workspace folder.
- No Node required. Cooker drives
esbuildandtailwindcssas standalone binaries. - No
node_modules. Packages live flat at.cooker/packages/<name>/. Cooker resolves transitive deps for you. - One command to install a stack.
php artisan cooker:add reactinstalls React + ReactDOM and scaffolds a workingApp.jsx. - Beginner-friendly defaults.
@cooker('app.js')and@cooker('app.css')Just Work. - Static assets in production. No PHP runtime asset routes —
public/build/*.jsis served by your web server like any other static file.
Requirements
- PHP >= 8.3
- Laravel 10 or newer
- ext-zlib, ext-phar, ext-json (standard with most PHP builds)
Installation
composer require genericmilk/cooker
php artisan cooker:install
The installer will:
- Publish
config/cooker.php. - Create
.cooker/(bin, cache, packages) and add it to.gitignore. - Scaffold starter recipes at
resources/js/app.jsandresources/css/app.css. - Download
esbuildfor your platform. - Optionally bootstrap a stack (
react,vue,tailwind).
After install, drop into a Blade view:
<head>
@cooker('app.css')
</head>
<body>
<div id="app"></div>
@cooker('app.js')
</body>
Then build:
php artisan cooker:cook # production build
php artisan cooker:watch # dev — rebuilds on save
Concepts
Recipes
A recipe maps an output filename to a single entry file. Configured in config/cooker.php:
'recipes' => [
'app.js' => 'resources/js/app.js',
'app.css' => 'resources/css/app.css',
],
The output filename's extension determines the loader (.js/.mjs → script, .css → stylesheet). The entry's extension determines parsing — Cooker handles .js, .ts, .jsx, .tsx, .mjs, .css, .less, and .scss.
You import other files normally inside the entry — Cooker bundles them with esbuild.
The .cooker/ workspace
.cooker/
├── bin/ ← auto-downloaded binaries (esbuild, tailwindcss)
├── cache/ ← intermediate compiled CSS, etc.
├── packages/ ← flat npm package extracts
└── cooker.json ← installed packages + active stacks
.cooker/cooker.json is your project's manifest — it's the only file inside .cooker/ that's checked into git.
Adding a stack
Stacks are opinionated bundles — they install the right packages, scaffold a working starter, and wire everything in.
php artisan cooker:add react # React 18 + scaffolded App.jsx
php artisan cooker:add vue # Vue 3 + scaffolded App.js
php artisan cooker:add tailwind # Tailwind 4 — adds @import "tailwindcss"
After cooker:add react:
resources/js/
├── app.jsx ← entry; mounts <App/> to #app
└── components/App.jsx ← starter component
Update config/cooker.php to point the recipe at app.jsx:
'recipes' => [
'app.js' => 'resources/js/app.jsx',
],
Adding npm packages
php artisan cooker:add lodash
php artisan cooker:add @floating-ui/dom@^1
php artisan cooker:add zod@latest
Cooker fetches the tarball straight from the npm registry, extracts it to .cooker/packages/<name>/ and resolves transitive dependencies. There's no package.json and no lockfile — cooker.json records the top-level packages you asked for.
In your code:
import _ from 'lodash';
import { z } from 'zod';
Remove with:
php artisan cooker:remove lodash
The @cooker directive
@cooker('app.css')
@cooker('app.js')
Reads public/build/manifest.json and emits the right tag with the hashed filename:
<link rel="stylesheet" href="/build/app-3f8a91c2bd.css">
<script type="module" src="/build/app-7c0b1bf9aa.js"></script>
If a build hasn't been produced for the recipe yet, Cooker emits an HTML comment telling you to run cooker:cook.
Building & watching
php artisan cooker:cook # production build, minified
php artisan cooker:cook --no-minify # disable minification
php artisan cooker:cook --sourcemap # emit sourcemaps
php artisan cooker:cook --clean # wipe public/build first
php artisan cooker:watch # dev — incremental rebuilds on file change
php artisan cooker:watch --no-hmr # disable live reload
In app.debug=true environments, cooker:cook defaults to non-minified + sourcemaps. In production, it minifies and skips sourcemaps. Override per-environment with COOKER_MINIFY and COOKER_SOURCEMAP env vars.
Live reload
cooker:watch runs an embedded SSE server (default 127.0.0.1:5173) and the @cooker directive injects a tiny client snippet into your pages — but only when APP_DEBUG=true.
- CSS-only changes hot-swap the matching
<link>tag, no full reload. - JS or mixed changes trigger
location.reload(). - The client auto-reconnects if the watcher restarts.
Configure host/port in config/cooker.php under dev, or via COOKER_DEV_HOST / COOKER_DEV_PORT. Disable entirely with COOKER_DEV_ENABLED=false or --no-hmr.
Configuration
config/cooker.php is short on purpose:
return [
'recipes' => [
'app.js' => 'resources/js/app.js',
'app.css' => 'resources/css/app.css',
],
'output' => [
'path' => 'public/build',
'url' => '/build',
],
'toolbox' => [
'path' => '.cooker/bin',
'esbuild' => '0.24.2',
'tailwind' => '4.0.0',
],
'packages' => [
'path' => '.cooker/packages',
'manifest' => '.cooker/cooker.json',
'registry' => env('COOKER_REGISTRY', 'https://registry.npmjs.org'),
],
'build' => [
'minify' => env('COOKER_MINIFY', null),
'sourcemap' => env('COOKER_SOURCEMAP', null),
'target' => env('COOKER_TARGET', 'es2020'),
],
];
Upgrading from Cooker 8
Cooker 10 is a clean rewrite. The runtime PHP asset server (__cooker/{file}), Ovens, Preparsers and the import name from 'name' rewrite-to-CDN behaviour are all gone. To upgrade:
composer require genericmilk/cooker:^10php artisan cooker:uninstall(in your old project) or deleteconfig/cooker.phpand.cooker/manually.php artisan cooker:install.- Move your hand-written code into the new
resources/js/app.js/resources/css/app.cssentry files and add realimportstatements. - Replace any old
cooker-toolbelt/cooker-routesimports — they're not part of Cooker 10. - For each npm package you used to import directly from
esm.run, runphp artisan cooker:add <name>.
License
MIT — see LICENSE.
Related Packages
Laravel named routes for SPA frontends: per-tier lazy loading via an HTTP metada...
Laravel Localizer bridges Laravel translations to your SPA frontend (React/Vue/I...
Composable, enterprise-grade project scaffolding CLI for Laravel applications.
A multi-framework UI component library for Laravel. Supports Tailwind CSS, Boots...
Version History
| Version | Released | PHP | License |
|---|---|---|---|
| 10.0.0 | >=8.3 | MIT | |
| 8.1.0 | >=8.3 | MIT | |
| 8.0.7 | >=8.3 | MIT | |
| 8.0.0 | >=8.3 | MIT | |
| 7.0.5 | >=8.2 | MIT | |
| 7.0.4 | >=8.2 | MIT | |
| 7.0.3 | >=8.2 | MIT | |
| 7.0.2 | >=8.2 | MIT | |
| 7.0.1 | >=8.2 | MIT | |
| 7.0.0 | >=8.2 | MIT | |
| 6.0.5 | >=8.1 | MIT | |
| 6.0.4 | >=8.1 | MIT | |
| 6.0.3 | >=8.1 | MIT | |
| 6.0.2 | >=8.1 | MIT | |
| 6.0.0 | >=8.2 | MIT | |
| 5.0.0 | >=8.0 | MIT | |
| 4.1.5 | >=8.0 | MIT | |
| 4.1.4 | >=8.0 | MIT | |
| 4.1.3 | >=8.0 | MIT | |
| 4.1.2 | >=7.4 | MIT | |
| 4.1.1 | >=7.4 | MIT | |
| 4.1.0 | >=7.4 | MIT | |
| 4.0.8 | >=7.3 | MIT | |
| 4.0.7 | >=7.3 | MIT | |
| 4.0.6 | >=7.3 | MIT | |
| 3.3.0 | >=7.3 | MIT | |
| 3.2.2 | >=7.3 | MIT | |
| 3.0.2 | >=7.3 | MIT | |
| 2.3.0 | >=7.0 | MIT | |
| 2.2.1 | >=7.0 | MIT |
Showing the latest 30 of 38. See every release on Packagist