So you decided that
Laravel is a great choice for a backend and that
Angular is going to fit perfectly as the framework of choice for the frontend. Yeah! That is correct and I am starting to like you.
How to start? So many question, so little time (someone said :P)
Before we start, let me explain a little bit the different options we have for combining this two.
Isn’t there a perfect solution which work in any case? No. It all depend on the project itself and the use case. I am going to show here my opinions about the subject.
Let’s start with the option of letting
Angular for you.
- It is the simplest way of combining this two.
- In development, it is easier to communicate the
Laravel. There is no need of CORS or proxies.
- Makes deployment a breeze. Just tell
forgeto compile the angular before doing any deployment and you are good to go.
- It is perfect for newbies and you can always move to other workflows later without problem if needed.
- Perfect for small projects and pet projects. I even see big projects using this workflow tho.
- Since everything is inside the same domain, you just need one SSL certificate, ideal for pet projects.
- We can easily bootstrap data from
Laravelat startup with some minimum changes to this workflow.
- It is a little bit (just a little) coupled. Letting
Angularcouples the solution a little bit. It could be problematic for some kind of projects.
- If you want to change the frontend, you need to delete everything you created for
Angularbut luckily for us, you just need to delete one folder.
- If you want to change the backend, you need to move that folder somewhere else.
Angular in one domain (
Laravel in another domain (
- Totally decoupled, they know nothing of each other, so we have complete freedom.
- You can swap
Angularin a breeze.
- Works for big projects without problem.
- Maybe little bit more daunting if you’re just starting to learn
- You need two SSL certificates, I know, they are cheap but if you just have a pet project, you don’t want to pay double (not a problem if it is an enterprise project).
- Communication between both of them, even when still easy, needs more work (which is not handy for newbies).
There is a middleground between both, having them separate but inside the same domain (
- Easy to deploy
- You just need one SSL certificate.
- If you’re using
Homesteadyou will need to craft your own
nginxconfig in the new applications.
- Makes API versioning maybe a little bit more complicated.
In my opinion, the first way works really good, it is done in a lot of different backends (just google about XXX + angular) and you will see a lot of people doing it. There is nothing wrong with it.
If you feel that your project is going to be big and you prefer a complete and total separation there, that is also awesome, you can do it.
So the TL;DR here is that there are a couple of ways (and more I didn’t mention here) and luckily we have the freedom of picking the one who fits our project. But before doing that, we need to learn how to use them :)
So for this first article, we are going to use the first way
So, right from the beginning:
Blimey! We arrived. Thank you reading this article.
No, wait, we forgot the Angular part.
As I said before, we are going to follow the first approach here, so I prepared a little workflow here that we can use to accomplish this easily.
Assuming we are on the directory of our
Laravel application we do:
1 2 3
To use the
Angular workflow we just need to clone it on the application root and install its dependencies. We can choose any name for the workflow, I chose
angular because it is a pretty obvious name. You can clone it on the
/app directory if you wish (check the workflow repository for more information).
Let’s create a git repo for our project. From the root directory we:
We delete the repository that comes with the workflow and we create a new one for the whole application, then we modify our
.gitignore to support our
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Ignoring those ignores for now, we can now commit:
Now assuming we have a remote repository (I have mine for this project here):
Alright, everything is set in place, let’s do a
Hello World first to see everthing working.
First, we just need to start
gulp which is going to do all the heavy lifting for us:
And then we modify our
index.html file to put that
1 2 3 4 5 6 7 8 9 10 11 12
Here we have the message with a little angular to prove it is working. Notice that the
ng-app is already set for us.
Also, don’t be scared with those
<%= ... %> placeholders, that is for the
cache-busting and we don’t need to worry about that.
If you take a look to our
/public folder (the
Laravel one) we can see:
There is our compiled
angular application! (In concrete, the
js folders along the
angular.html instead of
index.html? Well, the
nginx could load that for us and in a first sight there is no issue, but I am not an experienced
Laravel developer so it could have some side effect and I don’t want that. Changing the name to
angular.html will prevent that.
Great, but if we run our application…
Uh, what happened with our
Hello World ?
Well, nothing, the question is… Who is routing it?
Laravel knows nothing about that file, we need to create a route for it:
1 2 3 4
We delete all its content and we put that.
What can you tell me about this complex route? This is a
catch-all route. What’s that? A
catch-all route is a route we put at the END that will catch any request (that is why we put it last). You can read it like… If after all the routes I have on the file, you end here, please get the
/public/angular.html file and give it back. Just what we needed. We can define all our
/api routes before that and when our request doesn’t match any
REST endpoint it will serve the
angular. Later you will see another advantage.
If we run the app now, we see:
Fantastic! It simply works!
We can create a
Laravel controller to serve that
/public/angular.html but we don’t really need to. Uh, talking about controllers… There is one we don’t need:
We didn’t need that view as well.
Let’s commit the changes:
1 2 3
Now we are going to implement a simple endpoint to serve a list of our favorite TV shows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
1 2 3 4 5 6
Laravel fu, I am new at it.
So, a controller which returns an array of TV shows and a route to serve them (notice how I put it before the
We know need to consume it from
For the sake of completion, we are going to pull
angular-route.js from here and we just need to download it to
angular/vendor/js. There is no bower here, I don’t like it.
Well, we don’t need to tell anyone about that new file, just put is a dependency:
Then we configure
ngRoute a little bit:
1 2 3
We redirect to ‘/shows’ if the route doesn’t match anything registered.
Now we create a new feature for the show listing:
1 2 3 4 5 6
1 2 3 4 5
1 2 3 4 5 6 7
We create a new route for the
/shows pointing to our template and controller. The controller will forget a little bit about angular conventions and will make a
$http request to our
Laravel endpoint and will save the result on
$scope.shows. Lastly, our template will show them on a list.
The last piece is our
index.html which needs a
1 2 3 4
If we execute this:
Here it is! Working like charm.
/#/ at the url, that is something we expect on an
Angular app. What if we want to use
html5mode to remove it?
1 2 3 4 5
With that new change, we are using
html5mode. That also needs a little change on the
index.html as well:
1 2 3 4 5 6
Oh, now it doesn’t have that
If you’re curious about how this work, it is something like:
- You request
- It goes to Laravel and it starts looking the
- Ok, we ran out of matches, so here is the
catch-allroute will render the angular and will give to it the
- Angular will give that
/requested route to its router.
- No match, so it runs the
otherwisewhich redirects to
Let’s commit our changes:
1 2 3
Our application is done! What about preparing our
Angular for production?
You will notice that our
angular.html is different now:
1 2 3 4 5 6 7 8 9 10 11 12 13
Our assets have a hash to do cache-busting.
You can simply tell
forge to run that before any deployment and you’re good to go.
If you feel like this way is not for you, worry not, in a future article, we are going to play with the third option of having both separated but in the same domain.