Sapper - imported scss styles disappear - sass

I have a strange problem which may be related toe tree-shaking. I build a sapper app and in my rollup config, I use the svelte-preprocess package and configure it like this:
const preprocessOptions = {
scss: {
data: `#import '${join(process.cwd(), "src/styles/main.scss")}';`,
includePaths: ["node_modules", "src"],
},
postcss: {
plugins: [
require("autoprefixer"),
require("cssnano")({
preset: "default",
}),
],
minimize: !isDevelopment,
sourceMap: isDevelopment,
},
};
Via the scss plugin I copy the global stylesheet main.scss. All of the styles out of it seem to get applied, except for the styles of the body. Somehow these get ignored, because when I check the body styles in the dev console, it is empty. Can't you access the body in Sapper or is there maybe a special way to do this?

The problem is that with Sapper the body is part of the template.html file. That means there's no component with a body element. Svelte will remove styles that are not used in your component unless they are explicitly marked as global. The global preprocessor can help with this. I think in your case I would just get the bundler to create a separate css file for the template.html and include it explicitly like the global.css:
...
%sapper.base%
<link rel='stylesheet' href='global.css'>
...

Related

Configure SASS Load Path in Nuxt 3

I have my SCSS partials in my Nuxt 3 project's assets/css directory (e.g. assets/css/_cards.scss). I can import them in my components using the full path (#use '~/assets/css/cards';), but I'm having trouble getting the load path working so that I can import like #use 'cards';
From what I've seen, the Nuxt config should look like this to enable that, but this and similar variations are not working for me.
export default defineNuxtConfig({
vite: {
css: {
preprocessorOptions: {
scss: {
loadPaths: ['#/assets/css'],
},
},
},
},
});
This approach is not working for me either. However, my use case is that I wanted some global styles imported, as opposed to every component on its own.
What worked for me was to use css property directly inside defineNuxtConfig object.
export default defineNuxtConfig({
css: ["#/assets/css/_variables.scss"]
});
The correct key to use is includePaths which is documented here. I tried this key before, but the reason it did not work was that I used #/assets/css for the path. The # alias does not work in this option, so I needed to use ./assets/css for the path. Here is the corrected config:
export default defineNuxtConfig({
vite: {
css: {
preprocessorOptions: {
scss: {
includePaths: ['./assets/css'],
},
},
},
},
});

How to customise Bulma variables via Nuxt/Buefy?

How can I customise Bulma variables when using Nuxt and Buefy?
It seems Nuxt is loading Bulma/Buefy before it loads my Sass vars, where I set my custom values.
nuxt.config.js:
export default {
target: 'static',
head: {},
css: [
'~/assets/bulma-vars.sass'
],
plugins: [],
components: true,
buildModules: [
'#nuxt/typescript-build',
],
modules: [
['nuxt-buefy', {css: true}],
],
build: {}
}
bulma-vars.sass:
$danger: orange
How can I set my vars before Bulma/Buefy is initiated?
[--- UPDATE ---]
Following #kissu's idea of doing this via a plugin, I set to work on this.
nuxt.config.js:
plugins: [
'~/plugins/set-bulma-vars.js'
],
plugins/set-bulma-vars.js
#import '~/assets/set-bulma-vars.sass'
assets/set-bulma-vars.sass
$danger: #00f
...but it doesn't seem to the variables in a scope such that Bulma can inherit them, and subsequently my vars are ignored (though the plugin CSS is loaded.)
So the only way I've solved this so far is via my own answer, below.
I have created a /assets/scss/custom_buefy.scss file with variables like this
#import "~bulma/sass/utilities/_all";
// the line above is important
$primary: hsl(168, 59%, 47%);
$link: hsl(24, 94%, 66%);
$info: hsl(200, 100%, 75%);
...
To customize our application.
Then created a /plugins/vue-buefy.js file to import it
import '~/assets/scss/custom_buefy.scss'
And then, imported it into our nuxt.config.js file
plugins: [
{ src: '#/plugins/vue-buefy', mode: 'client' },
],
Working good so far. Maybe not the best configuration, but flexible enough for customizing the CSS and also importing some specific components on demand (and not the whole library).
My starting point was not the CLI tho (I do use the buefy package), so YMMV.
In the end, this is what I did.
First, disable auto-loading of Buefy in nuxt.config.js > modules:
modules: [
['nuxt-buefy', {css: false}],
]
This solves the problem of Buefy (and Bulma) loading before we have chance to set any theme variables.
Next, create a Sass file e.g. bulma-vars.css:
$danger: orange
#import "~bulma/bulma"
#import "~buefy/src/scss/buefy"
(~bulma/bulma and ~buefy/src/scss/buefy are the relative paths to the main Bulma Sass file and Buefy SCSS file, respectively, within node_modules.)
Add this to nuxt.config.js > css:
css: [
'~/assets/bulma-vars.sass'
]
There's probably better ways (I've seen references to doing this via the Nuxt style-resources module, or via a custom plugin - see #kissu's answer) but this at least works.

Importing external stylesheets globally with CSS modules

I'm struggling to add SASS with an external stylesheet (Bulma) to my React application. So far I have set up Parcel with CSS modules via postcss. This is my .postcssrc config:
{
"modules": true,
"plugins": {
"autoprefixer": {
"grid": true
},
"postcss-modules": {
"generateScopedName": "[name]_[local]_[hash:base64:5]"
}
}
}
I have installed node-sass and successfully added a .scss file to one of my components. External (Bulma) styles are added via #import "~bulma/bulma"; and are correctly resolved.
Unfortunately, imported styles are not applied globally and instead the class names are modified similarly to local definitions, e.g.:
/*! bulma.io v0.8.0 | MIT License | github.com/jgthms/bulma */
#-webkit-keyframes container_spinAround_28_Bz {
from {
transform: rotate(0deg); }
to {
transform: rotate(359deg); } }
#keyframes container_spinAround_28_Bz {
from {
transform: rotate(0deg); }
to {
transform: rotate(359deg); } }
Note the added prefixes and suffixes.
Ideally, I would like to import the stylesheet globally and do not modify their names. I'd like to continue using CSS modules and I think I also have to use SASS in order to globally modify Bulma stylesheet by overriding SASS variables.
Anyway, things I've tried so far:
Using postcss-nested and wrapping the import with :global block:
:global {
#import "~bulma/bulma";
}
However, this throws an exception:
main.scss:5018:5: Missing whitespace before :global
Creating a separate scss file included directly in HTML file via <link> rather than imported in a jsx/tsx file to avoid using CSS modules.
This seems to break Parcel entirely, as it fails to link correct files in the compiled HTML files, i.e. <LONG-HASH>.css instead of generated main.<HASH>.css.
Using postcss-import.
Either my setup is incorrect or it has no effect on SASS files.
You can define regular expressions to mark matched files as global stylesheets with the globalModulePaths setting.
"postcss-modules": {
"globalModulePaths": [
".*\\.global\\..*"
]
}
The example above would mark all files with .global. in their name, e.g. main.global.css.
Managed to figure it out while writing the question.
The only solution that worked for me to load global CSS styles from rollup (when applying preserveModules: true) was using the 'rollup-plugin-styles' plugin and the following configuration:
// rollup.config.js
plugins: [
styles({
extensions: ['.css'],
use: ['css'],
}), …
]
// In the package.json you have to add the proper side effects
{
"sideEffects": [
"**/*.css",
"**/*.css.js" //this one is very important too
],
}
// MyComponent.tx
import '../styles/myGlobal.css';

How to get webpack to inline css into the generated html file

I'm trying to get webpack to inline some scss into the generated html file to use as my app-shell css.
The idea is to get webpack bundle any scss file ending in '-file.scss' into a css file and to inline any scss in files ending '-shell.scss'.
This way I would get my app-shell to style before react or anything else loads.
By inline I mean to put it in STYLE tags in the generated html file.
The css part of my webpack is:
{
test: /\.css$/,
include: [paths.appSrc, paths.appNodeModules],
// Disable autoprefixer in css-loader itself:
// https://github.com/webpack/css-loader/issues/281
// We already have it thanks to postcss.
loader: ExtractTextPlugin.extract('style', 'css?-autoprefixer!postcss')
},
{
test: /-shell\.scss$/,
include: paths.appSrc,
loaders: ['style', 'css', 'sass'],
},
{
test: /-file\.scss$/,
include: paths.appSrc,
loader: ExtractTextPlugin.extract('style', 'css!sass'),
},
I had thought that removing the ExtractTextPugin loader from "test: /-shell.scss$/" would do it but it doesn't put those styles into STYLE tags in the generated html build file.
I've adapted the Create React App setup from https://github.com/facebookincubator/create-react-app

How to combine `css-modules` with normal `sass`, preferably in `webpack`

TLDR: How to combine css-modules with normal sass, preferably in webpack.
The Setup:
I am working on the styling build process for an e-commerce website. The site's styles are currently done in sass along with the js through a gulp browserify build process.
I have recently added a single page app that is built using react with webpack and babel. Inside of that application I am taking advantage of css-modules provided by webpack to scope the class names to each react component.
The problem:
I would like to incorporate the styles from the webpack css-modules build in with the main styling bundle for the site. To do this, I was considering building a webpack configuration to build the styles for the whole site. The problem I have is how to get the styles which are currently built by the single page webpack configuration and inject just the style chunk into a global webpack configuration that handles styles for the whole site. I should mention that I would like to keep the two configurations as separate as possible
The Questions:
Is there a proper way of having decoupled webpack builds where one is still able to use chunks from the other?
If so, how do I do it so that the css-module setup stays in the single page configuration, and the extract-text-webpack part along with a boring sass build goes into a global configuarion?
If not, how should I go about having one section of sass go through the css-modules workflow, and still combine it with the bundle from the rest of the site.
Thanks in advance.
EDIT
based on #Alexandr Subbotin's answer, I have updated my webpack to look something like the code below. I did have to change names and paths because of the code belongs to my employer, so there may be slight errors.
var ExtractTextPlugin = require('extract-text-webpack-plugin');
const JSDIR = './build/js/';
const STYLES = './build/css/bundle.css';
module.exports = {
entry : {
'styles' : './src/styles.scss',
'app' : './src/index.js',
// a javascript file that includes the root of the single page app.
'single-page' : './src/single-page/styles-entry.js',
},
output : {
path : JSDIR,
filename : '[name].js', // normally compiles my
publicPath: 'http://localhost:8080/',
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader : 'babel-loader',
query : {
presets: [
'react','es2015','stage-0',
]
},
},
{
test : /\.scss$/,
loader: ExtractTextPlugin.extract('style?sourceMap', 'css?-url&sourceMap!sass?sourceMap'),
exclude : /\/single-page\//,
},
{
test : /\.scss$/,
loader: ExtractTextPlugin.extract(
'style?sourceMap',
'css?-url&modules&importLoaders=1&localIdentName=SinglePage__[name]__[local]!sass?sourceMap'
),
include : /\/single-page\//,
}
]
},
plugins : [
new ExtractTextPlugin(STYLES, {
allChunks : true,
}),
],
resolve : {
alias: {
"eventEmitter/EventEmitter": "wolfy87-eventemitter",
},
extensions: ['', '.js','.jsx'],
},
}
If I understood your question you want to apply css-modules only to one part of your application and leave simple sass building process in other parts.
To do this you can use exclude and include options in loaders. I.e. if you have your single page application inside single-page directory your webpack config can be:
module: {
entry: {
// it is your global sass styles
application_css: './css/application.scss',
// it is main file of your SPA bundle. Somewhere inside you will use require('./styles.scss') that should be processed by css-modules
spa_index: './single-page/index.js'
},
loaders: [
...,
{
// This loader will build all your sass that are not in `single-page` directory
test: /\.scss$/,
loader: ExtractTextPlugin.extract('style', 'css!sass'),
exclude: /\/single-page\//
},
{
// This loader will handle all your css module in `single-page` directory
test: /\.scss$/,
loader: 'style!css?modules!sass',
include: /\/single-page\//
},
],
...
}
So, in this case all css from single-page/ will use css modules, and the rest won't.
EDIT:
If you take a look in API section of ExtractTextPlugin documentation you find
The ExtractTextPlugin generates an output file per entry, so you must use [name], [id] or [contenthash] when using multiple entries.
In your example you have have two chunks with css (styles and single-page), but only one output ./build/css/bundle.css. If you change your output to ./build/css/[name].css your will have two css files: styles.css with your global css and single-page.css with SPA styles.

Resources