The Laravel-native frontend toolkit. Tailwind, React, Vue, TS — without the Node baggage.
genericmilk/cooker is a Laravel package for the laravel-native frontend toolkit. tailwind, react, vue, ts — without the node baggage..
It currently has 6 GitHub stars and 6.688 downloads on Packagist (latest version 10.0.0).
Install it with composer require genericmilk/cooker.
Discover more Laravel packages by genericmilk
or browse all Laravel packages to compare alternatives.
Last updated
Cooker is the Laravel-native frontend toolkit. It gives you Tailwind, React, Vue, TypeScript and JSX/TSX bundling — all driven from php artisan, with no Node, no npm, no node_modules and no package-lock.json in your project.
Cooker auto-downloads the binaries it needs (esbuild, tailwindcss) into .cooker/bin. npm packages are fetched directly from the registry and stored flat in .cooker/packages. Built assets are written to public/build as static files with hashed names.
@cooker directiveIf 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.
esbuild and tailwindcss as standalone binaries.node_modules. Packages live flat at .cooker/packages/<name>/. Cooker resolves transitive deps for you.php artisan cooker:add react installs React + ReactDOM and scaffolds a working App.jsx.@cooker('app.js') and @cooker('app.css') Just Work.public/build/*.js is served by your web server like any other static file.composer require genericmilk/cooker
php artisan cooker:install
The installer will:
config/cooker.php..cooker/ (bin, cache, packages) and add it to .gitignore.resources/js/app.js and resources/css/app.css.esbuild for your platform.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
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.
.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.
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',
],
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
@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="https://raw.githubusercontent.com/genericmilk/cooker/refs/heads/main/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.
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.
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.
<link> tag, no full reload.location.reload().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.
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'),
],
];
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 delete config/cooker.php and .cooker/ manually.php artisan cooker:install.resources/js/app.js / resources/css/app.css entry files and add real import statements.cooker-toolbelt / cooker-routes imports — they're not part of Cooker 10.esm.run, run php artisan cooker:add <name>.MIT — see LICENSE.