Chapters
-
Course Code
Subscribe to download the code!
Subscribe to download the code!
-
This Video
Subscribe to download the video!
Subscribe to download the video!
-
Subtitles
Subscribe to download the subtitles!
Subscribe to download the subtitles!
-
Course Script
Subscribe to download the script!
Subscribe to download the script!
Single File Component
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
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 this 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.
Creating the Single File Component
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> | |
Show Lines
|
// ... 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.
Show Lines
|
// ... 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.
Using the Single File 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.
Show Lines
|
// ... line 1 |
import App from './pages/products'; | |
Show Lines
|
// ... 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)
.
Show Lines
|
// ... 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!
Adding a Component Name
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.
Show Lines
|
// ... lines 1 - 5 |
export default { | |
name: 'Products', | |
Show Lines
|
// ... lines 8 - 12 |
}; | |
Show Lines
|
// ... lines 14 - 15 |
$mount() the Component
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
.
Show Lines
|
// ... 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.
Shorthand render() Method
Second, because the render()
method only contains a return
line, we can shorten it: render
set to h => h(App)
.
Show Lines
|
// ... 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.
21 Comments
That looks pretty nice! I'm guessing it's not as simple as just mimicking what's in that example file?
:( unfortunately no, there is something that doesn't add up. Yet I followed the instructions in the video to the letter, I'm not very familiar with Vue
In the example it load script type=module after tag with id="App" in the view (here the file)
Ah! I think the key is to focus more on the original file - App.vue
. Pretend this is any single file component - you could call it MyProductTable.vue
. When you're ready to render it, forgot the script type="module"
stuff - that detail varies based on how your build system, etc is set up. Instead, import MyProductTable.vue
into some other part of your Vue app and render it like you normally would.
Let me know if this helps :)
many thanks Ryan I solved it works, I didn't want to delve too deeply into vue but I will in the future, at the moment the datatable works and that's enough for me XD
Woohoo! I'm happy we were able to at least get this working for you :)
Also got the "Syntax Error: TypeError: Cannot read property 'parseComponent' of undefined" error. This fixed it for me in case anyone else gets it. This change is in package.json and was made to match the value for vue-template-compiler in package.json
Old Value"vue": "2.5",
New Value"vue": "^2.6.12",
Then run yarn install
Thank you for the info! Yes, you should get the latest version of Vue 2 always!
I was getting the same error as below so I changed package.json to:
"vue": "2.6.11",
"vue-loader": "15.9.1",
"vue-template-compiler": "2.6.11",
Uncaught Error: Module build failed (from ./node_modules/vue-loader/lib/index.js):
TypeError: Cannot read property 'parseComponent' of undefined
help me , please.
resolved -> package.json
"vue": "2.6.11",
"vue-loader": "15",
"vue-template-compiler": "2.6.11",
Hi, Alexei!
Please try with these settings in your package.json and see if it works:
"vue": "^2.6.11",
"vue-loader": "^15.9.1",
"vue-template-compiler": "^2.6.11",
Hi, it's work perfectly by replacing the "2.5" version of vue package by "^2.6.11".
"vue-loader" is set to 15 so he's already using the latest version.
It would be nice if wp-encore updated his installation message.
Thanks for the solution!
Hi guys,
I had the same problem but changing vue and vue-template-compiler to "2.6.11" was not enough. I had to type :yarn add --dev @vue/component-compiler-utils@1.3.1
find on this <a href="https://github.com/parcel-bundler/parcel/issues/1490">github</a>
Now everything work
Hey! I'd like to further comment on this:
Different projects might have different requirements as to what to install in order for Vue to compile properly through Webpack. Also, when upgrading older versions of Vue to, say, 2.6.11, you might have special needs as well. But if you start from our project's starting point and follow our directions to the letter, you should have no problems with it!
Having said that, if you find issues, please, let us know!
In the future, encore might choose to install Vue 2.7 (when it's available) as its default Vue 2 version. There should be no problem there as well, but if there is, we'd also like to hear about it!
Hey Micka!
Thanks for letting us know!
Hi guys,
I am having a problem with the single page component.
I am getting an error in the products.vue file and I could not find a solution for this. This is the error I am getting.Syntax Error: TypeError: Cannot read property 'parseComponent' of undefined<br />
Could you tell me what I am doing wrong?
Cheers and Thanks!
HI Sayil,
had exactly the same issue. I have downloaded start code of tutorial and in package.json vue version is/was set to 2.5 but vue-template-compiler to ^2.6.11
so all you need is just to change vue: to ^2.6.11 rerun yarn install and yarn watch and it should be fine
Hi Sayil!
Please look at your package.json for vue-template-compiler. This might be an error where Yarn has installed a wrong version of it. You might be able to fix this by changing the version number from ^2.6.10 to 2.6.10 (remove the ^) and run Yarn again to update the package.
This could also happen if vue-template-compiler is missing (i.e. you have forgotten to run yarn to install your packages in the first place)
Let me know if this helps!
Hi Matias,
thanks for answering so quick!
I tried this but I am still getting the error. I made sure that the vue-template-compiler was installed but still nothing. I ran yarn install after changing the version but I still get the same error. Could there be any other reason for this?
Thanks in advance.
Hmm, hard to think of a reason! Did you config Encore for Vue 3 or Vue 2? what do your package.json and webpack.config.js files look like?
"Houston: no signs of life"
Start the conversation!
What JavaScript libraries does this tutorial use?
// 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
}
}
Thanks for the great video tutorial, it would be interesting to have an example of how to run this ^_^