Using global css files with CSS Modules - css

I'm using https://github.com/mxstbr/react-boilerplate for a project, which uses CSS Modules and postCSS for the styles, which is great. However, I also need to have some global CSS files for typography, base components, etc. What is the best practice for how these should be added in? I've looked at using preCSS but not entirely sure how to set it up within webpack, so that it can import these global files into the main stylesheet. I'm new to webpack (come from a Gulp/Grunt background, using Sass) so any help here would be much appreciated.
It would also be great if I could use the variables and mixins defined in these files in the CSS Module files, but unsure if this is possible or advised. I've installed react-css-modules so that I can use styleName to refer to the CSS Module file and className to refer to the global CSS classes.
I know there is the composes: class from '/path/to/file.css'; attribute but I would prefer to have some global files where various utility classes are defined, such as clearfix and error classes, etc. So using react-css-modules, it would look something like this:
<div className="clearfix" styleName="app-header">{...}</div>
Again, not sure if this is correct.
I want to stick to best practices as I'm working on an open-source project and want it to be done in the best way possible. Thanks for any advice!

css-modules provides :global that can be used to include locally in your code css files that will included globally in application

I did come across this problem when I wanted to use a 3rd party library that requires some css files that are directly referenced in the js templates (by class name strings) and css modules were not supported. As I did not want to change the css files by adding :global modifier (because they are 3rd party and might change in the future), I've figure out there is a mode setting in the css-loader that you can use to preserve original names for certain files.
How it works:
There is a mode setting in the in the css-loader that (beside other options) accepts a function. It takes a resourcePath as an argument and returns values local, global and pure. Global keeps all the name as they were defined in the original file, while local uses standard hashing as defined. This is handy for third party libraries that don't work with css modules.
I've written a short function that checks the the resourcePath for modules that should stay global. Seems to work fine for me, the only disadvantage is that I have to write it twice (development and production setting).
Here is the development env example:
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[name]_[local]_[hash:base64:6]',
exportLocalsConvention: 'camelCase',
mode: (resourcePath) => {
let globalStyles = ['module-to-stay-global-1', 'module-to-stay-global-2'];
return globalStyles.some(globalFile => resourcePath.includes(globalFile)) ? 'global' : 'local'
}
},
}
}
Documentation to the mode function can be found here:
https://github.com/webpack-contrib/css-loader#function-3

Related

How to use Sass in blazor?

I found MS DOC about Css in razor. But it isn't work with Scss file.
I resolve this problem by creating two files: css and scss. And use sass --watch. But I need write this every time, when creating new component.
Unfortunately SASS is not supported for CSS Isolation feature of Blazor. At least, not at this moment.
In our project, we use CSS Isolation for the CSS component isolation feature, but we use SASS files to manage our theme, for style we want accros the application.
That being said, if you really need some SASS for an unique component, you totally can, by adding for example a wrapper with a specified id, and use this id in your scss file, with a dedicated name for it, for example MyComponent.scss.
In addition, I've found this article, but I preferred to not use it because it is a bit heavy to setup, but up to you: https://joren-thijs.medium.com/how-to-add-scss-support-to-blazor-cd2a62995441
You can use AspNetCore.SassCompiler which supports both normal and isolated scss. I believe it has a watch mode when using Blazor Server, WASM is not supported yet.
It can also do minification with source mapping.

Conditional stylesheet in Nuxt SSR depending on a store value

I've been surfing StackOverflow and the Nuxt documentation, but I cannot get my head around this one.
So, I need to do RTL. My project is in Nuxt and we use SCSS. I'm setting the htmlAttrs to dir="rtl" conditionally depending on a store getter that tells me if the language is RTL or not. The requirement for this specific task is that a RTL stylesheet should be imported conditionally from the server side also if the country is RTL, so that it overrides the main.scss file.
Now, in nuxtServerInit(), I cannot set the stylesheet in the head, because the route will not direct me to the file, and, most importantly, Webpack won't compile it, as it's outside the regular flow of the application and not imported by main.scss, which is the stylesheet the Nuxt config is pointing to, and which contains all other styles. I realize that I could use a class and use it conditionally in components, but that is not the requirement. The nuxt.config.js file, in the relevant part, looks like this:
css: [
'#/assets/styles/main.scss'
]
There I obviously don't have access to the store.
What I said I tried was this:
if (isRTL) {
service.addEntryToArray('link', {
rel: 'stylesheet',
type: 'text/css',
href: '../assets/styles/main.rtl.scss'
});
}
(We use a service to add things to the head)
I understand that was naive on my part, because Webpack has no say there, so there is no transpilation, and there is no actual asset, which means the route is just wrong, and even if it were right, the browser would not be able to read it.
Any ideas on how this could be achieved at a non-component level? This needs to be part of the Webpack flow, has to be added server-side, and needs to be an import --I cannot just import it regularly and use just a class (again, I'm not stubborn, I'm working on a project, and this is a requirement by the client).
If you need more information, I'll update the post, but I don't know what else to provide.

Svelte/Sapper Build - Seemingly old CSS still exists after building?

I just committed and pushed a minor CSS tweak. On my server I git pull, npm run build, and forever restart __sapper__/build
Now there seems to be more than one version of the same CSS rule across different files, as per the below screenshot (this is after disabling browser cache):
The correct rule is the third one (vertical-align: top; margin-top: 1px;), which seems to be a combination of CSS files.
Any idea where the 'old' rules are coming from? Cached somewhere somehow?
/EDIT This is my rollup.config.js: https://gist.github.com/Bandit/bbcfd6c70ace5800765313dfe6021854
/EDIT2 The styles in question are in a /style/global.scss file, which is included using the following code in /routes/_layout.svelte:
<style lang="scss" global>
#import "./style/global.scss";
main {
background-color: white;
padding: 5rem 1rem 0 1rem;
}
</style>
Guessing this is somehow the issue? Where is the right place to 'inject' global stylesheet for colours/theme/typography etc?
/EDIT3 The styles being included via _layout.svelte are being included more than once in dev as well, here's a screenshot:
These selectors don't seem to come from a Svelte component, since they're not scoped (e.g. .split-button.svelte-a9ylb1)? Or are you using :global(.split-button) in a Svelte component?
Anyway... I failed to reproduce your issue, but my intuition is that your problem probably comes from the postcss plugin. It has an inject option that is enabled by default. What this option does is injecting a <style> tag in the <head> of your doc; the code that does this is appended to your modules' JS by the postcss plugin. This behaviour might very well clash with what svelte-preprocess or rollup-plugin-svelte is doing.
Try adding inject: false in the 3 places where you're using postcss in your Rollup config, and see if this helps.
Another possibility might be the service worker. I don't think an issue there could produce your result you get, but we never know... You should try options like "Update on reload" and "Bypass for network" (I don't know what are the equivalent options in your browser) to see if that makes a difference.
Otherwise, you may have to show more of your code. Where does this precise CSS rule come from (e.g. style tag in a Svelte component, SCSS file in node_modules, ...)? How is it imported into your project (e.g. import './app.css', #import './app.scss', etc.), and where? Also, I'm surprised that you have the postcss rollup plugin only in the server (the one that is not registered in sveltePreprocess)... What do you need this for, that you don't need on the client?
EDIT: Follow up
Wait, what? You've got some style files under your routes directory?? routes/style/global.scss?
Even with that, I don't appear to be able to reproduce your problem, but it's worth noting that Sapper will try to include every file it encounters under this directory. If you've got a plugin that lets you import *.scss files, then Sapper will actually see a global.scss.js, so it will think it's a server route. Without a plugin that can eat SCSS, it should... crash. If the plugin in question is postcss with its default inject option still to true, to me it looks like a star suspect...
Anyway, some further points of clarification...
svelte-preprocess enables lang="xxx", global attribute in <style global ...>, in .svelte files only.
rollup-plugin-postcss can additionally be added, directly in plugins array (i.e. not as an option of svelte plugin). It gives support for import './foo.scss', in .js files, as well as in the <script> part of .svelte files.
(Of course, SASS support by PostCSS, or PostCSS support by Svelte preprocess are depending on the config you feed them.)
OK. So now there are multiple places where some CSS / SCSS can enter your build. That I can think of, there are the following ways:
<link rel='stylesheet' href='global.css'> in src/template.html: this one will copied as is without processing.
I suppose you can also have such a "custom" <link> tag in the markup (~HTML) part of a .svelte file, and it would be included as is in the resulting HTML (you'd still have the responsibility that the reference CSS file be accessible at the given URL).
import 'something.css' or 'import 'something.scss'in a.jsor JS part of a.sveltefile: these will get processed by bundler & plugins, and converted to some JS code, with optionally additional assets that the JS can reference (typically, a proper CSS file is generated, and some JS code dynamically injects atag for it at runtime; another approach is to generate some JS that will inject every CSS rule in the doc). PostCSS withinject: true` uses the CSS + inject tag method.
the CSS / SCSS style that you write in the <style> part of a .svelte file will also be processed by the Svelte plugin in a similar way as described just before (preprocess option required to accept anything else than raw CSS); depending on the plugin configuration, it may also try to write a '.css' file for your application (see docs. With the emitCss option, that is apparently needed for Sapper, it should output one CSS file per component (or maybe entrypoint).
In your case, you say that you've removed rollup-plugin-postcss from your config, so the 3rd point (import css from js) should not be possible anymore.
Well... I just hope this can help you investigate further.
I've pushed a Sapper + PostCSS example on a branch on this repo. As far as I can tell, it doesn't have the issue you're describing here. So maybe you can find the problem by comparing with what you have. See this commit for the diff with the vanilla official template.
I tried to also add rollup-plugin-postcss, like you initially had in your config, in order to be able to import .scss from outside of Svelte components. But I failed to find a way to do this that don't conflict with Sapper.
EDIT 2
Oh, and just to be sure... Be sure to try a little rm -r __sapper__ && rm -r src/node_modules/#sapper (notice: node_modules under src, not the one in your project's root) before pursuing your investigation. I'm sure you've already done that, but better safe than sorry. Stale things can live in there.

CSS modules and rollup - generating separate CSS files ("themes") with same hashes

I'm using CSS Modules (Sass) with rollup on a component library project, which is working well. Each component ends up with a dist folder containing a single JS bundle file, and a corresponding CSS file with the scoped CSS classes so consumers of the component don't have to worry about CSS class name conflicts. All they do is include the JS bundle and the CSS file and everything is great. Yay CSS Modules.
The problem I'm now facing is that some components really need separate "themes" - ideally, separate CSS files, one per theme. So consumers can continue as they've been doing: including the JS bundle, but now choosing which CSS file to include to pick a theme.
I'm not sure how to get this going with CSS modules & rollup, and whether this is even the sort of approach others are taking. From what I can see, rollup always handles bundling things together, whereas I want separate CSS files, all of which get their classes renamed identically during the build phase. That way, if within my JS I refer to styles.myclass, if myclass had gotten renamed to scoped-myclass by CSS modules for the original CSS file, for a second CSS file it would also get the same name.
This would keep consumption of the component extremely simple - just a matter of including a different CSS file.
Any suggestions?
Awfully late, but let me answer this 3 years on. So what I ended up doing was totally detaching the CSS generation step from rollup and relying on the Sass CLI to handle that portion of the build process. It felt a bit klutzy, but I remember it wasn't awfully hard to do and solved the problem I outlined above. I don't believe there was a plain rollup solution at the time, nor do I think there's one today.
However... in my case the whole approach was kinda mistaken. This certainly won't be everyone's scenario, but let me spell it all out because hey it may be useful and it definitely wasn't obvious to me at the time.
This was for an in-house shared component library, where each component and its corresponding CSS was a separate npm package stored in our Artifactory. When it grew, plenty of internal references popped up, e.g. multiple components would reference the Button component, and over time they'd reference different versions of the Buttons component - each of which needed its own properly scoped CSS, unique to that package-version.
So what I found was that by doing it this way - having the CSS generated as part of the npm package dist files - I had to write an additional layer for the consumer applications that would parse their node_modules/ folder for our own internal components and combine all the different CSS files, such as the multiple versions of buttons. e.g. the main application would directly import buttons v1.0.0 in its package.json file, but the Dialog component (also included in the package.json) could include buttons 2.0.0 as its own dependency. For every version of the package, there was a uniquely scoped version of the CSS - so the consuming application HAD to include every version otherwise the styling would be borked.
So all in all, it ended up being way more complex that I wanted. I thought I could make it easier & better with the separate generated themed CSS files as part of the package dist, but it didn't end up that way. If I could revisit that project today, I'd re-examine a solution used by Material UI and others which I kinda poo-poo'd at the time: automatic injection of the CSS into the page by the component JS, rather than generating standalone CSS files which required extra work by the consumer applications to gather up and add to the final webpage. Frankly, now I regard it as the "least crap". There are definite downsides to the injection approach (extra work done on every page render for everyone! Yikes!), but there's no doubt in my mind it hugely simplifies the job of the consumer applications. It's a balancing act, but in 20-20 hindsight I'd lean towards the injection approach. With that, scoping & theming is a different and much simpler problem.
If I got you right, consider looking at SCSS plugin: rollup-plugin-scss. It captures all spare .css files imported in the components, and then processes them through underlying node-sass. The catch is, it seems like you can write a custom callback function that'd handle your CSSs differently based on conditions you throw in.
Based on the example from the plugin's page:
import scss from 'rollup-plugin-scss'
...
export default {
input: 'src/index.tsx',
output: [...],
plugins: [
...
output: function (styles, styleNodes) {
// replace this with conditioned outputs as needed:
writeFileSync('bundle1.css', styles)
writeFileSync('bundle2.css', styles)
},
]
}

EmberJS CSS options

I'm trying to sift through all the CSS options / packages available for EmberJS and am looking for suggestions. I suppose it will help if I list what I need:
SASS syntax (variables, nesting, creating mixins, and extending)
Ability to import other CSS libraries
Pod support (although I'm not positive I'll be using this feature at the moment, but I at least want to be able to have one CSS per route/component)
Autoprefixer
Is there an all-in-one Ember package that will give me all these? Thanks!
SASS syntax (variables, nesting, creating mixins, and extending)
You should think long and hard before taking the blue SASS pill. SASS is a technology trending towards obsolescence, which was designed mainly to support some bad CSS coding practices, as well as overcome some deficiencies in earlier versions of CSS.
Variables are supported by postCSS plugins in a standard way which is compatible with the upcoming CSS variable syntax.
Nesting is an answer in search of a problem. It promotes a bad style of coding involving excessive dependency on HTML structure. Properly constructed systems of CSS classes, orthogonal to HTML, make nesting unnecessary.
With regards to mixins, I have not seen a real-life situation in which mixins or other more advanced SASS features were actually necessary. Using them, you end up learning yet another (weird) programming language, which you have to debug, and make sure all the people on your team know.
When it comes to extending, CSS experts counsel against it. Besides potential issues of performance and code size, they hide the logic of the CSS code, and require jumping back and forth from file to file to maintain and extend and debug. Everything that is accomplished with extending can be handled with properly-designed CSS classes.
SASS is slow, is bifurcated (binary version vs. Ruby version), and can give rise to strange npm installation problems. My advice is to avoid it.
There is an interesting read about SASS vs. postCSS here.
Ability to import other CSS libraries
Ability to import other CSS libraries is not a function of any other decision you make, or what package you choose. You can simply import these.
Pod support (although I'm not positive I'll be using this feature at the moment, but I at least want to be able to have one CSS per route/component)
Indeed. There is at least one new-ish Ember add-on to do this (and probably more), which IMHO is designed extremely poorly and grossly over-engineered. It follows the Ember approach of doing way too much, in an opaque way, in the name of being "helpful" (until it isn't, at which point you're screwed). This is great if you want your CSS to be littered with classes like .my-component-a34fba.
Until there is a better alternative, I'd do this manually, which is quite easy. Simply place your CSS files in the pod, and then import, from your styles/app.css or equivalent file, the CSS files from the pods you want, such as #import '../pods/thingie/; to import its index.css file. Yes, you will have to do some maintenance of these imports yourself, but how many pods do you have?
What I do to avoid a huge styles/app.css that would require constant updating is to place an index.css file in each pod and import that. From there, import a stylesheet for that directory itself and any necessary subdirectories:
/* styles/app.css */
#import '../app/pods/thingie';
/* app/pods/thingie/index.css */
#import `./style`;
#import `./subdir1';
#import `./subdir2';
Autoprefixer
You need look no further than the excellent postcss/autoprefixer.
Is there an all-in-one Ember package that will give me all these?
It would be nice if all our problems could be handled by all-in-one packages. Unfortunately, all-in-one packages are always missing two features we wanted, and we can never figure out how to add them. They always do one thing we didn't want them to do, and we can never figure how to turn it off. They import old versions of their subpackages. They break when there's an Ember upgrade. They stop being maintained. The Ember philosophy itself sadly promotes this pernicious all-in-one mentality--all my problems can be solved by yet another add-on!
You are better off understanding individual technologies, choosing simple, bounded, reliable implementations of them, and weaving them together yourself. Just my two cents.
This might be the closest thing you're looking for:
https://github.com/ebryn/ember-component-css
Which supports using pods layout, and lets you use ember-cli-sass.
To use auto-prefixing, there are plenty of sass libraries out there to help you out, like Bourbon.io, which you can install via npm. Then, it should just be matter of configuring the import paths via the sass options in the ember-cli-build.js
I recommend PostCSS. Last I checked, it doesn't work out-of-the-box with ember-component-css, but you don't need ember-component-css to namespace your styles.
You can modify Ember's Component generator / blueprint to (assuming you're using pods):
Add classNames: ['component-name-here'], to the generated component.js file.
Create a _component-name-here.css file/partial in app/styles/components (or similar), with a class .component-name-here to contain all styles in the partial.
If necessary, #import that new partial in your app.css.
Then all your Component styles will be namespaced.
To handle variables, nesting and Autoprefixer, you just need to set up PostCSS with the right plugins, e.g.:
plugins: [
{
module: require('postcss-partial-import'),
},
{
module: require('postcss-nested'),
},
{
module: require('postcss-custom-media'),
},
{
module: require('postcss-custom-properties'),
},
{
module: require('autoprefixer'),
options: { browsers: ['last 2 versions'] }
},
],
I'm using ember-cli-css-preprocess, which gives you the option to use SASS as well (alongside PostCSS), if you wish.

Resources