Laravel 5.4 MIX : Alternative way to perform a versionning of compiled files
A little introduction:
Since I upgraded to laravel 5.4, I start using Node and Assets. Before the last week, I was always putting my files directly into public directory. I builded a custom code to versionised my files. Since I moved everything to assets and start using mix.combine(), my versionning system is depracated. I read a bit about how things work with node and found on several discussion that version() and compile() can't be used at the same time. That became a problem.
Alternative way:
I called this an alternative way, because I don't know how to create node package or modify existing one... Yet... So, instead of modifying the core of laravel.mix(), I prefered to create some Artisan command to do something similar.
Goal :
The goal persue with this discussion is to show you how I manage to version all my compile file and integrate it to laravel.mix(). We still want to call our url this way :
{{mix('/css/app.css')}}
How :
What I did is creating 4 new Artisan command. The first three commands are to do each step and the last one is regrouping the three others. Going this way, we can call one Artisan command and it will clear files, compile the new one then version them. Simply use this command :
php artisan morino:version {dev|production}
Right now, it does'nt handle the HOT or WATCH.
Step 1: Adding new command
Run this in your terminal:
php artisan make:command MorinoClear
php artisan make:command MorinoNpmRun
php artisan make:command MorinoCreate
php artisan make:command MorinoVerison
After this you will need to add those command into your Kernel.php :
Commands\MorinoVersion::class,
Commands\MorinoClear::class,
Commands\MorinoNpmRun::class,
Commands\MorinoCreate::class,
OPTIONNAL
Create a new disk into your filesystem config and use the Storage facade. If you don't to this, you will need to change my code. Add this to config/filesystem.php :
'morino' => [
'driver' => 'local',
'root' => public_path(),
],
Step 2: Add a global string generating function.
You will need to add a function accessible from anywhere. The function will be used to create your version. I added it to an existing file. There is the function :
function genRandStr($length) {
return substr(str_shuffle(str_repeat($x='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length/strlen($x)) )),1,$length);
}
Step 3: Create each Artisan command
This step is straigth foward, just copy paste each block of code into the corresponding command. app/console/commands/MorinoClear.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
class MorinoClear extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'morino:clear';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This command will version clear every files by laravel:mix';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$json = file_get_contents("public/mix-manifest.json");
$files = json_decode($json, true);
foreach ($files as $key => $val) {
if (Storage::disk('morino')->exists($val)) {
Storage::disk('morino')->delete($val);
}
}
$this->info('Cleared!');
}
}
app/console/commands/MorinoNpmRun.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class MorinoNpmRun extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'morino:npm-run {env : Your current environment}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Artisan command to execute npm run "env".';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$exec = shell_exec('npm run '.$this->argument('env'));
$this->info('New files were created!');
}
}
app/console/commands/MorinoCreate.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
class MorinoCreate extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'morino:create';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This command will version every non versionned file by laravel:mix';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$json = file_get_contents("public/mix-manifest.json");
$file = json_decode($json, true);
foreach ($file as $key => $val) {
$a = explode('.', $val);
if (strlen($a[1]) != 20) {
$rand = genRandStr(20);
for ($i=0; $i <= count($a) ; $i++) {
if ($i == 0) {$new=$a[0];}
if ($i == 1) {$new.='.'.$rand;}
if ($i >= 2) {$j = $i-1;$new.='.'.$a[$j];}
}
Storage::disk('morino')->move($val, $new);
$file[$key] = $new;
} else {
}
}
$json = json_encode($file, true);
file_put_contents('public/mix-manifest.json', $json);
$this->info('All files have been versionned!');
}
}
app/console/commands/MorinoVersion.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
//use Log;
use Artisan;
class MorinoVersion extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'morino:version {env : Your current environment}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'RECOMMENDED - Do everything to version your files.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$env = $this->argument('env');
Artisan::call('morino:clear');
$this->info('Cleared!');
Artisan::call('morino:npm-run',['env' => $this->argument('env')]);
$this->info('New files were created!');
Artisan::call('morino:create');
$this->info('All files have been versionned!');
}
}
Step 6 : Enjoy!
Just run aphp artisan morino:version {dev|production} and everything will be handled as usual, but now your compiled files will be versionnised. Just call them with a {{mix(files.ext)}}.
Please leave any comment and/or suggestion. This will be appreciate and it's one of the first time that I suggest something to help people.
Please or to participate in this conversation.