How to preprocess scoped css (sass) - riot.js

Does anyone know how to do this? Riot scoped css would be awesome if only I could use SASS. I checked the docs but couldn't understand what's required.
I would like to be able to:
<style scoped>
#extend %my-sass-extension;
h1 {
color: $my-color;
}
</style

You can import scss in script tagļ¼Œ if you use webpack, like this:
<script>
import './page-head.scss'
</script>
And my webpack config:
// webpack.config.js
module.exports = {
...
module: {
rules: [{
test: /\.scss$/,
use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "sass-loader" // compiles Sass to CSS
}]
}]
}
};

Related

How can I use CSS Modules from my main global scss stylesheet?

I need to extend the CSS Loader for Nuxt.js so I can use modules within my global .scss files in assets/scss/screen.scss.
This is taken from the Vue.js site.
// webpack.config.js
{
module: {
rules: [
// ... other rules omitted
{
test: /\.css$/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: {
// enable CSS Modules
modules: true,
// customize generated class names
localIdentName: '[local]_[hash:base64:8]'
}
}
]
}
]
}
}
Problem is I don't know where to put this in my Nuxt.config.js for what I have tried fails.
If I place here:
build: {
extend(...){
config.module.rules.push({
test: /\.scss$/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: {
// enable CSS Modules
modules: true,
// customize generated class names
localIdentName: '[local]--[hash:base64:8]'
}
}
]
});
}
}
It throws
Error: Cannot read property 'forEach' of undefined at at node_modules\#nuxtjs\style-resources\lib\module.js:88:18
I am confused because I am already extending it successfully in my nuxt.config.js to allow for CSS modules INSIDE of each component.
loaders: {
cssModules: {
modules: {
localIdentName: process.env.NODE_ENV === "production"
? "[hash:base64:6]"
: "[local]--[hash:base64:6]"
}
}
},
But I can't call a CSS class as a module from my main 'global' stylesheet. No error, it just can't find it.
/assets/scss/screen.scss
.triangle{
background:red;
}
Can't be linked-to in my Nuxt file as
<div :class="$style.triangle"></div>
Just like it can if I add the CSS directly within my module. I wonder why I can't access CSS Modules this way? But I can if it's directly within a component using
<style module lang="scss"></style>
Am I able to use CSS modules from a main global stylesheet?

Can't compile sass while using Vue Storybook

I'm trying to create storybook on vue. My components written using sass. So, I made this in .storybook/main.js:
webpackFinal: (config) => {
config.module.rules.push({
test: /\.s[ac]ss$/i,
use: [
// Creates `style` nodes from JS strings
'style-loader',
// Translates CSS into CommonJS
'css-loader',
// Compiles Sass to CSS
'sass-loader',
],
})
return config
}
And the styles looks like this:
<style lang="sass" scoped>
button
background-color: red
</style>
So I'm getting this error when trying to compile:
SassError: Invalid CSS after "": expected 1 selector or at-rule, was "button"
on line 1 of C:\Code\testproj\src\components\UI\TestComponent.vue
And if I change my style to this:
<style lang="sass" scoped>
button {
background-color: red
}
</style>
All works, but that's not a sass syntax.
I was having this exact same issue and I was able to solve it. The issue is from the webpack config. If you're using SASS, your webpack.config.js file in your .storybook folder should look like this:
module.exports = ({ config }) => {
config.module.rules.push({
test: /\.sass$/,
use: [
require.resolve("vue-style-loader"),
require.resolve("css-loader"),
{
loader: require.resolve("sass-loader"),
options: {
sassOptions: {
indentedSyntax: true
}
}
}
],
});
return config;
};
And if you're using SCSS, then it should be like this:
module.exports = ({ config }) => {
config.module.rules.push({
test: /\.scss$/,
use: [
require.resolve("vue-style-loader"),
require.resolve("css-loader"),
require.resolve("sass-loader"),
],
});
return config;
};
I was able to figure this out while reading the Vue Loader Docs
The problem is that in your webpack config, you are telling webpack that only use sass-loader when de extension of your file was test: /.s[ac]ss$/i That is to say .sass or .scss. However the extension of your file is .vue, because you are using sass in the vue file of your component.
With that configuration, try to put your sass style in a .sass file and check if works
For anyone using React 17+ with Storybook 6.4.9+, I had a similar problem where the Storybook/webpack build was not including my SCSS files. This configuration in .storybook/main.js worked for me:
module.exports = {
"stories": [
"../src/**/*.stories.mdx",
"../src/**/*.stories.#(js|jsx|ts|tsx)"
],
"addons": [
"#storybook/addon-links",
"#storybook/addon-essentials"
],
"framework": "#storybook/react",
webpackFinal: async (config) => {
// add SCSS support for CSS Modules
config.module.rules.push({
test: /\.scss$/,
use: [
require.resolve("style-loader"),
require.resolve("css-loader"),
require.resolve("sass-loader"),
],
});
return config;
}
}
I spend a lot of time to find better solution. It is may main.js config file for Storybook 6.4.9:
const path = require('path');
module.exports = {
"stories": [
"../src/**/*.stories.#(js|jsx|ts|tsx|mdx)"
],
"addons": [
"#storybook/addon-essentials",
"#storybook/addon-actions",
"#storybook/addon-controls",
"#storybook/addon-links",
{
name: '#storybook/preset-scss',
options: {
sassLoaderOptions: {
implementation: require('node-sass'), // ATTENTION: We need to use "node-sass" instead "sass/dart-sass"
sassOptions: {
indentedSyntax: true
},
},
}
},
"#storybook/addon-postcss",
],
"framework": "#storybook/vue",
features: {
babelModeV7: true,
},
webpackFinal: async (config, { configType }) => {
// `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
// You can change the configuration based on that.
// 'PRODUCTION' is used when building the static version of storybook.
// ATTENTION: Need to preload "global.sass" style for all elements;
config.module.rules.map(rule => {
if (rule.test instanceof RegExp && rule.test.toString() === '/\\.s[ca]ss$/') {
rule.use.push({
loader: require.resolve('sass-resources-loader'),
options: {
resources: [
path.resolve(__dirname, '../src/styles/global.sass')
]
}
})
}
return rule
})
// ATTENTION: Need to compile "Pug" templates.
config.module.rules.push(
{
test: /\.pug$/,
oneOf: [
// this applies to `<template lang="pug">` in Vue components
{
resourceQuery: /^\?vue/,
use: ['pug-plain-loader']
},
// this applies to pug imports inside JavaScript
{
use: ['raw-loader', 'pug-plain-loader']
}
]
}
);
// Return the altered config
return config;
},
}

Webpack + vue-loader + postcss-modules results in empty $style object

In my app I'm initializing a Vue app, which uses single file .vue components.
I use Webpack to bundle, and vue-loader + postcss-modules to generate scoped classes.
But for some reason I can't access the generated classes inside my components ($style object is empty). I'll explain the problem below and created this repo as an example.
My hello.vue component looks like this:
<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 is generated as expected (CSS Modules mapping):
{"hello":"_hello_23p9g_17"}
Scoped styles are appended in the document head, and when using mini-css-extract-plugin it is bundled in app.css:
._hello_23p9g_17 {
background: lime;
}
Does anyone know what the problem is and possibly how to fix this?
Below my config files.
webpack.config.js (trimmed for readability)
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": {}
}
};
EDIT:
FYI, setting modules: true in the css-loader options works in that it populates the $style object (see docs):
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
modules: true
}
}
]
}
But in our app we use postcss-loader (as per docs) that takes care of all transformations including scoping. Enabling both modules: true and postcss-modules conflicts and breaks the classes/mapping (as expected).
In other words, I'm looking for a way to omit the modules: true option and enable css modules using postcss-modules instead.
Found a workaround: manually import the styles from the JSON file.
If anyone knows a better way please let me know :)
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>
This only works when using postcss-modules (loaded from config by postcss-loader in my case) instead of using modules: true:
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
importLoaders: 1
}
},
"postcss-loader"
]
};
See this PR as a full example.

Using module in vue.config.js

I am trying to use the following code in my vue.config.js file, but it is giving me errors that module is not allowed. I am aware that there are configureWebpack and chainWebpack options, but I have no idea how to convert the following to use them. Any help would be appreciated
var path = require('path');
module.exports = {
foo:{},
bar{},
// Putting module in here does not work
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
'scss': [
'vue-style-loader',
'css-loader',
{
loader: "sass-loader",
options: {
includePaths: [
path.resolve(__dirname, "./node_modules/#syncfusion")
]
}
}
]
}
}
}
]
}
}
and in my vue file
<style lang="scss">
#import 'subfolder-inside-syncfusion/some-file.scss';
</style>
Link to code I found:
https://www.syncfusion.com/forums/139116/scss-files-when-included-in-my-file-doesnt-work-as-expected
You dont have to tap into the webpack config, if all you need is to include a global SCSS file. To import #syncfusion from node_modules, you can setup your vue.config.js like so:
css: {
loaderOptions: {
sass: {
data: `#import "~#syncfusion";`
}
}
}
For more info, see the Vue docs "Working with CSS".

Vue CLI: set default style language to scss

Is there an option in Vue CLI (like in Angular CLI) to set the default language used in component styles to "scss"?
Must I set lang="scss" in all my style markups by myself?
You can try to setup your loaders in webpack config in a correct order.
And in there isn't a specific item called scss it is sass here which will handle .scss
module: {
loaders: [{
test: /\.js$/,
loader: 'babel',
exclude: /node_modules/
}, {
test: /\.vue$/,
loader: 'vue'
}, {
test: /\.s[a|c]ss$/,
loader: 'style!css!sass'
}]
},
vue: {
loaders: {
scss: 'style!css!sass'
}
}