vendor and env first commit
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
namespace Vanguard\Plugins\Console\Commands;
|
||||
|
||||
use Illuminate\Contracts\Filesystem\FileNotFoundException;
|
||||
use Symfony\Component\Process\Exception\ProcessFailedException;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
class GeneratePluginCommand extends PluginCommand
|
||||
{
|
||||
/**
|
||||
* The console command name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'vanguard:make-plugin';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Scaffold all the necessary files for the new plugin.';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
if ($this->pluginExists($this->pluginPath())) {
|
||||
$this->error('Plugin already exists!');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->warn('Generating plugin folder structure...');
|
||||
$this->generateFolderStructure();
|
||||
$this->generateFiles();
|
||||
$this->info('Plugin folder structure generated successfully.');
|
||||
|
||||
$this->warn('Installing plugin as a local composer dependency...');
|
||||
$this->updateApplicationComposerFile();
|
||||
$this->installPlugin();
|
||||
$this->info('Plugin installed successfully.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the plugin folder structure.
|
||||
*/
|
||||
private function generateFolderStructure(): void
|
||||
{
|
||||
$pluginPath = $this->pluginPath();
|
||||
|
||||
foreach ($this->getFolders() as $folder) {
|
||||
$this->makeDirectory($pluginPath."/{$folder}");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of folders to create.
|
||||
*/
|
||||
protected function getFolders(): array
|
||||
{
|
||||
return [
|
||||
'database/factories',
|
||||
'database/migrations',
|
||||
'database/seeds',
|
||||
'resources/views',
|
||||
'routes',
|
||||
'src/Http/Controllers/Api',
|
||||
'src/Http/Controllers/Web',
|
||||
'src/Http/Requests',
|
||||
'tests',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate necessary plugin files.
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
private function generateFiles(): void
|
||||
{
|
||||
$pluginPath = $this->pluginPath();
|
||||
|
||||
foreach ($this->getFiles() as $stubPath => $filePath) {
|
||||
$this->makeDirectory($pluginPath."/{$filePath}");
|
||||
|
||||
$stub = $this->files->get(__DIR__.'/stubs/'.$stubPath);
|
||||
$stub = $this->replacePlaceholders($stub);
|
||||
|
||||
$this->files->put($pluginPath."/{$filePath}", $stub);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of files that should be created for the plugin.
|
||||
*/
|
||||
protected function getFiles(): array
|
||||
{
|
||||
return [
|
||||
'routes/web.stub' => 'routes/web.php',
|
||||
'routes/api.stub' => 'routes/api.php',
|
||||
'views/index.stub' => 'resources/views/index.blade.php',
|
||||
'config.stub' => 'config/config.php',
|
||||
'composer.stub' => 'composer.json',
|
||||
'assets/js/app.stub' => 'resources/assets/js/app.js',
|
||||
'assets/sass/app.stub' => 'resources/assets/sass/app.scss',
|
||||
'webpack.stub' => 'webpack.mix.js',
|
||||
'package.stub' => 'package.json',
|
||||
'unit-test.stub' => 'tests/Unit/ExampleTest.php',
|
||||
'feature-test.stub' => 'tests/Feature/FeatureTest.php',
|
||||
'gitignore.stub' => '.gitignore',
|
||||
'plugin.stub' => 'src/'.$this->studlyName().'.php',
|
||||
'controller.stub' => 'src/Http/Controllers/Web/'.$this->studlyName().'Controller.php',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace placeholders within the stub files.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function replacePlaceholders(string $stub)
|
||||
{
|
||||
return str_replace(
|
||||
[
|
||||
'$ROOT_NAMESPACE$',
|
||||
'$PLUGIN_NAMESPACE$',
|
||||
'$VENDOR$',
|
||||
'$AUTHOR_NAME$',
|
||||
'$AUTHOR_EMAIL$',
|
||||
'$SNAKE_NAME$',
|
||||
'$STUDLY_NAME$',
|
||||
],
|
||||
[
|
||||
$this->rootNamespace(),
|
||||
$this->pluginNamespace(),
|
||||
config('plugins.composer.vendor'),
|
||||
config('plugins.composer.author.name'),
|
||||
config('plugins.composer.author.email'),
|
||||
$this->snakeName(),
|
||||
$this->studlyName(),
|
||||
],
|
||||
$stub
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the main application composer file to include the
|
||||
* newly generated plugin.
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
private function updateApplicationComposerFile(): void
|
||||
{
|
||||
$composer = json_decode($this->files->get(base_path('composer.json')), true);
|
||||
|
||||
$composer['repositories'][] = [
|
||||
'type' => 'path',
|
||||
'url' => './plugins/'.$this->studlyName(),
|
||||
];
|
||||
|
||||
$this->files->put(
|
||||
base_path('composer.json'),
|
||||
json_encode($composer, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Install the plugin via composer.
|
||||
*/
|
||||
private function installPlugin(): void
|
||||
{
|
||||
$pluginFullName = sprintf('%s/%s', config('plugins.composer.vendor'), $this->snakeName());
|
||||
|
||||
$command = Process::fromShellCommandline("composer require {$pluginFullName} \"*\"");
|
||||
|
||||
$command->setWorkingDirectory(base_path());
|
||||
|
||||
$command->run();
|
||||
|
||||
if (! $command->isSuccessful()) {
|
||||
throw new ProcessFailedException($command);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace Vanguard\Plugins\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Illuminate\Support\Str;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
|
||||
abstract class PluginCommand extends Command
|
||||
{
|
||||
/**
|
||||
* Create a new controller creator command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected Filesystem $files)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the console command arguments.
|
||||
*/
|
||||
protected function getArguments(): array
|
||||
{
|
||||
return [
|
||||
['name', InputArgument::REQUIRED, 'The name of the plugin.'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the desired class name from the input.
|
||||
*/
|
||||
protected function getNameInput(): string
|
||||
{
|
||||
return trim($this->argument('name'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root namespace for the class.
|
||||
*/
|
||||
protected function rootNamespace(): string
|
||||
{
|
||||
return rtrim($this->laravel->getNamespace(), '\\');
|
||||
}
|
||||
|
||||
/**
|
||||
* The namespace of the plugin itself.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function pluginNamespace()
|
||||
{
|
||||
return sprintf("%s\%s", $this->rootNamespace(), $this->studlyName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the directory for the class if necessary.
|
||||
*/
|
||||
protected function makeDirectory(string $path): string
|
||||
{
|
||||
if (! $this->files->isDirectory(dirname($path))) {
|
||||
$this->files->makeDirectory(dirname($path), 0777, true, true);
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* The path to the plugin directory.
|
||||
*/
|
||||
protected function pluginPath(): string
|
||||
{
|
||||
$name = Str::replaceFirst($this->rootNamespace(), '', $this->getNameInput());
|
||||
|
||||
return $this->laravel['path.base'].'/plugins/'.str_replace('\\', '/', Str::studly($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if plugin exists on a given path.
|
||||
*
|
||||
* @param string $pluginPath
|
||||
*/
|
||||
protected function pluginExists($pluginPath): bool
|
||||
{
|
||||
return $this->files->exists($pluginPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the plugin in StudlyCase format.
|
||||
*/
|
||||
protected function studlyName(): string
|
||||
{
|
||||
return Str::studly($this->getNameInput());
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the plugin in snake-case format.
|
||||
*/
|
||||
protected function snakeName(): string
|
||||
{
|
||||
return Str::snake($this->getNameInput(), '-');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace Vanguard\Plugins\Console\Commands;
|
||||
|
||||
use Symfony\Component\Process\Exception\ProcessFailedException;
|
||||
use Symfony\Component\Process\Process;
|
||||
use Vanguard\Plugins\Vanguard;
|
||||
|
||||
class RemovePluginCommand extends PluginCommand
|
||||
{
|
||||
/**
|
||||
* The console command name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'vanguard:remove-plugin';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Removes the specified plugin from the system.';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
if (! $this->pluginExists($this->pluginPath())) {
|
||||
$this->error("The plugin [{$this->studlyName()}] does not exist.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->pluginIsStillActive()) {
|
||||
$message = "The [{$this->studlyName()}] plugin is still active. Please remove it from the list of active";
|
||||
$message .= ' plugins inside the VanguardServiceProvider first.';
|
||||
$this->error($message);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->warn("Removing [{$this->studlyName()}] plugin...");
|
||||
$this->files->deleteDirectory($this->pluginPath());
|
||||
$this->updateApplicationComposerFile();
|
||||
$this->uninstallPluginDependency();
|
||||
$this->info('Plugin removed successfully.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the plugin that should be deleted is still active.
|
||||
*/
|
||||
private function pluginIsStillActive(): bool
|
||||
{
|
||||
$pluginClassName = sprintf(
|
||||
"%s\%s",
|
||||
$this->pluginNamespace(),
|
||||
$this->studlyName()
|
||||
);
|
||||
|
||||
return isset(Vanguard::availablePlugins()[$pluginClassName]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall plugin composer dependency.
|
||||
*/
|
||||
private function uninstallPluginDependency(): void
|
||||
{
|
||||
$pluginFullName = sprintf('%s/%s', config('plugins.composer.vendor'), $this->snakeName());
|
||||
|
||||
$command = Process::fromShellCommandline("composer remove {$pluginFullName}");
|
||||
$command->setWorkingDirectory(base_path());
|
||||
$command->run();
|
||||
|
||||
if (! $command->isSuccessful()) {
|
||||
throw new ProcessFailedException($command);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the main application composer file and remove
|
||||
* the reference to the plugin.
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
|
||||
*/
|
||||
private function updateApplicationComposerFile(): void
|
||||
{
|
||||
$composer = json_decode($this->files->get(base_path('composer.json')), true);
|
||||
|
||||
$composer['repositories'] = collect($composer['repositories'])->filter(function ($repo) {
|
||||
return ! isset($repo['url']) || $repo['url'] != './plugins/'.$this->studlyName();
|
||||
})->toArray();
|
||||
|
||||
$this->files->put(
|
||||
base_path('composer.json'),
|
||||
json_encode($composer, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "$VENDOR$/$SNAKE_NAME$",
|
||||
"description": "",
|
||||
"authors": [
|
||||
{
|
||||
"name": "$AUTHOR_NAME$",
|
||||
"email": "$AUTHOR_EMAIL$"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"$ROOT_NAMESPACE$\\$STUDLY_NAME$\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"$ROOT_NAMESPACE$\\$STUDLY_NAME$\\Tests\\": "tests/"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
//
|
||||
];
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace $PLUGIN_NAMESPACE$\Http\Controllers\Web;
|
||||
|
||||
use Vanguard\Http\Controllers\Controller;
|
||||
|
||||
class $STUDLY_NAME$Controller extends Controller
|
||||
{
|
||||
/**
|
||||
* Displays the plugin index page.
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('$SNAKE_NAME$::index');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace $PLUGIN_NAMESPACE$\Tests\Feature;
|
||||
|
||||
use Tests\TestCase;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
class ExampleTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* A basic test example.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testBasicTest()
|
||||
{
|
||||
$response = $this->get('/');
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/dist
|
||||
/.idea
|
||||
/vendor
|
||||
/node_modules
|
||||
package-lock.json
|
||||
composer.phar
|
||||
composer.lock
|
||||
phpunit.xml
|
||||
.phpunit.result.cache
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "npm run development",
|
||||
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
|
||||
"watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
|
||||
"watch-poll": "npm run watch -- --watch-poll",
|
||||
"hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
|
||||
"prod": "npm run production",
|
||||
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env": "^5.1.4",
|
||||
"laravel-mix": "^2.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace $PLUGIN_NAMESPACE$;
|
||||
|
||||
use Route;
|
||||
use Illuminate\Database\Eloquent\Factory;
|
||||
use Vanguard\Plugins\Plugin;
|
||||
use Vanguard\Support\Sidebar\Item;
|
||||
|
||||
class $STUDLY_NAME$ extends Plugin
|
||||
{
|
||||
/**
|
||||
* A sidebar item for the plugin.
|
||||
*/
|
||||
public function sidebar(): ?Item
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register plugin services required.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap services.
|
||||
*
|
||||
* @return void
|
||||
* @throws \Illuminate\Contracts\Container\BindingResolutionException
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
$this->registerConfig();
|
||||
$this->registerViews();
|
||||
$this->registerFactories();
|
||||
$this->loadMigrationsFrom(__DIR__ . '/../database/migrations');
|
||||
|
||||
$this->loadViewsFrom(__DIR__ . '/../resources/views', '$SNAKE_NAME$');
|
||||
$this->loadMigrationsFrom(__DIR__ . '/../database/migrations');
|
||||
|
||||
$this->mapRoutes();
|
||||
|
||||
$this->registerFactories();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register plugin configuration files.
|
||||
*/
|
||||
protected function registerConfig(): void
|
||||
{
|
||||
$configPath = __DIR__.'/../config/config.php';
|
||||
|
||||
$this->publishes([$configPath => config_path('$SNAKE_NAME$.php')], 'config');
|
||||
|
||||
$this->mergeConfigFrom($configPath, '$SNAKE_NAME$');
|
||||
}
|
||||
|
||||
/**
|
||||
* Register plugin views.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerViews(): void
|
||||
{
|
||||
$viewsPath = __DIR__.'/../resources/views';
|
||||
|
||||
$this->publishes([
|
||||
$viewsPath => resource_path('views/plugins/$SNAKE_NAME$')
|
||||
], 'views');
|
||||
|
||||
$this->loadViewsFrom($viewsPath, '$SNAKE_NAME$');
|
||||
}
|
||||
|
||||
/**
|
||||
* Map all plugin related routes.
|
||||
*/
|
||||
protected function mapRoutes(): void
|
||||
{
|
||||
$this->mapWebRoutes();
|
||||
|
||||
if ($this->app['config']->get('auth.expose_api')) {
|
||||
$this->mapApiRoutes();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map web plugin related routes.
|
||||
*/
|
||||
protected function mapWebRoutes(): void
|
||||
{
|
||||
Route::group([
|
||||
'namespace' => '$PLUGIN_NAMESPACE$\Http\Controllers\Web',
|
||||
'middleware' => 'web',
|
||||
], function () {
|
||||
$this->loadRoutesFrom(__DIR__ . '/../routes/web.php');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Map API plugin related routes.
|
||||
*/
|
||||
protected function mapApiRoutes(): void
|
||||
{
|
||||
Route::group([
|
||||
'namespace' => '$PLUGIN_NAMESPACE$\Http\Controllers\Api',
|
||||
'middleware' => 'api',
|
||||
'prefix' => 'api',
|
||||
], function () {
|
||||
$this->loadRoutesFrom(__DIR__ . '/../routes/api.php');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Illuminate\Contracts\Container\BindingResolutionException
|
||||
*/
|
||||
private function registerFactories(): void
|
||||
{
|
||||
if (! $this->app->environment('production') && $this->app->runningInConsole()) {
|
||||
$this->app->make(Factory::class)->load(__DIR__ . '/../database/factories');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| API Routes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you can register API routes for your application.
|
||||
| Enjoy building your API!
|
||||
|
|
||||
*/
|
||||
|
||||
Route::get('/$SNAKE_NAME$', function (Request $request) {
|
||||
return $request->user();
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Web Routes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you can register web routes for your application.
|
||||
| Now create something great!
|
||||
|
|
||||
*/
|
||||
|
||||
Route::prefix('$SNAKE_NAME$')->group(function () {
|
||||
Route::get('/', '$STUDLY_NAME$Controller@index')->middleware('auth');
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace $PLUGIN_NAMESPACE$\Tests\Unit;
|
||||
|
||||
use Tests\TestCase;
|
||||
use Illuminate\Foundation\Testing\WithFaker;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
class ExampleTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* A basic unit test example.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testExample()
|
||||
{
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('page-title', '$STUDLY_NAME$')
|
||||
@section('page-heading', '$STUDLY_NAME$')
|
||||
|
||||
@section('breadcrumbs')
|
||||
<li class="breadcrumb-item active">
|
||||
$STUDLY_NAME$
|
||||
</li>
|
||||
@stop
|
||||
|
||||
@section('content')
|
||||
<p>
|
||||
This view is loaded from <strong>$STUDLY_NAME$</strong> plugin.
|
||||
</p>
|
||||
@stop
|
||||
@@ -0,0 +1,10 @@
|
||||
const mix = require('laravel-mix');
|
||||
|
||||
mix.setPublicPath('./dist/');
|
||||
|
||||
mix.js( __dirname + '/resources/assets/js/app.js', 'dist/js/announcements.js')
|
||||
.sass( __dirname + '/resources/assets/sass/app.scss', 'dist/css/announcements.css');
|
||||
|
||||
if (mix.inProduction()) {
|
||||
mix.version();
|
||||
}
|
||||
Reference in New Issue
Block a user