How can I use CSS Modules in a Nrwl NX workspace? - nrwl

I'm refactoring an old React/Webpack project to Nrwl's NX monorepo solution.
In that project css modules are used.
For example, styles are imported this way:
import style from './style.scss';
and used like this:
const MyComponent = () => <div className={style.root}>Hello World</div>
This doesn't work in NX, because style is an empty object at runtime, so all class names are gone in the actual output.
Is there a way to make CSS Modules work with NX?

Related

Third-party UI library [using styled-components] + Next.js SSR CSS rules ordering/specificity issue

I have a third-party library that uses styled-components v5.3.6
I am using this UI library in my Next-JS app. My Next-JS app also has styled-components v5.3.6 as a dependency, using which i overwrite styling for my UI components.
For instance, i have a component in my UI-library as :
const Header = (props) => {
return (
<Text p="0 14px" {...props}/>
);
}
Usage in my main-app
For my requirement , i require padding of 4px on right and left. So, i created a styled.ts file and i have overwritten the component
mystyled.styled.ts
import styled from "styled-components";
export const ModifiedTextComponent = styled(Text)`
padding: 0 4px;
`
> someComponent.ts
import modifiedTextComponent from './mystyled.styled.ts';
function test() {
return <ModifiedTextComponent> Text </ModifiedTextComponent>
}
Issue
On SSR, css-specificity for this component changes. Styling defined in <ModifiedTextComponent /> takes less priority over styling of my Text Component.
So during SSR, my ModifiedTextComponent always ends up with a padding of '14px' instead of `4px` on left and right-side.
Note, for this query, naming my third-party UI library as `MyLib`
What i tried.
To resolve this, i removed styled-components dependencies from my main-app and exposed styled utility from my third-party library
Third-party library
import styled from 'styled-components'
export {styled}
main-app > mystyled.styled.ts
import {styled} from "MyLib";
export const ModifiedTextComponent = styled(Text)`
padding: 0 4px;
`
Exposing styled utility from my third-party library i.e MyLib and consuming it directly seems to resolve the issue.
But this creates an extra dependency on my UI library. I would like to know if there is some other way to resolve this. Also, wanted to understand why specificity for my third party library is high over css-styling that i add in my app.
Solution - 2 , suggested by styled-components-library
https://styled-components.com/docs/faqs#how-can-i-override-styles-with-higher-specificity
Please suggest if someone has a better solution to this, or an explanation to why CSS specificity gets affected with NextJS SSR and Styled-components.

How to globally add styles to some components

I would like to add some styles to some components for example v-chip I want to add some padding globally. I do not want to do it, or import a style file on each component that uses v-chip. I tried to add the styles to variables.scss it works fine but violate the caveats https://vuetifyjs.com/en/features/sass-variables/#caveats that produces duplicate css. Created a overwrites.scss file and add to it dose not work neither. Please if anyone know how to achieve it?
According to caveats CSS duplication is happened when you import any other stylesheet into variables.scss. As far as I understand, there is no any duplication happened when you haven't imported any CSS file. So, to configure variables in variables.scss is a good way to configure global styles.
If you need to configure styles which have no applicable variable (or you just prefer this way of styles configuration) you can:
a. Create your own component (e.g. XChip.vue) as a wrapper for v-chip.
<!-- XChip.vue -->
<template>
<v-chip v-bind="$attrs" v-on="$listeners">
...
</v-chip>
</template>
b. Add necessary styles in this component
<style scoped>
...
</styles>
c. Then use it everywhere in your project when you need a chip.
You can find more information how to pass down slots here: Vue - how to pass down slots inside wrapper component?

PrismJS syntax highlighting is broken due to conflicts with Bulma

PrismJS syntax highlighting is broken when used together with Bulma.
Both PrismJS and Bulma use the number and tag classes. So, there is a conflict between PrismJS and Bulma.
Are there any workarounds?
There are at least 2 workarounds.
Workaround #1
PrismJS adds token class to all highlighted elements including number and tag unlike Bulma. It allows us to write a more specific CSS rule and resolve conflict with Bulma:
.token.number,
.token.tag {
all: inherit;
color: #905;
}
Just specify the correct color used in your chosen PrismJS theme.
Workaround #2
Use Custom Class Prism plugin.
It allows to prefix all Prism classes (e.g., with prism- prefix).
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/components/prism-core.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/plugins/autoloader/prism-autoloader.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/plugins/custom-class/prism-custom-class.min.js"></script>
<script>
Prism.plugins.customClass.prefix('prism-');
</script>
So number and tag become prism-number and prism-tag so the conflict with Bulma will be resolved.
But you also have to manually prefix classes in Prism CSS style-sheet, e.g.:
...
.prism-token.prism-class-name,
.prism-token.prism-function {
color: #dd4a68
}
...
I don't like this approach due to the need to manually edit Prism theme CSS file and then hosting it yourself.
Like Eugene Khyst mentioned in his answer, one way to do it is to use the Custom Class plugin for prismjs.
Instead of renaming every prism class you can selectively rename some of the classes. Which should be easier to maintain.
Prism.plugins.customClass.map({
number: 'prism-number',
tag: 'prism-tag'
});
This will rename only the number and tag classes.

How do I use angular-fontawesome with Angular Material?

Existing questions on this subject refer to how to use Angular with FontAwesome Icons and the Answer is ideally Angular FontAwesome. I searched both repo's and didn't really find much using angular-fontawesome. There are hints of older solutions only.
So I have that. I am also using Angular Material Buttons, to which I have been tasked with using FontAwesome Icons in my Buttons and this leads me to Material Icons
I am not really sure where to begin.
Providing I have added an Icon to angular-fontawesome as described. I have a Button with a Icon ready to go, there is a standard method to use to connect the two?
TLDR: I want to use a Material Icon Button, but I am unable to use a Material Icon and have to use FontAwesome Icons instead. I don't know how to achieve this.
Approach 1: Material icon registry
Material allows to use custom SVG icons with its components (like mat-button). FontAwesome icons are also SVGs, so you can use this mechanism to solve task at hand.
// 1. Import desired FontAwesome icon
import { faFontAwesomeFlag } from '#fortawesome/free-brands-svg-icons';
import { icon } from '#fortawesome/fontawesome-svg-core';
// 4. Use with `mat-icon` component in your template
#Component({ template: '<button mat-button type="button"><mat-icon svgIcon="font-awesome" style="vertical-align: top"></mat-icon>Make Awesome!</button>' })
export class AppComponent {
constructor(registry: MatIconRegistry, sanitizer: DomSanitizer) {
// 2. Render icon into SVG string
const svg = icon(faFontAwesomeFlag).html.join('');
// 3. Register custom SVG icon in `MatIconRegistry`
registry.addSvgIconLiteral(
'font-awesome',
sanitizer.bypassSecurityTrustHtml(svg)
);
}
}
Also check this issue for description of a more lightweight implementation.
Approach 2: Use fa-icon component from angular-fontawesome library
As you already seem to use #fortawesome/angular-fontawesome package in your application, you can avoid using mat-icon altogether and use fa-icon inside mat-button instead.
import { faFontAwesomeFlag } from '#fortawesome/free-brands-svg-icons';
#Component({ template: '<button mat-button type="button"><fa-icon [icon]="faFontAwesomeFlag" style="padding-right: 6px"></fa-icon>Make Awesome!</button>' })
export class AppComponent {
faFontAwesomeFlag = faFontAwesomeFlag;
}
Note that you'll also need to add FontAwesomeModule to imports for this to work. See documentation for more details.
Here is the demo with both described approaches: https://stackblitz.com/edit/components-issue-8znrc5
Note that I also had to add some CSS to ensure that icon is aligned well with the button text.
Go to your project directory and run this command to install google material icons pack
npm add material-design-icons.
Next, update the “.angular-cli.json” file to include the web font into the “index.html” page when application gets compiled:
{
styles: [
"./assets/fonts/material-icons/material-icons.css"
]
}
Finally, you can test the font by updating the main application template with something like the following:
<h1>Material Icons</h1>
<i class="material-icons">account_circle</i>
<i class="material-icons">thumb_up</i>
You can refer to this site . I followed all the steps fro this site to use mat-icons when I was creating angular 6 project.
More
You can also checkout this stackblitz
Update
If you want to use font awesome icons I suggest you can start by following this guide . It's super easy and simple to use.
Install font-awesome dependency using the command npm install --save font-awesome angular-font-awesome.
After that import the module :
import { AngularFontAwesomeModule } from 'angular-font-awesome';
#NgModule({
//...
imports: [
//...
AngularFontAwesomeModule
],
//...
})
export class AppModule { }

How to integrate TypeScript WebPack ts-loader with Angular2 #View styles?

I'm using Angular2 + WebPack + Typescript 1.7 stack + SASS + CommonJs.
I have webpack SASS loader configured to watch for scss files with "style!css!sass" loaders.
In my component I have #View decorator which contains styles or styleUrls parameters which can be used to pass inline styles or style url for this component.
In case I'll specify one of those #View parameters Angular2 automatically will load specified css files or (or will inline css) and that works for me.
But in case I'll use sass-loader + require() that will enable me to compile scss to css and built-in it to my js file (i'm using ts-loader and all my scripts merged into app.js).
So I can use stylesUrl to automatically preload css file by Angular2.
#View({ stylesUrl: 'my.css'}) export class Component{}
Or I can use require('*.scss') to merge css into my app.js
require('styles/my.scss');
#View({}) export class Component{}
What is the better approach for this, i mean Angular2 way?
Also I can pre-build some common.css from all scss files and simply avoid specifying any styles for component. And there simply will be 1 common.css + common.css.map file (for debugging) included in index.html
P.S. about the last approach (merge all css files)
//webpack.config.js
loaders: [
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract('style', ['css?sourceMap', 'sass?sourceMap']),
include: path.join(__dirname, 'src', 'styles'),
}
...
plugins: [
new ExtractTextPlugin("assets/path/styles.css?[hash]-[chunkhash]-[contenthash]-[name]", {
disable: false,
allChunks: true
})
//index.html
<link rel="stylesheet" href="assets/path/styles.css" />
So now I have CDN vendor links to css. And all my custom css (written in scss) is merged to 1 file styles.css, which loaded once for all components.
This approach is sourceMap enabled. But it's a little bit tricky to clarify which scss file to modify in debug.. And also there is no any information in Angular #View declaration
well I didn't quite understand the question or questions, but I will try to answer what I understood.
So for me I think that neither of the 2 ways you specified is the best one. what I use is :
#Component({
selector: 'message',
template: '<p class = {{class}}> whatever html </p>',
styles: [ require('./style.scss')],
})
export class Comp{}
so by including the style sheet like that I gained 2 things:
using sass and inputting it directly to my code
The ability to use the view encapsulations of Angular 2

Resources