Configure Laravel to work in a SubDirectory and with artisan serve at the same time
When you use Laravel to work with shared hosting, one of the main problems is that you can not configure a host directly to the public folder.
Our scenario is the same:
Development environment:
Use the base Laravel configuration with no change, in this way you can use artisan serve or valet to serve your app.
root@localmachine:~# php artisan serve
Production environment:
Add the fix showed below to allow Laravel to work on a subdirectory, usually served by Apache installation.
Let’s started, redirect all the request!
First of all, create a .htaccess file in root folder of your Laravel app, this file will redirect all request to the public folder of your app, this comes out of the box if you use valet or artisan serve.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^(.*)$ public/$1 [L]
</IfModule>
Now, if you try to access your app in a subfolder:
http://localhost/laravel_subdir
all works fine, but if you use asset or mix function, they will return a wrong path, for example:
asset('css/app.css')
will return:
http://localhost/css/app.css
This because the asset and mix functions use baseRoot to build a path, this is right using valet or artisan serve, but wrong with apache. Our goals it’s to write one code that works in both environments.
Here the trick!
Add APP_DIR environment variable to your .env file, containing the subdirectory where Laravel is installed into, like showed below:
APP_NAME=Laravel
APP_ENV=local
APP_DIR = "laravel_subdir"
APP_KEY=base64:56qPq0000qqQv3yAo000NmCH83yEUS6nFRb8Fj0/PyI=
APP_DEBUG=true
APP_URL=http://localhost/laravel_subdir
Then create a Helper Provider to define our custom functions, create a file HelperServiceProvider.php inside Providers directory, with the following code:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;class HelperServiceProvider extends ServiceProvider{/**
* Bootstrap services.
*
* @return void
*/
public function boot(){}/**
* Register services.
*
* @return void
*/
public function register(){ foreach (glob(app_path() . '/Helpers/*.php') as $file) { require_once($file); }}
}
Then, at the level of App directory, add Helpers directory, and inside it, create a file SubdirectoryAssetsHelper.php, with the following code:
<?phpif (! function_exists('subdirAsset')) {function subdirAsset($path){return asset( (App::environment('production') ? env('APP_DIR') : '')."/".$path);}}if (! function_exists('subdirMix')) {function subdirMix($path){return mix( (App::environment('production') ? env('APP_DIR') : '')."/".$path);}}
Now register the provider by adding this line to config/app.php file:
App\Providers\HelperServiceProvider::class,
Now replace the function mapWebRoutes of file RouteServiceProvider.php, like showed below:
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*
* @return void
*/protected function mapWebRoutes(){ Route::prefix(App::environment('production') ? env('APP_DIR') : '') ->middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));}
And import App class in top of file:
use App;
That’s all, now you can use function subdirAsset instead of asset and subdirMix instead of mix inside your blade files.
Switch environment
If you are using valet or artisan serve, keep your APP_ENV variable to “local”:
APP_ENV = local
If you are in a production environment of shared hosting, use:
APP_ENV = production
Demo
Please clone my demo repo at: https://github.com/lucabecchetti/laravel_subdir