La syntaxe
Les SFC sont des fichiers qui ont une syntaxe particulière et qui permet de renseigner tous les éléments qu'un composant peut posséder :
- Du JS (nos data, CP, watchers, methods...)
- Du HTML (le template)
- Du CSS pour le style
Ces fichiers ont une extension propre en .vue et ont la syntaxe suivante :
{"language":"text/html","content":"<template>\n\t<!-- C'est ici que je mets mon HTML -->\n</template>\n<script>\n\t// Mon JS est ici, évidemment\n</script>\n<style>\n\t/** Le CSS ! **/\n</style>","filename":"Composant.vue"}
Dans la partie script on importera tout ce dont on a besoin (d'autres composants, une librairie) puis exportera le code de notre composant. Il est important de respecter cet ordre : template, script puis style (ou script, template puis style) comme indiqué dans le style guide (Single file component top level element order recommended) pour des questions de lisibilité.
{"language":"text/html","content":"<template>\n\t<!-- C'est ici que je mets mon HTML -->\n</template>\n<script>\n\t// Des import si besoin\n\texport default {\n\t\tdata() {\n\t\t\treturn {\n\t\t\t\t...\n\t\t\t}\n\t\t},\n\t\tmethods:{\n\n\t\t},\n\t\tcreated() {\n\t\t\t\n\t\t}\n\t}\n</script>\n<style>\n\t/** Le CSS ! **/\n</style>","filename":"Composant.vue"}

Oui, regarde voici comment ça se passe :
{"language":"text/html","content":"<template>\n <div>\n <button @click=\"slide(-1)\">Aller à gauche</button>\n <button @click=\"slide(1)\">Aller à droite</button>\n <template v-for=\"(slide, key) in slides\" :key=\"key\">\n <div>Key : {{ key }} Index : {{ index }}</div>\n <div v-if=\"index == key\">\n {{ slide }}\n </div>\n </template>\n </div>\n</template>\n\n<script>\n export default {\n data() {\n return {\n slides:[\n 'Flower',\n 'Animal',\n 'Space'\n ],\n index:0\n }\n },\n methods:{\n slide(operation) {\n // Car % n'est pas le modulo mathématique en JS\n // on doit faire un code un peu compliqué\n // pour gérer les nombres négatifs\n this.index = (((this.index + operation)%this.slides.length)+this.slides.length)%this.slides.length\n }\n }\n }\n</script>","filename":"Slider.vue"}

Comme on l'a vu au début et comment tu peux peut être l'imaginer, on peut mettre des composants dans des composants. Pour ça, il suffit de les importer !
Utiliser un SFC
Pour utiliser un SFC, il nous faut tout simplement l'importer et l'utiliser. Si c'est notre composant principal, on peut créer notre application Vue depuis ce dernier avec createApp. C'est déjà ce qu'on faisait avant avec notre root component ! Le root component est par défaut un composant.
Imaginons donc que nous avons un fichier main.js (ce qui est le cas par défaut avec vue-cli) que l'on inclut dans notre index.html. Il ressemblera à :
{"language":"text/javascript","content":"import { createApp } from 'vue'\n\nimport Slider from './components/Slider.vue'\n\ncreateApp(Slider).mount('#app')","filename":"main.js"}

Si tout à fait ! Mais d'habitude on n'importait pas createApp non plus, on avait accès à tout Vue grâce au CDN. Là on importe que ce dont on a besoin depuis vue, par exemple la méthode createApp() ;)

Parfait. Là on vient de voir comment utiliser notre composant en tant que root component. Comme dit avant, on peut aussi l'utiliser au sein d'un autre composant. Ce sera généralement le cas. D'autant plus si tu utilises vue-cli ou vue-vite, par défaut tu as un composant principal nommé App.vue et tu appelles tous les autres composants dedans.
Pour préciser au sein d'un composant que ce dernier utilise d'autres composants on va utiliser l'objet components. Voici donc un exemple réutilisant le fichier App.vue par défaut de vue-cli :
{"language":"text/html","content":"<template>\n <img alt=\"Vue logo\" src=\"./assets/logo.png\">\n <slider></slider>\n</template>\n\n<script>\nimport Slider from './components/Slider.vue'\n\nexport default {\n name: 'App',\n components: {\n Slider\n }\n}\n</script>\n\n<style>\n#app {\n font-family: Avenir, Helvetica, Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n text-align: center;\n color: #2c3e50;\n margin-top: 60px;\n}\n</style>\n","filename":"App.vue"}
{"language":"text/javascript","content":"import { createApp } from 'vue'\nimport App from './App.vue'\n\ncreateApp(App).mount('#app')","filename":"main.js"}
Utiliser des preprocesseurs
Les SFC ne se limitent pas à l'utilisation simple de HTML et CSS natifs. On peut utiliser des préprocesseurs comme PUG pour le HTML ou SASS (ou LESS, ou Stylus...) pour le CSS. On doit simplement préciser la "langue" dans notre balise, comme suit pour PUG :
{"language":"text/html","content":"<template lang=\"pug\">\nimg(alt=\"Vue logo\" src=\"./assets/logo.png\")\nSlider\n</template>\n\n<script>\nimport Slider from './components/Slider.vue'\n\nexport default {\n name: 'App',\n components: {\n Slider\n }\n}\n</script>\n\n<style>\n#app {\n font-family: Avenir, Helvetica, Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n text-align: center;\n color: #2c3e50;\n margin-top: 60px;\n}\n</style>\n","filename":"App.vue"}

Oui et non. En fait, tu peux utiliser PUG uniquement SI tu as installé le "loader de PUG" qui permet à ton bundler (webpack par exemple (rappel : vue-cli se base sur webpack)) de lire ce genre de format et de le compiler. Ainsi, n'oublie pas d'avoir bien installé ton loader comme habituellement avant de l'utiliser dans tes SFC. Par exemple pour sass, il faut installer sass-loader etc. On aurait donc le code suivant si on voulait aussi utiliser SASS :
{"language":"text/html","content":"<template lang=\"pug\">\nimg(alt=\"Vue logo\" src=\"./assets/logo.png\")\nSlider\n</template>\n\n<script>\nimport Slider from './components/Slider.vue'\n\nexport default {\n name: 'App',\n components: {\n Slider\n }\n}\n</script>\n\n<style lang=\"sass\">\n#app {\n font-family: Avenir, Helvetica, Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n text-align: center;\n color: #2c3e50;\n margin-top: 60px;\n}\n</style>","filename":"App.vue"}

Tout à fait, dès que tu as leur loader ou leur plugin. Je te conseille de te renseigner sur comment les installer avec ton bundler/compilateur (webpack, vue-cli, vue-vite...) car cela change pour chacun.
Attention cependant, pour TailwindCSS, on n'utilisera pas lang="tailwind" mais lang="postcss" pour utiliser les @apply classiques :
{"language":"text/html","content":"<template>\n <img alt=\"Vue logo\" src=\"./assets/logo.png\" />\n <Slider />\n</template>\n\n<script>\nimport Slider from './components/Slider.vue'\n\nexport default {\n name: 'App',\n components: {\n Slider\n }\n}\n</script>\n\n<style lang=\"postcss\">\n#app {\n @apply bg-red-500;\n}\n</style>","filename":"App.vue"}
Tu remarqueras par ailleurs qu'on peut écrire la balise Slider de manière auto-fermante ou orpheline (comme les img, les meta...). On peut toujours le faire à partir du moment où on ne précise rien comme contenu au sein de notre balise (pas de <slider>Du contenu </slider>). On verra ce cas d'utilisation plus tard.

Tout à fait, ça sert à ça !

Pas exactement, il faudrait qu'on voit autre chose concernant le style.
Un point sur le style
On a vu qu'on pouvait utiliser des préprocesseurs CSS pour le style au sein de nos SFC. Cependant, comment sont gérés ces styles au sein de notre page ? Comment sont-ils appliqués sur le HTML ?

En l'état actuel, une balise <style></style> est créée et contient notre code #app{...}. Tu peux vérifier en faisant "Inspecter l'élément" sur ton navigateur. C'est d'ailleurs pour ça que même si on n'a pas la div id="app" dans notre composant App.vue, celle-ci est bien stylisée. Cela peut poser vite des problèmes...
Imaginons le code suivant :
{"language":"text/html","content":"<template>\n <div>\n <button @click=\"slide(-1)\">Aller à gauche</button>\n <button @click=\"slide(1)\">Aller à droite</button>\n <template v-for=\"(slide, key) in slides\" :key=\"key\">\n <div>Key : {{ key }} Index : {{ index }}</div>\n <div v-if=\"index == key\">\n {{ slide }}\n </div>\n </template>\n </div>\n</template>\n\n<script>\n export default {\n ...\n }\n</script>\n\n<style>\n\tdiv{\n\t\tcolor:blue;\n\t}\n</style>","filename":"Slider.vue"}
{"language":"text/html","content":"<template>\n <div>\n <img alt=\"Vue logo\" src=\"./assets/logo.png\">\n </div>\n <Slider />\n</template>\n\n<script>\nimport Slider from './components/Slider.vue'\n\nexport default {\n name: 'App',\n components: {\n Slider\n }\n}\n</script>\n\n<style>\n#app {\n font-family: Avenir, Helvetica, Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n text-align: center;\n color: #2c3e50;\n margin-top: 60px;\n}\n\ndiv{\n color:red;\n}\n</style>\n","filename":"App.vue"}

Oui. Ce serait bien mieux de faire en sorte que le style de notre composant est une portée "locale", c'est à dire qu'il n'agisse que sur les éléments HTML de notre composant. C'est possible grâce à scoped ou grâce aux modules.

Le scoped CSS, que je traduirais en Français par "CSS à portée limitée", permet d'appliquer du CSS uniquement sur le HTML du composant en question. Grâce à PostCSS, utilisé par vue-cli (mais qu'on peut utiliser avec les autres outils de build), le code suivant :
{"language":"text/html","content":"<template>\n\t<div class=\"container\">...</div>\n</template>\n<style scoped>\n\t.container{\n\t\tborder:1px solid black;\n\t}\n</style>","filename":"Component.vue"}
Sera transformé lors de la compilation en code suivant :
{"language":"text/html","content":"<template>\n\t<div class=\"container\" data-v-f3f2eg8>...</div>\n</template>\n<style scoped>\n\t.container[data-v-f3f2eg8]{\n\t\tborder:1px solid black;\n\t}\n</style>","filename":"Component.vue"}
Ainsi, la portée du CSS est limitée à tous les éléments qui auront l'attribut personnalisé data correspondant, et donc uniquement aux éléments HTML du composant ;). Mission réussie !
Petite note : Vue déconseille d'utiliser le style à portée limitée avec les sélecteurs CSS d'éléments (button{}, div{}...) pour des questions d'optimisation. Voici le lien vers cette note : [les sélecteurs d'éléments avec le scoped CSS]

Tout à fait !
Les modules CSS ont le même but mais j'avouerais que je les trouve plus complexes à utiliser et les retrouve moins souvent. Si tu es intéressé : https://vue-loader.vuejs.org/guide/css-modules.html#usage

Oui ! Le but va être de créer un site de recueil d'avis artistiques.

Presque. On va noter des photos prises bien loin de nous, par des professionnels nommés Curiosity ou encore Spirit...
Rendez-vous au prochain chapitre pour en savoir plus ;) J'ai terminé cette partie