I've recently switched to Webpack and have all my JS and CSS running perfectly through it now. Here's the relevant piece of webpack.config.js:
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
},
{loader: 'import-glob-loader'}
]
},
{
test: /\.scss$/,
exclude: /node_modules/,
use: [
{loader: MiniCssExtractPlugin.loader},
{loader: 'css-loader'},
{
loader: 'postcss-loader',
options: {
plugins: [
require('autoprefixer')
]
}
},
{loader: 'sass-loader'},
{loader: 'import-glob-loader'}
]
}
]
I have Vue included from a CDN and with this setup I can do the following no problem:
Vue.component('test-component', {
data: function () {
return {
title: 'Title',
description: 'Description'
};
},
methods: {
created: function () {
console.log('Created');
}
},
template: '<section id="test-component"><h2>{{ title }}</h2>{{ description }}</section>'
});
new Vue({el: '#app'});
And in my HTML:
<div id="app">
<test-component></test-component>
</div>
I'd now like to use Vue single file components instead, and reading the docs it tells me to simply run .vue files through vue-loader, so I changed my rules to the following:
rules: [
// NOTE: This is new
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
},
{loader: 'import-glob-loader'}
]
},
{
test: /\.scss$/,
exclude: /node_modules/,
use: [
{loader: MiniCssExtractPlugin.loader},
{loader: 'css-loader'},
{
loader: 'postcss-loader',
options: {
plugins: [
require('autoprefixer')
]
}
},
// NOTE: This is new too, but commented because it throws errors
// {loader: 'vue-style-loader'},
{loader: 'sass-loader'},
{loader: 'import-glob-loader'}
]
}
]
With that in place my .vue files are picked up and added to dist/main.js so it seems to be working (as long as I don't include a <style>
element in the Vue file in which case it fails), but now new Vue({el: '#app'})
does absolutely nothing. Checking the DOM the <test-component>
is still in there and not rendered by Vue at all.
If I also try to enable vue-style-loader
the build fails entirely saying:
(1:4) Unknown word
> 1 | // style-loader: Adds some css to the DOM by adding a <style> tag
| ^
2 |
3 | // load the styles
What am I doing wrong here?
Edit: Progress. Thanks to Daniel my <style>
now works as long as it has lang="scss"
set. This is because my webpack config only has rules for scss
files and not css
files.
I've also figured out the reason the <test-component>
won't render is because I never actually register it, simply including the .vue
-file is not enough for it to be registered obviously.
The problem I'm having now is trying to glob import all my .vue
-files as an array of components. If I do this it works fine:
import TestComponent from "./test-component.vue";
import AnotherComponent from "./another-component.vue";
document.querySelectorAll('[data-vue]').forEach(el => {
new Vue({
el: el,
components: {
'test-component': TestComponent,
'another-component': AnotherComponent
}
});
});
But I'd like to be able to do this some how:
import components from "./**/*.vue";
document.querySelectorAll('[data-vue]').forEach(el => {
new Vue({
el: el,
components: components
});
});
Using import-glob-loader
.
Simply importing the vue
files is not enough for them to be available for use. You also have to register them with Vue.
So, this is wrong:
import 'component.vue';
new Vue({el: '#app'});
This is right:
import component from 'component.vue';
new Vue({
el: '#app',
components: {
'component': component
}
});
That takes care of making them usable.
The reason the <style>
elements don't work is because I don't have a webpack rule for CSS
files - only for SCSS
files. Thanks to @Daniel for pointing out that I need <style lang="scss">
.
vue-style-loader
is only needed to inject styles into the DOM as <style>
elements which I don't actually use (I use mini-css-extract-plugin
to create css
-files) also according to the docs:
However, since this is included as a dependency and used by default in vue-loader, in most cases you don't need to configure this loader yourself.
Will create a separate question regarding the glob import.