Creating a Laravel Preset Package, Part Two

Published September 23rd, 2018
12 minute read
Warning!
This was written over two years ago, so some information might be outdated. Frameworks and best practices change. The web moves fast! You may need to adjust a few things if you follow this article word for word.

We'll add some custom functionality to the composer package we created in part one to create a Laravel boilerplate with things set up just how we prefer.

Part Two, Doing the Work

What We'll Cover

We will cover how to configure the preset to remove compiled files from version control
and have it automatically set up a better default layout for Laravel

Our first order of business will be to remove compiled assets from version control :skull:. Storing minified files in our git repository should be avoided. Since we can automatically generate those files with our build process, they aren't true "source" files.

A convention many of the community presets adopt is storing the new versions of files within our package's src/stubs directory, so we'll follow that with our example too.

Create a file at src/stubs/new-gitignore containing the following:

1/node_modules
2/public/hot
3/public/storage
4/public/css
5/public/js
6/public/mix-manifest.json
7/storage/*.key
8/vendor
9/.idea
10/.vscode
11/.vagrant
12Homestead.json
13Homestead.yaml
14npm-debug.log
15yarn-error.log
16.env
17.phpunit.result.cache
1/node_modules
2/public/hot
3/public/storage
4/public/css
5/public/js
6/public/mix-manifest.json
7/storage/*.key
8/vendor
9/.idea
10/.vscode
11/.vagrant
12Homestead.json
13Homestead.yaml
14npm-debug.log
15yarn-error.log
16.env
17.phpunit.result.cache

We just added the public/css, public/js, and public/mix-manifest.json paths on top of Laravel's default.

Now tell our Preset class to replace the default .gitignore file.
Open up the src/Preset.php file and update the install() method with the following.

1public static function install()
2{
3 // Replace the default .gitignore with our own
4 copy(__DIR__ . '/stubs/new-gitignore', base_path('.gitignore'));
5}
1public static function install()
2{
3 // Replace the default .gitignore with our own
4 copy(__DIR__ . '/stubs/new-gitignore', base_path('.gitignore'));
5}

If we were to run php artisan preset austencam we should see the changes get made to our main app's .gitignore file, pretty slick!

Let's do something more interesting now, like replacing the default views with a simple "app" layout.

Add a new file at this location in our package: src/resources/views/layouts/app.blade.php:

1<!DOCTYPE html>
2<html lang="{{ app()->getLocale() }}">
3 <head>
4 <meta charset="utf-8" />
5 <meta http-equiv="X-UA-Compatible" content="IE=edge" />
6 <meta name="viewport" content="width=device-width, initial-scale=1" />
7 <meta name="csrf-token" content="{{ csrf_token() }}" />
8 <!--
9 Note: I'm pulling Tailwind CSS from the CDN to shorten this tutorial
10 but most apps will want to build it with their own config, see
11 https://tailwindcss.com/docs/installation for more details.
12 -->
13 <link
14 href="https://cdn.jsdelivr.net/npm/tailwindcss/dist/tailwind.min.css"
15 rel="stylesheet"
16 />
17 <title>{{ config('app.name', 'Laravel') }}</title>
18 </head>
19 <body class="font-sans text-green antialiased text-grey-dark">
20 <div id="app">@yield('body')</div>
21 </body>
22</html>
1<!DOCTYPE html>
2<html lang="{{ app()->getLocale() }}">
3 <head>
4 <meta charset="utf-8" />
5 <meta http-equiv="X-UA-Compatible" content="IE=edge" />
6 <meta name="viewport" content="width=device-width, initial-scale=1" />
7 <meta name="csrf-token" content="{{ csrf_token() }}" />
8 <!--
9 Note: I'm pulling Tailwind CSS from the CDN to shorten this tutorial
10 but most apps will want to build it with their own config, see
11 https://tailwindcss.com/docs/installation for more details.
12 -->
13 <link
14 href="https://cdn.jsdelivr.net/npm/tailwindcss/dist/tailwind.min.css"
15 rel="stylesheet"
16 />
17 <title>{{ config('app.name', 'Laravel') }}</title>
18 </head>
19 <body class="font-sans text-green antialiased text-grey-dark">
20 <div id="app">@yield('body')</div>
21 </body>
22</html>

This is a simple layout our app's views can inherit from. The default welcome.blade.php the framework comes with is meant to be ripped out in favor of your favorite frontend framework anyway, so let's make our new welcome view use the new layout.

Create a file at src/stubs/resources/views/welcome.blade.php with this code:

1@extends('layouts.app') @section('body')
2<div class="min-h-screen flex items-center justify-center">
3 <h1 class="text-3xl">Build Something Great!</h1>
4</div>
5@endsection
1@extends('layouts.app') @section('body')
2<div class="min-h-screen flex items-center justify-center">
3 <h1 class="text-3xl">Build Something Great!</h1>
4</div>
5@endsection

The only thing left to do is tell our preset to copy these files over. Open up the src/Preset.php file and add the following use statement.

1use Illuminate\Filesystem\Filesystem;
1use Illuminate\Filesystem\Filesystem;

Now update the install() method in our src/Preset.php file to match this code:

1 public static function install()
2 {
3 // Replace the default .gitignore with our own
4 copy(__DIR__ . '/stubs/new-gitignore', base_path('.gitignore'));
5 
6 // Delete the default view and copy our stub views into place
7 tap(new Filesystem, function ($files) {
8 $files->delete(resource_path('views/welcome.blade.php'));
9 $files->copyDirectory(__DIR__.'/stubs/resources/views', resource_path('views'));
10 });
11 }
12}
1 public static function install()
2 {
3 // Replace the default .gitignore with our own
4 copy(__DIR__ . '/stubs/new-gitignore', base_path('.gitignore'));
5 
6 // Delete the default view and copy our stub views into place
7 tap(new Filesystem, function ($files) {
8 $files->delete(resource_path('views/welcome.blade.php'));
9 $files->copyDirectory(__DIR__.'/stubs/resources/views', resource_path('views'));
10 });
11 }
12}

So let's break down the code we added there (starting with tap). Some of you may be thinking "whoa, what the heck is tap?". Tap is a helper function that allows us to easily string together groups of actions without needing to use a temporary variable. It's a matter of personal preference really... I think of it as "we're taking a filesystem object, and performing these actions with it", so using tap makes a lot of sense in this context.

Here are a couple other ways we could've written these lines:

1// One way
2$files = new Filesystem;
3$files->delete(...);
4$files->copyDirectory(...);
5 
6// Another way.. but not the same object :(
7(new Filesystem)->delete(...);
8(new Filesystem)->copyDirectory(...);
1// One way
2$files = new Filesystem;
3$files->delete(...);
4$files->copyDirectory(...);
5 
6// Another way.. but not the same object :(
7(new Filesystem)->delete(...);
8(new Filesystem)->copyDirectory(...);

Anyway, run our php artisan preset austencam command again. We should see our new views in the resources/views folder of the main app. Feel free to open up your app in the browser and check it out too!

Now we've got an idea of how to build any Laravel preset / boilerplate we want. Taking this knowledge further, your preset might contain custom vue components, the CSS framework of your choice, or any number of other customizations!

Let's Review

We've covered how to create a composer package in part one, how to extend the php artisan preset command with our own preset, and how to configure that preset to set up a new app just how we'd like it. Now we can easily require our package from any Laravel app and to set up the app like we want in seconds. This is a great way to create your own boilerplate so you can more rapidly iterate on your ideas. Looking forward to seeing what you folks come up with!

Although my real preset does a few more things, I kept it simple for the sake of focusing on the process in this article. Laravel's base Preset class also includes a few useful methods you'll want to check out if you're building your own preset.

Please, if you run into problems or have any questions, feel free to reach out to me on twitter. I'd love to help. Thanks!

Enjoy this article? Follow me on Twitter for more tips, articles and links.
😢 Awww, nobody has liked or mentioned this on Twitter yet.

Want Updates?

Sign up here if you want to stay in the loop about new articles or products I'm making.
I'll never spam you. Unsubscribe at any time.
Copyright ©2024 Austen Cameron