Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use MiniCssExtractPlugin and vue-style-loader at the same time?

Tags:

sass

webpack

I would like to use scss in my component file (Home.vue) and in a separate file (style.scss) at the same time. Webpack generate default.css from style.scss - I use MiniCssExtractPlugin and vue-style-loader.

I prepare webpack.config.js but it seems incorrect becouce when I change <style lang="scss" scoped> to <style lang="css" scoped> everything works fine otherwise it doesn't. <style lang="scss" scoped> do nothing - no error, no effects.

How to change webpack.config.js to works MiniCssExtractPlugin and vue-style-loader at the same time?

webpack.config.js

var path = require('path')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

const isDevelopment = process.env.NODE_ENV

console.log("Dev status: " + (isDevelopment == 'development' ? 'Development' : 'Production'), isDevelopment);

module.exports = {
  mode: isDevelopment,

  entry: {
    'vwp': ['./src/vue/welcome.js'],
    'default': './src/scss/style.scss'
  },
  output: {
    path: path.resolve(process.cwd(), 'public/assets/js'),
    filename: '[name].js'
  },
  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js'
    }
  },
  module: {
    rules: [{
      test: /\.vue$/,
      loader: 'vue-loader'
    },
    {
      test: /\.js$/,
      loader: 'babel-loader',
      exclude: file => (
        /node_modules/.test(file) &&
        !/\.vue\.js/.test(file)
      )
    },
    {
      test: /\.css$/,
      use: [
        'vue-style-loader',
        'css-loader'
      ]
    },
    {
      test: /\.scss$/,
      use: [
        'vue-style-loader',
        MiniCssExtractPlugin.loader,
        'css-loader',
        'sass-loader',
      ]
    }
    ]
  },
  plugins: [
    new VueLoaderPlugin(),
    new CleanWebpackPlugin({
      dangerouslyAllowCleanPatternsOutsideProject: true,
      cleanOnceBeforeBuildPatterns: ['../css/*', '../js/*'],
      cleanAfterEveryBuildPatterns: ['defautl.js'],
      dry: false
    }),
    new MiniCssExtractPlugin({
      filename: isDevelopment == 'development' ? '../css/[name].css' : '../css/[name].[hash].css',
      chunkFilename: isDevelopment == 'development' ? '../css/[id].css' : '../css/[id].[hash].css'
    }),
    new CleanWebpackPlugin({
      cleanAfterEveryBuildPatterns: ['defautl.js']
    }),


  ]
}

welcome.js

import Vue from 'vue'
import Home from './Home.vue'

Vue.config.productionTip = false

new Vue({
    el: '#vwp',
    components: { Home },
    template: '<Home />'
})


Vue.config.devtools = true

Home.vue

<template>
  <div>hello text</div>
</template>

<script>
export default {
  name: "Home"
};
</script>

<style lang="scss" scoped>
* {
  color: lime;
}
</style>
like image 374
Ale Avatar asked Dec 17 '19 11:12

Ale


People also ask

What is vue style-loader?

This is a fork based on style-loader. Similar to style-loader , you can chain it after css-loader to dynamically inject CSS into the document as style tags.

What is the use of Minicssextractplugin?

This plugin extracts CSS into separate files. It creates a CSS file per JS file which contains CSS. It supports On-Demand-Loading of CSS and SourceMaps.

How does style-loader work?

style-loader injects the styling through a style element. The way it does this can be customized. It also implements the Hot Module Replacement interface providing for a pleasant development experience. The matched files can be processed through asset modules by using the type field at a loader definition.

What is mini-CSS-extract-plugin?

It creates a CSS file per JS file which contains CSS. It supports On-Demand-Loading of CSS and SourceMaps. It builds on top of a new webpack v5 feature and requires webpack 5 to work. Compared to the extract-text-webpack-plugin: To begin, you'll need to install mini-css-extract-plugin:

Can I use style-loader and mini-CSS-extract-plugin together?

For development mode (including webpack-dev-server) you can use style-loader, because it injects CSS into the DOM using multiple and works faster. i Do not use together style-loader and mini-css-extract-plugin. ⚠ Names of locals are converted to camelCase.

How do I load a CSS file in Vue?

.css .scss and .sass files are loaded with vue-style-loader in development mode and MiniCSSExtractPlugin.loader in production mode. One tricky point is that sass files are loaded by using two loaders: sass-loader and css-loader.

Can this plugin be used with style-loader in loaders chain?

This plugin should not be used with style-loader in the loaders chain. Here is an example to have both HMR in development and your styles extracted in a file for production builds. (Loaders options left out for clarity, adapt accordingly to your needs.)


2 Answers

The problem is that WebPack refuses to work if there is a regular expression match in the rules. I think it somehow marks the processed files. This is true at least for this situation.

But WebPack is a very powerful tool. Instead of a regular expression in the rule parameter, it can take a function with two parameters (filename and entry).

After that, I determined that vue-loader splits the component file into three files:

  • <component name>.vue.js
  • <component name>.vue and finally
  • <component name>.vue.css (or .scss)

Note: The SASS extension depends on the lang parameter of the style tag.

Next, it was necessary to separate these two cases with logic in the function. My implementation is seen in the example.

rules: [
            {
                test: function(filename, entry){
                    if(/\.s[ac]ss$/.test(filename)){
                        if(/\.vue\.s[ac]ss$/.test(filename)){
                            return false;
                        }
                        return true;
                    }
                    return false;
                },
                use: [
                    {
                        loader: MiniCssExtractPlugin.loader, 
                        options:{
                        }
                    }, 'css-loader', 'sass-loader']
            },      
            {
                test: /\.vue$/,
                loader: 'vue-loader',
                options: {
                }
            },
            {
                test: /\.css$/,
                use: [
                  'vue-style-loader',
                  'css-loader'
                ]
            },
            {
                test: (filename, entry) => {
                    return /\.vue\.s[ac]ss/.test(filename);
                },
                use: [
                  'vue-style-loader',
                  'css-loader',
                  'sass-loader'
                ]
            }
        ]
    }
like image 84
Pavel Kalita Avatar answered Dec 13 '22 06:12

Pavel Kalita


No need for a testing function. You can use a negative lookbehind (?<!...) in your RegEx:

rules: [
    // SASS and CSS files from Vue Single File Components:
    {
        test: /\.vue\.(s?[ac]ss)$/,
        use: ['vue-style-loader', 'css-loader', 'sass-loader']
    },
    // SASS and CSS files (standalone):
    {
        test: /(?<!\.vue)\.(s?[ac]ss)$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
    }
]
like image 25
Tomme Avatar answered Dec 13 '22 06:12

Tomme