0

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.

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

Comments

1

Make sure you have <style lang="scss"> in your SFC

You can also try deleting the package-lock and node_modules folder and do a clean install. Sometimes that can resolve an issue if the dependencies are not using compatible versions.


Update

To import using glob style imports you may need to use import-glob

https://www.npmjs.com/package/import-glob

You can also achieve similar result using global component registration. This is documented well in the official docs at: https://v2.vuejs.org/v2/guide/components-registration.html#Automatic-Global-Registration-of-Base-Components

6 Comments

I'm not using any style at all so far. And when I tried using it I tried plain CSS - no SASS. The problem I'm having is that my component doesn't render at all. Not sure why I'd need to delete node_modules and package-lock?
Just in case the dependency versions are not playing nice. This looks a bit like a "works fine on my machine ¯\_(ツ)_/¯" issue
Ah ok I see. I did realize one thing however, I'm never actually registering my SFC anywhere like I am with the Vue.component example. I'm just importing the vue file and nothing more. So that's probably my issue. Will get back once near computer.
Ok so a couple of things: 1) Using lang="scss" actually makes my <style>s work so thanks for that (I understand this is because I only have a webpack rule for scss files and not for css) and 2) The reason the component doesn't render is because it's never registered. I've updated my question with my new problems. Thanks for your help
I am using import-glob-loader (npmjs.com/package/import-glob-loader) already, the problem is that I can't import all vue-files and then pass them to new Vue() because there doesn't seem to be a way to import them all into an array. webpack-import-glob-loader does seem to support this however so I will check it out: npmjs.com/package/webpack-import-glob-loader
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.