Vue CLI Heroku Deployment Guide
In this tutorial, I'm going to walk through how you can deploy a Vue CLI 3 application to Heroku.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

Now, in order to do this, there are a few prerequisites. First, you have to have git installed on your system. You can check by going into the terminal, you can simply type git, and as long as you don't get an error, then that means that you have git installed on your system and you're ready to use it.

large

You also need to have the Heroku account and CLI installed. To have a Heroku account, that means that you need to be able to go to Heroku.com and that you have an account here. It's free to have an account, but you may not be able to have the website up for free, you may have a fee. I'm going to talk about that a little bit more later.

You need to have that, and you need to have the CLI installed. You can verify that by performing the same test that you did with git. If you type Heroku into the terminal, and you don't get an error, but instead you get these list of commands. That means that you have the Heroku CLI installed.

large

Let's go to our checklist. Obviously, you have to be using Vue CLI 3. This is specifically made for a CLI 3 application, the same rules will apply. The only difference would be if you're using version 2, the file system is are going to look quite a bit different, the commands that were going to run here, and everything that we're going to do is going to be very similar.

If you're following along, and you are still using Vue CLI 2, that's perfectly fine. Let's get started. These are the steps that we're going to take. Before I even do that, I do need to create a git repository so I'm going to say git init, git add ., which will add everything, then git commit -m "Initial Commit".

Now we are set. This is giving a warning, but don't worry about that. It looks like everything worked. If you type git status, then you can see we are On branch master, nothing to commit, working directory clean.

large

One other item, that you have to make sure if you're using Heroku, you need to go into your .gitignore directory. Right now it is saying to ignore this /dist directory, but we actually want to have that. So I'm going to remove that from gitignore. In a little while, I'll talk about why that is important.

Let's go back into the terminal. Now we need to add a start command, so let's come into our package.json. When I say start command, anytime that you need to create a custom script in the Vue CLI, you do it right here.

I'm going to come and add one more script. This is going to be start. The reason for this is because Heroku, by default, when you push up a node-based application, the command they try to run is going to be an npm start. That's going to be something that you won't run right here.

large

We need to make sure that we have that command. Now what we want to have happen, when it says npm start, we want to say: node server.js. What this means is that when Heroku receives this application, it is going to recognize right away that it is a JavaScript node-based application. So it's going to run this command.

From there, what's going to happen is we are going to set up a server.js file. This is going to manage our entire server for us. We're going to say "okay, I want you to run node, so I want you to run the note commands and then call this server.js file."

As you can tell, this is not set up yet. We're going to do that in a little bit, but not yet, because we still have a few more things. Inside of that server.js file, we're going to use the express server. We need to make sure that we add that into the application.

In order to do that you can type npm install --save express. That is going to go and grab the express server, which if you've never used it before, it is a very lightweight node-based server. It will allow us to have a built-in server directly in our application.

It is very fast and efficient, and it also performs one incredibly helpful task that I will also discuss in a little bit. We will add that to our server.js file. Now we are at the step where we can create this file.

large

You want to do it at the very root of the application, so just come here and click new file. Type server.js. Let's close out of the terminal, and then we're going to create this file. I'm first going to set up some variables.

I'm going to require express, the way that you can do that you have to use the common JS syntax. You can't use the latest version of the import, so we're going to use require statements. We're also going to set up a port.

The way that this works is whenever Heroku's running, it's going to set up what is called a configuration variable. What we can do is say:

server.js

const express = require('express');
const port = process.env.PORT

This is going to grab the configuration environment variable. This is going to check for the environment, and it's going to see if a port is been established. If it has, then it just going to use that port. If not, then it's going to use || 8080.

server.js

const express = require('express');
const port = process.env.PORT || 8080;

What this means is that if it finds an environment variable called port, it is going to use that port. If it's on Heroku, and Heroku says "okay, I want you to use port 3000, it will use port 3000." It's really going to use whatever the system tells it to use, which makes it nice and dynamic.

If that's not set, then it's going to say "let's just fall back and use port 8080." Now that we have that, we are going to instantiate the application or instantiate the server. I'm going to say:

server.js

const express = require('express');
const port = process.env.PORT || 8080;
const app = express();

Then it is a function, so call it like a function. Then we have some configuration to do here, we first have to tell the server where to find the files so I'll say:

server.js

const express = require('express');
const port = process.env.PORT || 8080;
const app = express();

app.use(express.static)

What we're going to do when we run our bundle command that's going to generate all of the files, it's going to create a static website for us. All of our Vue code can't be processed by the browser. What we need to do is convert it into plain Vanilla JavaScript, HTML, and CSS because that's what the browser can work with.

So we are going to say express.static(). I want you to run this static function, and I want you to pull in these files. Now the way we can access this is by saying

server.js

const express = require('express');
const port = process.env.PORT || 8080;
const app = express();

app.use(express.static(__dirname + "/dist/"));

That's short for directory name. Inside of a string, we are going to reference that /dist/ directory, which is short for distribution. Anytime you see this /dist directory, what that means is that is where all of your compiled code is going to go, and that's what the browser can actually read.

Now that we have that, the next thing I'm going to do is I'm going to give you a little trick here. If you have ever gone to an application or if you've ever tried to push up an application, that is a single page app, like a Vue app, an Angular app, a React app, what happens is...let's do a demo on this really quick.

Let's pretend that Heroku is a single page application. If you clicked on a route here, say I clicked on this support link, and it would work perfectly as a Vue app. What would happen is if you hit refresh, right now, this will work.

If you didn't do the little trick I'm going to show you and you are using a single page application, the system or server is going to go and try to find a file called support. Remember, whenever you are using a single-page application, we really just mock routes.

The routes aren't even real they are just there to help people see where they're at inside an application. If you tried to send somebody to a route in a Vue app, then it would break. It wouldn't look for the app, it would look for the app-url/support, and then it would look on the server for something like support.html.

It wouldn't find that file, and then it would throw an error. What we need to do is we need to add in a little trick. We're going to say:

server.js

const express = require('express');
const port = process.env.PORT || 8080;
const app = express();

app.use(express.static(__dirname + "/dist/"));
app.get(/.*/, function())

Then I'm going to pass in a regular expression: /.*/. Which just means get everything after the / and the end it with another /. This is going to essentially take care of all routes. Now you're going to pass in a function with the request and response, as the arguments here.

server.js

const express = require('express');
const port = process.env.PORT || 8080;
const app = express();

app.use(express.static(__dirname + "/dist/"));
app.get(/.*/, function(req, res))

Then inside of curly braces, what we're going to do is we're actually going to mock the file. We're going to capture all of the request, and then we're going to send all of the request to the index.html file. So I'm going to say:

server.js

app.use(express.static(__dirname + "/dist/"));
app.get(/.*/, function(req, res) {
    res.sendfile(__dirname + "/dist/index.html");
})

If this looks weird to you. If you've never seen anything like this before, it's actually pretty simple once you actually understand how it works. All we are saying is that I want you to capture all routes. No matter what someone goes to, say that we're back at our fake Vue application that's in production right now, if someone goes to support, this is going to get rerouted.

Instead of trying to find the support file, it's going to go in the server, and it's going to get rerouted to this index.html file, which is exactly where all of the application is stored. Now, if someone goes to something like this, a bunch of gibberish, it would also get routed there. That's all this is doing.

Because this is a single page application, every single entry point into the app is through this index.html file. What we're saying here is: whatever the route is, I want you to actually redirect it, push them to the index.html file, and if you do that it is going to the index file because it is storing the Vue app.

It is going to be able to know how to handle those routes, so that's what we're doing right there, and it is critical. I've run into so many people that have had bugs where they pushed up a single page application and it looked like it worked, the routing and everything like that.

The app was just perfect until they tried to refresh the page on an outside route. Then it broke, and they got some very weird 404 errors. Make sure that you have added that. Now, after that is in place we can call app again, and then we want to listen for the port.

server.js

app.use(express.static(__dirname + "/dist/"));
app.get(/.*/, function(req, res) {
    res.sendfile(__dirname + "/dist/index.html");
})
app.listen(port);

Now, remember, the port is what we set up right here. We can also, just to make sure everything's working, console.log something out. Let's say console.log('Server started...');. Hit save, and now we have our server.js file.

Let's go back to our checklist. We created that start command, we installed express, we set up the server.js file. Now it's time to actually build this. You've seen us reference the /dist directory multiple times, but you may be curious. Where is it? That's what we're going to do now.

Let's open up the terminal one more time, and run npm run build. What this is going to do is it's going to take all of our files, this entire Vue application, it's going to go through our source directory, it's going to take all of this, then it's going to convert that into something the browser can actually work with.

If you click now, you see this dist directory. The reason why we needed to make sure we removed it from .gitignore, is because this is what Heroku's going to use in production.

large

Anytime that you make a change, if you are following this workflow, there are other ways of automating it, but for right now I think it's important to understand what's going on here. So anytime you'd make a change, you also need to run this build command again to update the disc directory.

Now if you click here, you may notice that we don't have any Vue code here. Now you can see that we have our index.html file, and it's all minified. It looks kind of weird because it's all on one line, but that's for performance reasons.

large

This is the same index.html file that we referenced here. This is the entry point for the entire application. This is where everything in the app is going to be called. Then we have JavaScript code, so all of the Vue code that you create is going to get processed and converted into something that looks like this.

large

If you ever wonder why in the world do I need to use a framework like Angular or Vue or React? It's because you really do not want to write code like this, but this is what your Vue code actually gets converted into. That is all done, and we also do the same thing with the compiled CSS files.

With all of that place make that if you type git status that you add all of these, so I'll say git add ., and git commit -m "Built for Heroku". Now what we can do is if you do you have a gitHub account, you can push this up to gitHub.

What we're going to do is skip that process, and we're going to create our Heroku instance here. I'm going to say heroku create devcamp-vue-three-deploy. It's a very long name, but I don't think anyone else has taken this name. I'm going to hit enter. We should be good.

You can do whatever you want just one thing to know if you're new to Heroku is this name has to be unique. No one else in the world can use it because this is going to be the subdomain for your application. I'm going to hit enter, and there you go. Our application has been created.

large

We still need to push to it and I'm going to tell you that this is going to work, but it's going to get an error. The reason is, and the reason why I'm keeping the error in here because I want to show you how to debug it. I'm just going to add that as a little spoiler alert.

To push up to here, you first make sure to type git status. Make sure that you don't have any other changes to commit. Now you can say git push heroku master. This is going to take all of this code, and it's going to pass it to the Heroku app engine.

When we ran heroku create, what Heroku did is it created a connection between their server and our system. Now when we're pushing this up, it's pushing it up to that app that was created. The reason why this is going to run into an error is because Heroku allows you to have a certain amount of free server time each month.

If you have not hit your max limit, then you're probably going to be fine. I have so many apps on there, I actually have hit my limit, and so I want to keep this in here just in case you do. That way, you don't think that you did something wrong.

It may just be a problem where you ran out of free time. It looks like everything worked. The build succeeded. It looks like it worked on that side. If you ever want to see where everything is located, you can type git remote -v.

You can see that we have deployed to here. This is not the URL where we're going to find the application. This is the remote git repository that Heroku his storing our code.

large

If we were to go grab this name one more time, let's go into Chrome, and go into that URL. So devcamp-vue-three-deploy/herokuapp.com or whatever name you gave your application, it's going to be that name .herokuapp.com. If you then type enter, you will run into an application error.

large

That is because we ran out of space, or I ran out of space on my personal account. Now the way that you can test this, and this is part of why I wanted to keep this error going in the tutorials because if you run into that error, the best way to debug this is type heroku logs -n 250.

This is going to bring the last 250 lines of the logs for our Heroku server. If I run this then it's going to give me the error. Right here you can see that I have the build succeeded, and everything worked, but right here this is the problem. It says Idling because quota is exhausted.

large

If you get this error, and then you have the stopping all processes, it is simply telling you that nothing's the matter with your code. It is simply a problem that you have used all of your free time. That's all you have to do.

Now, let's get it fixed. I'm going to come here, I'm going to log in, I'm going to hide my credentials, and I'll show you how you can get it fixed. If you do have a situation where you don't want to pay for this, then that's perfectly fine.

That means that you will not be able to see your application until the next month comes around, and you get all of your free time back up there. The way that you can do it is you can search for that app, so you can search for all of your apps right here.

large

I'm going to say devcamp-vue-three-deploy, and you see that it has it right there. There's a couple ways that you can fix it. You can click on Configure Dynos, click on upgrade to hobby, and then click here. The way that I'm going to do it, you can see that $7/month.

Don't do this if you're just testing it right now and you're learning about it unless you feel like spending $7. If you are actually wanting to host the website on Heroku then pay for that. The way I'm going to do it is I'm going to have the Bottega account take care of it.

If you're working with teams on Heroku, I can go to Bottega here, click on Transfer app, and that's automatically going to put it in the team account. Then it's going to make it active. Now I can click on Open App right here.

If everything works, then it will work. That looking really good. You can even test this out. If I click on About, you can see right here, if I hit refresh, that our routes are still working.

large

One last thing that I want to do, and I know this video has definitely gone on for a while, but this is a really important topic. Hopefully, you find it helpful. Notice this route right here. Notice how it has this little hash mark. That is the way that Vue has their routes set up by default.

That's pretty ugly. You really never want to do that. The reason why they did that is because of what we talked about in our server.js file. Right here, when we added our little workaround for getting all routes to be mapped to index.html.

large

It is because by default Vue tries to put this little hash in there because that's their work around., but I don't like that. I'm going to show you how to fix that. Also, it's going to teach you how you can update your application on Heroku.

The way that you can fix that is you can go into your source directory, go into your router.js, and this is different. If you're following along with Vue CLI 2, then you would go into your router directory and then index.js.

You can come right here and then type mode right under router. Then as a string history, hit save.

large

This is going to bypass the default, annoying, little hash, and it's going to work more like a real application. It's going to use what is called the Windows History Tool. This is now going to allow our single-page-application route to look exactly like a real route.

Let's now rebuild, so I'll say npm run build, so our changes will actually take effect. Then I'm going to create another git commit and then we can deploy. So git add ., git commit -m "Upgraded routes". Now we can say git push heroku master.

Hopefully, by going through this a few times, it'll get you in the routine of seeing exactly what the processes in order to deploy. I definitely recommend for you to reference, as it's going through I'll show it to you again, reference this checklist. For the most part, this is accurate.

There's one thing I do want to add before I add this to the show notes. If you may have remembered, we needed to Remove the /dist directory from .gitignore. That is very important.

large

If you don't do that, then git is not going to be aware of your application, and it's not going to have a /dist directory to look to. It's not going to have any entry points. It's not going to have any code to actually show in the browser.

That's an important thing to understand. Now let's come back to our application. Let's go back to the homepage, and let's remove the little hash. Hit enter, and it's working perfectly.

large

If I click About, notice how it removed that hash. I can still hit refresh, and everything here is working. In review, that is how you can deploy a Vue CLI version 3 application to Heroku.

Resources