Webpack + vue-loader + postcss-modules导致空的$ style对象

时间:2019-06-27 20:57:06

标签: vue.js webpack vuejs2 css-modules vue-loader

在我的应用中,我正在初始化一个Vue应用,该应用使用单个文件.vue组件。
我使用Webpack进行捆绑,并使用vue-loader + postcss-modules来生成作用域类。

但是由于某些原因,我无法访问组件内部的生成类($style对象为空)。我将在下面说明问题,并以 this repo 为例。

我的 hello.vue 组件如下所示:

<template>
  <div :class="$style.hello">
    Hello World!
  </div>
</template>

<script>
export default {
  name: "hello",
  created() {
    console.log(this.$style); // <- empty object :(
  }
};
</script>

<style module>
.hello {
  background: lime;
}
</style>

hello.vue.json 已按预期生成(CSS模块映射):

{"hello":"_hello_23p9g_17"}

作用域样式附加在文档头中,并且在使用mini-css-extract-plugin时捆绑在 app.css 中:

._hello_23p9g_17 {
  background: lime;
}

有人知道问题出在哪里,可能怎么解决?

在我的配置文件下面。

webpack.config.js(出于可读性而修剪)

const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const VueLoaderPlugin = require("vue-loader/lib/plugin");

module.exports = {
  entry: {
    app: "./src/index.js"
  },
  output: {
    filename: "[name].js",
    path: path.resolve(__dirname, "build")
  },
  resolve: {
    extensions: [".js", ".vue", ".json", ".css"],
    alias: {
      vue: "vue/dist/vue.esm.js"
    }
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /\.vue$/,
        loader: "vue-loader"
      },
      {
        test: /\.css$/,
        use: [
          "vue-style-loader",
          // MiniCssExtractPlugin.loader,
          {
            loader: "css-loader",
            options: {
              // modules: true,
              importLoaders: 1
            }
          },
          "postcss-loader"
        ]
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new MiniCssExtractPlugin({
      filename: "[name].css"
    }),
    new VueLoaderPlugin()
  ]
};

postcss.config.js

module.exports = {
  ident: "postcss",
  plugins: {
    "postcss-preset-env": { stage: 0 },
    "postcss-modules": {}
  }
};

编辑:

仅供参考,在modules: true选项中设置css-loader的工作原理是,它会填充$style对象(请参见docs):

{
  test: /\.css$/,
  use: [
    MiniCssExtractPlugin.loader,
    {
      loader: "css-loader",
      options: {
        modules: true
      }
    }
  ]
}

但是在我们的应用程序中,我们使用postcss-loader(根据docs)来处理所有的转换,包括作用域。同时启用modules: truepostcss-modules会发生冲突,并会破坏类/映射(如预期)。

换句话说,我正在寻找一种省略modules: true选项并改为使用postcss-modules启用CSS模块的方法。

1 个答案:

答案 0 :(得分:0)

找到了一种解决方法::从JSON文件中手动导入样式。
如果有人知道更好的方法,请告诉我:)

hello.vue.json

{"hello":"_hello_fgtjb_30"}

hello.vue

<template>
  <div :class="style.hello">
    Hello World!
  </div>
</template>

<script>
import style from "./hello.vue.json";

export default {
  name: "hello",
  beforeCreate() {
    this.style = style;
  },
  created() {
    console.log(this.style);
  }
};
</script>

<style module>
.hello {
  background: lime;
}
</style>

仅当使用postcss-modules(在我的情况下是由postcss-loader从配置加载)而不是使用modules: true时才有效:

{
  test: /\.css$/,
  use: [
    MiniCssExtractPlugin.loader,
    {
      loader: "css-loader",
      options: {
        importLoaders: 1
      }
    },
    "postcss-loader"
  ]
};

请参见this PR作为完整示例。