Include external CSS in an Angular library by modules - css

I am working on an angular design library based on bootstrap, similar to ng-bootstrap
I currently created multiples modules for each design component that can be imported separately based on user needs.
ex :
src/
modules/
inputs/
buttons/
navs/
tooltips/
....
Each module can be imported independently and used in application.
The problem I face is with bootstrap scss. Has explained here we can import all bootstrap with
#import "../node_modules/bootstrap/scss/bootstrap";
or by chunk
#import "../node_modules/bootstrap/scss/root";
#import "../node_modules/bootstrap/scss/reboot";
#import "../node_modules/bootstrap/scss/type";
#import "../node_modules/bootstrap/scss/images";
#import "../node_modules/bootstrap/scss/containers";
#import "../node_modules/bootstrap/scss/grid";
I would like each of my modules to import their specific scss files. The table would import the tables scss, the navs the navs etc...
Since bootstrap files are scss they need to be compiled before added to the page, and the easy solution of manually adding in each module a stylesheet element would not work.
In ng-bootstrap they require users to manually add each bootstrap scss that they wish to use, but this could be kind of a pain for users since they need to manually add a module and the associated styles.
Are there any solution to bind a scss file to a module, and compile it if that module is used in the app ?

I would follow in the footsteps of Angular Material's implementation and provide users of your library instructions on how to include the design library styles default styles or custom styles. Take a look at Angular Materials build code and the corresponding exported assets made available as an NPM package. Essentially to manually import a single SCSS file per module that is imported as described above a user would need to take the following steps and understand the styles will be applied globally. There is no dynamic inclusion and compilation of SCSS in Angular upon loading of a module the chunks under the hood would need to be recompiled and the styles would be preprocessed again.
In angular.json under the "build.options" object modify "styles" and "stylePreprocessorOptions" and update the configuration to point to the new global styles directory "entry" such as "styles":["src/styles/styles.scss"], "stylePreprocessorOptions": { "includePaths": [ "styles" ] } then in styles.scss import your bootstrap scss. Under the styles directory you can now create a custom directory structure and the angular compiler will be able to find everything imported in the global "styles.scss" file. Further reading: read about the shadow DOM in Angular in the context of styles applied based on view encapsulation for component scoped styles vs. globally applied styles.

Related

How to get Storybook to use a project's CSS variables

I am using Storybook with a React project that also uses styled-components. Many of those style definitions access CSS variable values that are defined in :root in an index.css file at the root of the src directory. All of the CSS variables defined this way are just placeholders for colors. However, when the components are rendered in Storybook the values of the CSS variables aren't being accessed and so those colors never render/display.
Is there a way, either via a plugin or configuration, to make it so the CSS variables I am defining in my index.css file are accessible to the components when they are rendered in Storybook?
You can import CSS file in the .storybook/preview.js file:
import '../src/index.css';
// ... rest of the settings
This way it will be available across all pages in your Storybook.

How to load seprate css file for each page in Next.js with postcss

I'm trying to use PostCss with next.js which allow me only to add the main css file in the main _app.js file,
which make all the output style global,
how can I create css file for each page or even each component
As of Next.js version 9.2, it supports native css support.
As you said, if you import styles from _app.js file, they considered as global styles of your app.
Styles of components are considered "modules".
CSS Modules locally scope CSS by automatically creating a unique class name. This allows you to use the same CSS class name in different files without worrying about collisions.
All you need to do is call your css files with *.module.css suffix.
Check the official docs

Bundle sass files into single sass file

TL;DR: My question is how to bundle some of my sass files into single sass file?
I've been developing an Angular component library and I package it with ng-packagr. Let's call it #my-lib/ngx-components.
Consumers of my lib will import my components like #my-lib/ngx-components/navbar.
I decided to add theming support to components.
For example, I have a navbar component with default colors (background, text, hover etc.) I want consumers of my library to be able to override these colors with their own theme. That's why I've written a mixin which takes a $theme input and override some css rules as follows (this is a basic version of what I have)
_navbar-theme.sass
#mixin navbar-theme($theme)
$primary-color: map-get($theme, primary-color)
$secondary-color: map-get($theme, secondary-color)
$color: map-get($theme, color)
.navbar
background-color: $primary-color
color: $color
&:hover
background-color: $secondary-color
Each component has its own *-theme.sass file.
I also have global _theming.sass file which imports all of these as follows
_theming.sass
#import './components/navbar/navbar-theme'
#import './components/button/button-theme'
#import './components/dropdown/dropdown-theme'
I want to export this _theming.sass file from my lib, so people can import this file in their own sass file as #import '~#my-lib/ngx-components/theming' and start using all of the mixins available.
If they want to have custom navbar, button etc, they should be able to use those mixins with single import.
I tried to make it look like angular-material theming setup.
At first, I have tried node-sass which is already in my dependencies. But, it tries to build sass into css so it omits mixins in the output file.
Then, I looked at what angular-material has done. They use scss-bundle
I thought "this is exactly what I want." However, it requires scss files, not sass files. It cannot read sass files.
Then, I thought "Okay, I can give up on sass and start using scss. How do I convert all those files to scss without going through them by hand". Then, I found sass-convert. In this question it was said that I can use it within command line. However, when I install sass-convert with npm globally, it didn't give me a command line executable. I think I need Gulp to use it.
I've been avoding to use Gulp from the beginning, because it means another tool to learn and it adds complexity to codebase.
At this point, I feel like "Hal fixing light bulb"
TL;DR: My question is how to bundle some of my sass files into single sass file?
Also, If you can come up with a solution that requires webpack, that's fine too.
Let's through your opinion or questions:
I want to export this _theming.sass file from my lib, so people can
import this file in their own sass file as #import
'~#my-lib/ngx-components/theming' and start using all of the mixins
available. If they want to have custom navbar, button etc, they should
be able to use those mixins with single import.
You need to know, what is your target audience. Mostly people using angular cli for create their app like template scratch.
So you need provide css bundle (people just want import your css) and sass bundle (who want to use your object or your mixin).
I want to export this _theming.sass file from my lib, so people can
import this file in their own sass file as #import
'~#my-lib/ngx-components/theming' and start using all of the mixins
available. If they want to have custom navbar, button etc, they should
be able to use those mixins with single import.
I tried to make it look like angular-material theming setup.
Firstly, you need to know that #angular/material doesn't export sass (they use scss) but they export css thene compiled by scss-bundle (as you mention it) see their code and documentation theme.
I thought "this is exactly what I want." However, it requires scss
files, not sass files. It cannot read sass files.
I would like quote this answer:
Sass is a CSS pre-processor with syntax advancements. Style sheets in
the advanced syntax are processed by the program, and turned into
regular CSS style sheets. However, they do not extend the CSS standard
itself.
It is better you need transfer your code from sass to scss (by yourself), it would not much to do it (I think, I always write scss instead sass file).
Solution:
1. Provide css and sass (scss better)
When you deliver your component libs, You have to provide css and scss. Beacuse angular cli doesn't provide scss loader by default.
Don't use sass file, use scss file see my refer answer on top.
scss-bundle + webpack
Since you have to provide css, you can you webpack shell plugin to bundle scss. Scss have provide cli, if you want to use cli.
2. Structure your scss
Okay, let's take sample from bootstrap#4 module for this case. Bootstrap use structure like this (Documents):
scss
|-- _variables.scss
|-- _mixins.scss
|-- _functions.scss
|-- ...
|-- index.scss
inside index.scss will have like this:
#import 'variables'
#import 'mixins'
#import 'functions'
...
so, this scss you have to deliver beside css. Like bootstrap do, then mixin will available to consumer. Also this good approach when consumer to find scss file in scss folder (easy to pointing which is scss put in).
UPDATE
For bundle to single file you have to create task runner to do it. In your case you want to use webpack, you can create a plugin to do it.
Here example plugin:
scss-bundle-plugin.js
call to you config webpack:
plugins: [
new webpack.NoEmitOnErrorsPlugin(),
new SCSSBundlePlugin({
file: path.join(__dirname, 'src/index.scss')
})
],
To try playground, checkout hello-world-loader then:
# install dependency
npm install
# try play ground
npm run webpack
it will create file _theme.scss at ./dist.
My advice don't use webpack, use task runner instead (gulp or grunt) for this simple case. Webpack too advance and hard to write task.
There is also a widely used package, called scss-bundle.
It is quite simple to use, you just create a config file with all relevant configuration and then run scss-bundle.
This for example will use all scss files, imported in entry.scss and move it to out.scss. All imports will be resolved, except for angular themes in this example, like #import '~#angular/material/theming';.
scss-bundle.config.json:
{
"bundlerOptions": {
"entryFile": "my-project/src/entry.scss",
"outFile": "dist/out.scss",
"rootDir": "my-project/src",
"project": "../../",
"ignoreImports": [
"~#angular/.*"
],
"logLevel": "debug"
}
}
My solution for scss / sass files
I've used small module bundle-scss
It bundles files by file name mask. So you need to pass correct mask like ./src/**/*.theme.scss specify destination file and maybe your custom sort-order
You don't have to create one entry point file with all imports. bundle-scss will get all files by mask analyze all imports and include this files as well

import of SASS partials in Angular2 components

I am using SASS for designing my website and have developed some partials in separate file say _partials.scss. Now I want to use these variables and mixins in my scss files of various components. So I imported this scss to styles.scss file which is present inside the \src folder. But the mixins & variables are not available to each of the component level scss files.
So, next I import these partials to each of the component scss files. This works fine. But is this a good approach to import the partials in all the component stylesheets? What can be a better solution to this?
P.S. I am using Angular CLI and webpack. Angular 2 version 2.3.0
Thanks!
This is a good approach. Every .scss file in your project should know it's dependencies, that's why the #import is always good.
What you can improve is adding the partials to the includePaths (if you use node-sass), that you can directly use #import 'partials'; instead of #import '../../my/long/path/to/partials'; or do the styles as a single file (not component level styles).
in style.sass you can import css / scss link.

LESS CSS Hierarchical Heritance

In a project I have separated the CSS into two sub-projects:
C:/Projects/_Framework/css
C:/Projects/_Base/css
Note: I've purposely prefixed the above with the C:/Projects/ to illustrate that they are totally separate projects from each other.
The _Framework has basic things like reset, typography, forms, and a grid.
The _Base has the default theme for the project. _Base imports the _Framework
Inside _Base I have files like header.less and variables.less which store the design of the header and the colours for the theme.
So if I have my project at: C:/Projects/App
And inside this App project, I have a master CSS file that looks like:
#import "/_Framework/_loadAll.less
#import "/_Base/_loadAll.less
Which imports both the Framework and the Base theme (the reason that Base doesn't load the Framework itself is for flexibility but has scope to be done this way instead if needed).
The plan is to make it so that if a header.less file existed inside _App then it would automatically override the import of the one in _Base.
How could this be achieved?
You can't exclude a whole .less file by checking for duplicate names. Just make sure that the header.lessfile of your _App project is imported after the one from _Base.
Pseudo code:
#import "/_Framework/_loadAll.less
#import "/_Base/_loadAll.less
#import "_App/header.less"
And overwrite any properties you need in the _App/header.less file.
If you need to overwrite everything in the _Base/header.less file, I would suggest it's not a good fit for a Base style.

Resources