Global Sass Import & Usage - Nuxt 3 Static Assets - vue.js

I am trying to import a global Sass stylesheet from the /assets directory and use stuff like variables and mixins defined there throughout the components. My nuxt.config.ts looks like this currently:
import { defineNuxtConfig } from "nuxt3";
export default defineNuxtConfig({
css: ["#/assets/styles/main.sass"],
styleResources: {
sass: ["#/assets/styles/main.sass"],
},
build: {
extractCSS: true,
styleResources: {
sass: "#/assets/styles/main.sass",
hoistUseStatements: true,
},
},
// buildModules: ["#nuxtjs/style-resources"], // This throws error
vite: {
css: {
loaderOptions: {
sass: {
additionalData: ` #import "#/assets/styles/main.sass"; `,
},
},
},
},
});
When I try to use a variable now, I get [plugin:vite:css] Undefined variable. error. This used to work very well in Nuxt 2 with #nuxtjs/style-resources but I'm not sure how to make this work in Nuxt 3.
However, classes and applied styles from that stylesheet are working, only varibles, mixins and maps are not accessible.
Can someone please help?

Okay, so this solution worked, after playing around for a while.
import { defineNuxtConfig } from "nuxt3";
export default defineNuxtConfig({
css: ["#/assets/styles/main.sass"],
vite: {
css: {
preprocessorOptions: {
sass: {
additionalData: '#import "#/assets/styles/_variables.sass"',
},
},
},
},
});
Here,
main.sass contains the classes and styles.
_variables.sass contains the mixins, variables, maps, etc.
Note that in _variables.sass, you need to have an empty line at the beginning of the file to avoid error. It's a problem we're facing at the moment, hopefully will be solved soon.

It's not necessary import defineNuxtConfig
This works for me:
// nuxt.config.ts
export default {
css: ['#/static/assets/scss/base.scss'],
vite: {
css: {
preprocessorOptions: {
scss: {
additionalData: '#import "#/assets/style/global.sass";'
}
}
}
}
};

I'm using Nuxt 3 with TS setup and today is February 16, 2023 in the US. After trying many different variations, it would not work for me without the semi-colon at end of _variables.scss although I do agree with Juan, that first line of import { defineNuxtConfig } from nuxt3 is not needed.
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
app: {
head: {
htmlAttrs: { lang: "en" },
},
},
css: ["#/assets/styles/main.scss"],
vite: {
css: {
preprocessorOptions: {
scss: {
additionalData: '#import "#/assets/styles/_variables.scss";',
},
},
},
},
});
Image of my IDE and terminal messages

Related

How do I load an external stylesheet in Nuxt 3?

I am trying to load the mapboxgl stylesheet in my Nuxt 3.0.0-rc.8 app. Typically with a Vue projec I manually add it to the head of the index.html page.
However, that is not how you do in Nuxt 3 apparently. I've tried adding it to the head and css options in the nuxt.config.ts file, but neither got me there. I did notice that when I added it to the css array, it was added to my header but 'https://' was replaced with '_nuxt'.
I know I am missing something simple. Here is my config file:
export default defineNuxtConfig({
css: [
'~/assets/css/main.css',
],
build: {
postcss: {
postcssOptions: require('./postcss.config.js'),
},
},
buildModules: ['#pinia/nuxt'],
runtimeConfig: {
treesAPIKey: '',
public: {
baseURL: '',
mapToken: '',
},
},
head: { link: [{ rel: 'stylesheet', href: 'https://api.mapbox.com/mapbox-gl-js/v2.6.1/mapbox-gl.css' }] },
});
Use app.head instead of head.
import { defineNuxtConfig } from 'nuxt'
export default defineNuxtConfig({
app: {
head: {
link: [{ rel: 'stylesheet', href: 'https://api.mapbox.com/mapbox-gl-js/v2.6.1/mapbox-gl.css' }]
}
}
})

How to setup sass to use tabs as default on Vue?

I have a large project that use tabs for indentation, but after some update I can't build the project anymore. Sass alway return the error "Syntax Error: SassError: Expected spaces, was tabs."
How can I configure Sass to use tabs insted os spaces in Vue 2? My vue.config.js:
const path = require('path')
module.exports = {
productionSourceMap: true,
configureWebpack: {
devtool: 'source-map',
resolve: {
alias: {
'#ui': path.resolve(__dirname, '../ui'),
}
},
},
css: {
loaderOptions: {
sass: {
sassOptions: {
indentType: 'tab',
indentWidth: 1
},
additionalData: `#import "../ui/style/_main.sass"`
},
scss: {
additionalData: `#import "../ui/style/_margins.scss";`,
sassOptions: {
indentType: 'tab',
indentWidth: 1
}
},
}
}
}

Webpack control of output css file names

I'm trying to control the filenaming of files produced from a Vue app with Webpack.
The environment where I want to host the built app doesn't like filenames with '.' (don't ask).
I have been able via get js files to comply with a 'hyphen' naming scheme by using output.filename in vue.config.js configureWebpack entry. But css files are not renamed.
As I am loading the two bulk packed files rather than chunks I can obviously manually rename the single css file. However when I run it I get an error
Error: Loading CSS chunk error failed.
(/my-path/resources/css/error.d0f9a634.css)
I'm hoping I can force all css files (including the error one) to be renamed by the build process.
My vue.config.js
module.exports = {
outputDir: path.resolve(__dirname, 'dist'),
publicPath: "/my-path/resources",
configureWebpack: {
optimization: {
splitChunks: false
},
output: {
filename: "[name]-js",
chunkFilename: "[name]-chunk-js",
// get cssFilename() {
// return "[name]-css";
// }
},
resolve: {
alias: {
'vue$': path.resolve('./node_modules/vue/dist/vue.common.js'),
},
},
},
// https://cli.vuejs.org/config/#productionsourcemap
productionSourceMap: false,
// https://cli.vuejs.org/config/#css-extract
css: {
extract: { ignoreOrder: true },
loaderOptions: {
sass: {
prependData: '#import \'~#/assets/scss/vuetify/variables\''
},
scss: {
prependData: '#import \'~#/assets/scss/vuetify/variables\';'
}
}
},
// ...
}
I have started to look at MiniCssExtractPlugin but not sure if that is the right direction to look. Any help appreciated.
I found a working solution for this via the css.extract element in vue.config.js.
configureWebpack: {
optimization: {
splitChunks: false
},
output: {
filename: "js/[name]-js",
chunkFilename: "js/[name]-chunk-js",
},
...
},
// https://cli.vuejs.org/config/#css-extract
css: {
extract: {
ignoreOrder: true,
filename: 'css/[name]-css',
chunkFilename: 'css/[name]-chunk-css',
},
loaderOptions: {
sass: {
prependData: '#import \'~#/assets/scss/vuetify/variables\''
},
scss: {
prependData: '#import \'~#/assets/scss/vuetify/variables\';'
}
}
},
...
Which as the documentation link for css.extract says
Instead of a true, you can also pass an object of options for the
mini-css-extract-plugin if you want to further configure what this
plugin does exactly
and is covered by the webpack mini-css-extract-plugin documentation

Rollup not allowing SASS variables

I'm trying to setup a SASS structure in my Rollup config that would allow me to use variables throughout the application. I'd like to use postcss + autoprefixer. I've setup the following in my plugins array:
postcss({
modules: false,
extensions: ['.css', '.sass', '.scss'],
output: false,
extract: true,
plugins: [autoprefixer],
use: [
[
'sass', {
includePaths: [path.join(__dirname, 'scss')]
}
]
]
})
That works well, I'm able to import my SCSS files within my components ie. import "./App.scss";.
The problem I'm facing is I have a number of global variables declared in App.scss and I'd like to use those variables in components that are imported in children.
How would I go about doing that? I thought this plugin would resolve all the SCSS, concat then run postcss + SASS against it, but seems like that's not the case.
Adding my github comment here:
https://github.com/sveltejs/language-tools/issues/232#issuecomment-801549706
This worked for me:
svelte.config.js
module.exports = {
preprocess: autoPreprocess({
scss: { prependData: `#import 'src/styles/main.scss';`},
postcss: { plugins: [require('autoprefixer')] }
}),
#};
rollup.config.js
svelte({
dev: !production, // run-time checks
// Extract component CSS — better performance
css: css => css.write(`bundle.css`),
hot: isNollup,
preprocess: [
autoPreprocess({
scss: { prependData: `#import 'src/styles/main.scss';`},
postcss: { plugins: [postcssImport()] },
defaults: { style: 'postcss' }
})
]
}),
App.svelte
<style global lang="scss">
</style>
If you want the errors in terminal to go away on rollup.config.js
svelte({
dev: !production, // run-time checks
// Extract component CSS — better performance
css: css => css.write(`bundle.css`),
hot: isNollup,
preprocess: [
autoPreprocess({
scss: { prependData: `#import 'src/styles/main.scss';`},
postcss: { plugins: [postcssImport()] },
defaults: { style: 'postcss' }
})
],
onwarn: (warning, handler) => {
const { code, frame } = warning;
if (code === "css-unused-selector")
return;
handler(warning);
}
}),
The coolest thing is my main.scss file can import partials.
#import 'resets';
#import 'border_box';
#import 'colors';
#import 'fonts';
#import 'forms';
Documentation here: https://github.com/sveltejs/svelte-preprocess/blob/main/docs/getting-started.md

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.