VueJS is awesome. Creating self contained components and compose them together in your pages makes so much sense, and therefore I've been using it extensively in my latest projects. However, sometimes you want (or need) to create a traditional app, and can't use the SPA workflow development with hot reloading and .vue files.
Or can you? 🤔
TL;DR: I've prepared a repo with the full example code in case you want to dive right in at Github
Laravel already got Vue tightly integrated out-of-the-box, and you can actually register and use .vue
components in your blade
templates relatively easy. My weapon of choice is usually Express though, as I'm a Javascript fanboy 🤓. I set out to see if this is possible and spent 2 evenings trying to get the same working. With success! Below the steps to get this up and running for your next Express app as well.
Before setting out to come up with a solution I had to define the goals I had in mind. I came up with the following:
.vue
approach
Surely it's possible to write lengthy javascript and define components in one big file, but I want to use the .vue approach where <template>
, <script>
and <style>
are combined in one file.<custom-tag>
in my view files
Registering and compiling is one thing, but being able to use them is another. I don't want to have to use Vue code to render the components explicityscss
format, so this should be supported.So let's get started. Obviously we will need a starting point. The easiest way to start a new Express app is by using its generator. Basically this will create an empty project that you can build off from. If you don't have it yet, here is how you get it installed:
npm install express-generator -g
Next we run the generator to create our project:
express --view=pug myapp
I use pug
because I like the clean syntax. Though I know plenty people who hate it, so if you are one of them, just omit the --view
parameter 😉
The generator will have created a folder myapp
with an app which is pretty much ready to go, just go:
cd myapp
yarn install # or npm
yarn start
This will just install the dependencies and start the Express webserver. If all went well, browsing to http://localhost:3000 should give you the Welcome page of your new app.
With the base set up, it's about time we add some Vue to the project. Let's pull in the Vue dependency first:
yarn add vue
Next, we need to create our entry Javascript file. We will eventually bundle all the referenced javascript code into one file, so this will be our main file. I created a file in public/javascripts/main.js
. In there put the following:
var Vue = require("vue/dist/vue.js");
const app = new Vue({
el: "#app",
});
Notice we pull in vue/dist/vue.js
rather than just vue
. This is because by default Vue includes the runtime-only build, which means we can't use templates like we want in .vue files.
We also mount our Vue app to an element with id app
, so change the views/layout.pug
to include that
doctype html
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
body
+ #app
block content
Now, to use our javascript we will need to bundle it and include it in our template. My usual choice is webpack, but configuring this is quite cumbersome and to be completely honest, I couldn't get it to work. For some reason it would incude the default vue version meaning we can't use .vue files, one of the main goals.
Luckily, there is a nice tool called Vueify which we can use to compile our javascript. As a bonus, it supports pre-processors such as SASS, Styuls and even template languages such as Pug. Win. It's a transform for Browserify, so we will need both.
Installing is simple:
yarn global add browserify # We want this global, to run is easily
yarn add vueify
Now we can do the compiling:
browserify -t vueify -e public/javascripts/main.js -o public/javascripts/bundle.js
This will, unsurprisingly, create a new file bundle.js
with the compiled code. Let's not forget to include it in our layout:
doctype html
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
body
#app
block content
+ script(src="/javascripts/bundle.js")
Next up is the part we've been waiting for .. an actual component! Let's add a file public/javascripts/components/cruelWorld.vue
<template>
<div class="cruel">
Cruel
<span>{{ who }}</span>
</div>
</template>
<script>
module.exports = { // This is important, I got errors when using `export default`
data () {
return {
who: "World"
}
},
mounted () {
setTimeout(() => {
console.log('We can use ES6 too!')
}, 1000)
}
}
</script>
<style scoped>
.cruel {
color: green;
}
</style>
This is your basic Vue component. We have a simple template and some data, and it's mounted we log out a message after 1 second to show Arrow functions work as well.
Let's add it to our main.js
so we can use it:
var Vue = require("vue/dist/vue.js");
Vue.component("cruelWorld", require("./components/cruelWorld.vue"));
const app = new Vue({
el: "#app",
});
And compile it by running the command again:
browserify -t vueify -e public/javascripts/main.js -o public/javascripts/bundle.js
Nice. So we got our setup, we got our component. Now let's use it. Open up views/index.pug
and add the component:
extends layout
block content
h1= title
+ cruel-world
p Welcome to #{title}
Start the webserver:
yarn start
If all went well, you should be seeing our component alive and kicking!
Now, we can use pre-processors as well. For instance, we can add lang="scss"
to our <style>
tag to use SASS syntax:
<template>
<div class="cruel">
Cruel
<span>{{ who }}</span>
</div>
</template>
<script>
module.exports = {
data () {
return {
who: "World"
}
},
mounted () {
setTimeout(() => {
console.log('We can use ES6 too!')
}, 1000)
}
}
</script>
<style scoped lang="scss"> <!-- add this attribute -->
.cruel {
color: green;
span { <!-- nested scss syntax! -->
color: orange;
}
}
</style>
Before compiling this, we need to quickly add node-sass
as dependency:
yarn add node-sass
Now, when you compile and run, you should see the SASS is being compiled correclty and your component has become more colourful.
This is great. We can write .vue components and then use them in our traditional app. We could stop here, but let's add one more feature ..
This is just the icing on the cake. Being able to update our components and see the results straight away in our browser.
Open up your package.json
and add the following dev script to the scripts
section:
"scripts": {
"start": "node ./bin/www",
"dev": "watchify -vd -p browserify-hmr -t vueify -e public/javascripts/main.js -o public/javascripts/bundle.js & node ./bin/www"
}
This script looks daunting but is quite simple. Basically it uses watchify to watch for code changes, and proxies the result of vueify through browserify-hmr (hot module reloading) to our page. Awesome.
Don't forget to install the dependencies this relies on:
yarn add watchify
yarn add browserify-hmr
Now when you start the server ..
yarn dev
It will compile our javascript and watch for changes. Try it out, make a change to cruelWorld.vue
and see the change automagically in the browser!
I'm glad I could get this working. Sometimes it doesn't make sense to go all out with a single page app. Having the ability to still use the Vue Components in your traditional project is just gold.
If you want to see the full source code of the above, I've prepared a repository at Github which you can use as a reference or starting point.
Hope the above helps!