使用 Webpack 实现 Vue SFC(无 Vue CLI)

Implementing Vue SFC with Webpack (no Vue CLI)

我最近切换到 Webpack,现在我的所有 JS 和 CSS 运行 都能完美地通过它。这是 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'}
        ]
    }
]

我从 CDN 中包含了 Vue,使用此设置我可以毫无问题地执行以下操作:

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'});

在我的 HTML 中:

<div id="app">
    <test-component></test-component>
</div>

我现在想改用 Vue 单文件组件,并阅读它告诉我通过 vue-loader 简单地 运行 .vue 文件的文档,所以我将我的规则更改为以下内容:

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'}
        ]
    }
]

有了这个,我的 .vue 文件被拾取并添加到 dist/main.js 所以它似乎工作(只要我不包含 <style> 元素在Vue 文件,在这种情况下它会失败),但现在 new Vue({el: '#app'}) 什么都不做。检查 DOM <test-component> 仍然在那里,根本没有被 Vue 渲染。

如果我也尝试启用 vue-style-loader 构建将完全失败并显示:

(1:4) Unknown word

    > 1 | // style-loader: Adds some css to the DOM by adding a <style> tag
        |    ^
      2 | 
      3 | // load the styles

我做错了什么?

编辑:进展。多亏了 Daniel,我的 <style> 现在只要设置了 lang="scss" 就可以使用。这是因为我的 webpack 配置只有 scss 个文件的规则,而不是 css 个文件的规则。

我也弄清楚了 <test-component> 不会呈现的原因是因为我从未真正注册过它,仅仅包括 .vue-file 显然不足以让它注册.

我现在遇到的问题是尝试将我所有的 .vue 文件作为组件数组导入。如果我这样做,效果很好:

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
        }
    });
});

但我希望能够以某种方式做到这一点:

import components from "./**/*.vue";

document.querySelectorAll('[data-vue]').forEach(el => {
    new Vue({
        el: el, 
        components: components
    });
});

使用 import-glob-loader.

确保您的 SFC 中有 <style lang="scss">

您也可以尝试删除 package-lock 和 node_modules 文件夹并进行全新安装。如果依赖项未使用兼容版本,有时这可以解决问题。


更新

要使用 glob 样式导入,您可能需要使用 import-glob

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

您也可以使用全局组件注册来实现类似的结果。这在官方文档中有很好的记录: https://vuejs.org/v2/guide/components-registration.html#Automatic-Global-Registration-of-Base-Components

仅导入 vue 文件不足以使它们可供使用。您还必须使用 Vue 注册它们。

所以,这是错误的:

import 'component.vue';

new Vue({el: '#app'});

这是对的:

import component from 'component.vue';

new Vue({
    el: '#app', 
    components: {
        'component': component
    }
});

这会确保它们可用。

<style> 元素不起作用的原因是因为我没有针对 CSS 文件的 webpack 规则 - 仅针对 SCSS 文件。感谢@Daniel 指出我需要 <style lang="scss">.

vue-style-loader 只需要将样式注入 DOM 作为 <style> 元素,我实际上并不使用这些元素(我使用 mini-css-extract-plugin 创建 css-文件)也根据文档:

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.

将创建一个关于 glob 导入的单独问题。