gstreamer0.10-ffmpeg
gstreamer0.10-plugins-good
packages.
As we've seen, it's totally possible to configure the Vue instance and put the template in the same file. But... this is going to get crazy as our app grows: can you imagine writing 100 lines of HTML inside this string... or more? Yikes! Fortunately, Vue solves in a unique, and pretty cool way: with single file components.
Inside the js/
directory create a new folder called pages/
, and then a file called products.vue
. We'll talk more about the directory structure we're creating along the way.
Notice that .vue
extension: these files aren't really JavaScript, they're a custom format invented by Vue.
On top, add a <template>
tag. Then, copy the h1
HTML from the original file, delete the template
variable, and paste here.
<template> | |
<h1>Hello {{ firstName }}! Is this cooler?</h1> | |
</template> | |
... lines 4 - 14 |
Next, add a <script>
tag. Anything in here is JavaScript and we'll export default
an object that will hold our Vue options. Copy the data()
function, delete it, and move it here.
... lines 1 - 4 | |
<script> | |
export default { | |
data() { | |
return { | |
firstName: 'Ryan', | |
}; | |
}, | |
}; | |
</script> |
That's it! I know, the format is a bit strange, but it's super nice to work with. On top, the <template>
section allows us to write HTML just like if we were in a Twig template. And below, the <script>
tag allows us to set up our data, as well as any of the other options that we'll learn about. This is a fully-functional Vue component.
Back in products.js
, to use this, first, import it: import App
- we could call that variable anything - from './pages/products
. Thanks to Encore, we don't need to include the .vue
extension.
... line 1 | |
import App from './pages/products'; | |
... lines 3 - 10 |
Now, inside of render, instead of worrying about compiling the template and all this boring, crazy-looking code, the App
variable already has everything we need. Render it with return h(App)
.
... lines 1 - 3 | |
new Vue({ | |
el: '#app', | |
render(h) { | |
return h(App); | |
}, | |
}); |
Tip
For Vue 3, the code should look like this:
import { createApp } from 'vue';
import App from './pages/products';
createApp(App).mount('#app');
That feels good! Let's try it: move over, refresh and... it still works!
From here on out, we're going to do pretty much all our work inside of these .vue
files - called single file components. One option that we're going to add to every component is name
: set it to Products
. We could use any name here: the purpose of this option is to help debugging: if we have an error, Vue will tell us that it came from the Products
component. So, always include it, but it doesn't change how our app works.
... lines 1 - 5 | |
export default { | |
name: 'Products', | |
... lines 8 - 12 | |
}; | |
... lines 14 - 15 |
Before we keep working, there are two small changes I want to make to products.js
. First, the el
option: it tells Vue that it should render into the id="app"
element on the page. This works, but you usually see this done in a different way. Remove el
and, after the Vue
object is created, call .$mount()
and pass it #app
.
... lines 1 - 3 | |
new Vue({ | |
render(h) { | |
return h(App); | |
}, | |
}).$mount('#app'); |
I also like this better: we first create this Vue
object - which is a template and set of data that's ready to go - and then choose where to mount it on the page.
Second, because the render()
method only contains a return
line, we can shorten it: render
set to h => h(App)
.
... lines 1 - 3 | |
new Vue({ | |
render: (h) => h(App), | |
}).$mount('#app'); |
That's effectively the same: it uses the arrow function to say that render is a function that accepts an h
argument and will return h(App)
. I'm mostly making this change because this is how you'll see Vue apps instantiated on the web.
Next, let's get to work inside our single file component: we'll add the HTML markup needed for our product list page and then learn how we can add styles.
// package.json
{
"devDependencies": {
"@symfony/webpack-encore": "^0.30.0", // 0.30.2
"axios": "^0.19.2", // 0.19.2
"bootstrap": "^4.4.1", // 4.5.0
"core-js": "^3.0.0", // 3.6.5
"eslint": "^6.7.2", // 6.8.0
"eslint-config-airbnb-base": "^14.0.0", // 14.1.0
"eslint-plugin-import": "^2.19.1", // 2.20.2
"eslint-plugin-vue": "^6.0.1", // 6.2.2
"regenerator-runtime": "^0.13.2", // 0.13.5
"sass": "^1.29.0", // 1.29.0
"sass-loader": "^8.0.0", // 8.0.2
"vue": "^2.6.11", // 2.6.11
"vue-loader": "^15.9.1", // 15.9.2
"vue-template-compiler": "^2.6.11", // 2.6.11
"webpack-notifier": "^1.6.0" // 1.8.0
}
}