How to use multiple CSS modules with Tailwind in Remix.js? - javascript

I'm using Remix with Tailwind css.
currently I followed the tailwind and remix docs to add a global css file:
"scripts": {
"dev:css": "tailwindcss -i ./styles/tailwind.css -o ./app/styles/tailwind.css -w"
}
But what if I want to have a tailwind css file for a single component? like so:
# app/components/button.css
.button-primary {
#apply bg-slate-400;
}
// app/components/Button.jsx
import './button.css'
export function Button() {
return <button className='button-primary'>My Button</button>
}
Remix doesn't throw any errors but the styles are not applied, not sure if this is related to tailwind not parsing the button.css file or remix's issue

CSS modules are not currently supported in remix, you can follow the relevant discussion in the repo: https://github.com/remix-run/remix/discussions/2214
For now, you will need to expose your component CSS using the links() function on every route that uses it.

Related

How to publish a react-component with css modules that can be consumed by both, projects using ES Modules and CommonJs for css modules

For some frameworks (eg. Gatsby >= V3) the default for importing CSS modules is as ES modules like so:
import { class1, class2 } from 'styles.modules.css'
// or
import * as styles from 'styles.modules.css'
https://www.gatsbyjs.com/docs/reference/release-notes/migrating-from-v2-to-v3/#css-modules-are-imported-as-es-modules
Other projects such as Create React App still use the default export like this:
import styles from 'styles.modules.css'
How can I publish a react-component (that uses css modules internally) so that it can be imported and used in both scenarios without extracting the css?
One workaround I found is to generate the css module hashed classes and extract the stylesheet. Then import the stylesheet with the hashed classes instead of the css module stylesheet. Every bundler that is able to import css modules should also be able to deal with the extracted css file.
I am using babel-plugin-css-modules-transform for this using the following configuration:
…
"plugins": [
[
"css-modules-transform",
{
"extractCss": {
"dir": "./lib/",
"relativeRoot": "./src/",
"filename": "[path]/[name].compiled.css"
},
"keepImport": true,
"importPathFormatter": "./importPathFormatter"
}
]
]
…
The keepImport option will keep the import but transforms it from eg. import * as styles from 'styles.module.css' to import 'styles.module.css'.
I use this option in combination with the undocumented option importPathFormatter to import the transformed css. CSS preprocessing eg. postCSS is done by the consuming application.
Content of ./importPathFormatter.js:
module.exports = path => path.replace(/\.css$/, '.compiled.css');
In the long term I want to migrate my projects to vanilla extract and use rollup/vite for bundling, but for now this is working fine.

Vue component not loaded with Plugin syntax

I have this Vue plugin that is not working:
import _Vue from "vue";
import particles from "./Particles.vue";
const VueParticles = (Vue: typeof _Vue, options: unknown) => {
_Vue.component('Particles', particles);
};
export { particles as ParticlesComponent };
export default VueParticles;
It builds, but if I try to use it, it doesn't load the component and the app returns me this error:
[Vue warn]: Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option.
found in
---> at src/App.vue
And I load the plugin like this:
import Particles from "particles.vue";
Vue.use(Particles);
But if I load the component using the Vue.component syntax, it's working, like this:
import { ParticlesComponent } from "particles.vue";
Vue.component("Particles", ParticlesComponent);
This is the template I'm using:
<Particles id="tsparticles" :options="options" :particlesInit="particlesInit" :particlesLoaded="particlesLoaded"/>
You can try to replicate the issue following these steps:
Clone tsParticles dev branch with: git clone https://github.com/matteobruni/tsparticles.git --branch dev
Run yarn && npx lerna bootstrap && npx lerna run build
Go to demo/vue folder
Run yarn serve and open http://localhost:8080, everything should work (an animated background should start animating)
Edit src/App.vue commenting the working Vue.component and restoring the Vue.use
Rerun yarn serve and open http://localhost:8080, the background this time is not appearing
I just switched from yarn workspaces to standard yarn for big issues with the node dependencies in the whole project
I don't understand why it broke like this.
I also tried an external Vue.js app instead of the demo one inside the project but nothing changed.
The component is using vue-property-decorator but I tried switching to the Vue.extend syntax and nothing changed so I reverted to the previous class code.
The plugin file should be exporting an object with an install function, but your plugin just exports the function itself. Also, the install function's argument should be used in the body (i.e., Vue is the argument name, so the body should contain Vue.component()).
The fix should look like this:
const VueParticles = {
install(Vue: typeof _Vue, options: unknown) {
Vue.component('Particles', particles);
}
};
export default VueParticles;

How does css loader interprets the #import and url() in css

How does the css-loader interprets the #import or url() in css
For exmaple if in (index.js) module if i import (Style.css)
import './Style.css';
function Component(){
//javascript code
}
My (Style.css) file if I have
body{
background:url('./image.png')
}
So, when webpack see's that import of Style.css in index.js module, How does css-loader inteprets that url() syntax of background property. will the url('./image.png') be converted to require('./image.png).
For example will
body{
background:url('./image.png')
}
converted to
body{
background:require('./image.png') //not a valid css syntax
}
Because in the documentation there is resolution example like:
url('./image.png') => require('./image.png')
So, I want to know does the whole url('./image.png') syntax is replaced by require('./image.png'). if it is the case than background with require() is not a valid css syntax.
Does interpreting url() as require() means converting it to require() or something else.
Unfortunately it's not that simple as replacing url(<>) with require(<>) in content.
css-loader first loads necessary plugins including url-parser
url-parser then collects all url(<>) occurences and generates some metadata about them
Later on when the loader javascript code is generated it wraps those things in ___CSS_LOADER_GET_URL_IMPORT___ function

Can i use Enzyme's .hasClass feature with react components importing css files?

i am currently setting up a test environment and come across a problem, that all my calls to .hasClass return false.
Current Setup: My react components import scss files with an import statement. For example:
import styles from "./text.scss";
To test the components i had to define the moduleNameMapper in the jest.config.js file like so:
moduleNameMapper: { "\\.(scss|less)$": "<rootDir>/__mocks__/styleMock.js" },
I think that the moduleNameMapper is kind of responsible for the problems, since it replaces via default all scss definitions with an empty module. (styleMock.js content is just module.exports = {};)
But i need it to test my components, otherwise it would result in an error, when jest tries to load the scss imports.
When i now try this:
it("is Title", () => {
const wrapper = shallow(<Text textType={TextType.Title} />);
expect(wrapper.find("div").hasClass("Title")).toEqual(true);
});
It always returns false.
Is there any solultion on how to test the scss classes (with .hasClass from enzyme?), when you have scss import statements in your component?
Found a solution finally that works!
For me i had to install the identity-obj-proxy via
npm install --save-dev identity-obj-proxy
and then add it to the jest config file like that:
moduleNameMapper: {
"^.+\\.(css|less|scss)$": "identity-obj-proxy"
}
After that my class name's are now in the snapshots correctly and no more undefined classnames!
In addition to that i can now finally use the .hasClass feature of enzyme and check if new css class had been added to a div and so on. (Finally i can go into testing those conditional rendering parts!)

Next.js with FortAwesome and SSR

I am building a Next.js application and looking for an icon package that works with its SSR paradigm.
After trying a few libs, I'm now working with FortAwesome/react-fontawesome, which looks promising.
The problem is when the page loads the icons are large (unstyled) and then suddenly they are styled properly. I'm trying to figure out how to get these to style server-side.
I've seen folks talk about importing a stylesheet provided by FortAwesome:
import '#fortawesome/fontawesome-svg-core/styles.css';
However, I'm unsure which file(s) this should be done in and also, Next complains when I try this:
[ error ] ./node_modules/#fortawesome/fontawesome-svg-core/styles.css
1:8 Module parse failed: Unexpected token (1:8) You may need an
appropriate loader to handle this file type, currently no loaders are
configured to process this file
I've looked at the CSS plugin, but this also seems like a red herring.
How can I get the font-awesome icons in this package to be styled on the server with Next.js?
React-fontawesome has added a section on how to get FontAwesome working with Next.js.
https://github.com/FortAwesome/react-fontawesome#nextjs
Create an ./pages/_app.js file in your project
import React from 'react'
import App, { Container } from 'next/app'
import { config } from '#fortawesome/fontawesome-svg-core'
import '#fortawesome/fontawesome-svg-core/styles.css' // Import the CSS
config.autoAddCss = false // Tell Font Awesome to skip adding the CSS automatically since it's being imported above
class MyApp extends App {
render() {
const { Component, pageProps } = this.props
return <Component {...pageProps} />
}
}
export default MyApp
or using a function component:
import { config } from '#fortawesome/fontawesome-svg-core'
import '#fortawesome/fontawesome-svg-core/styles.css' // Import the CSS
config.autoAddCss = false // Tell Font Awesome to skip adding the CSS automatically since it's being imported above
export default function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
There are definitely a few ways to take this problem. I solved it in my project by importing the icons I needed directly into my React app. So no Font Awesome libraries sit on the client-side, just the rendered SVGs.
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import { faAdobe } from '#fortawesome/free-brands-svg-icons/faAdobe'
...
return (
<FontAwesomeIcon icon={faAdobe} />
)
Font Awesome also provides a page to discuss other methods: server-side-rendering
I'm going to put this as an answer, because it's a way, however I feel like there is a better solution out there, so I will not accept this one.
I created a static/css folder, then copied the css file referenced in the question
cp node_modules/#fortawesome/fontawesome-svg-core/styles.css static/css/fortawesome.css
Then in _document.js I load the file via link tag:
<link
rel="stylesheet"
type="text/css"
href="/static/css/fortawesome.css"
/>
I would consider this a stop-gap solution. One issue obviously is that when the underlying library updates I would need to copy over the latest version of the css file manually.
I had this same issue and fixed it by manually inserting Font Awesome's CSS into styles which I know will get SSR'ed correctly.
I use styled-components, which is easy to set up with Next.js SSR, and here's how I did it:
import { createGlobalStyle } from "styled-components";
import { config, dom } from "#fortawesome/fontawesome-svg-core";
// Prevent FA from adding the CSS
// (not that it was doing it in the first place but might as well)
config.autoAddCss = false;
// Add the FA CSS as part of Global Styles
const GlobalStyles = createGlobalStyle`
${dom.css()}
`;
Here is what I have tried so far to fix this issue in my project:
Installation of #zeit/next-css, #zeit/next-sass [I need sass too.]
Installation of fontawesome packages & import CSS
Installation of #zeit packages
Install required packages:
npm i --save #zeit/next-css
npm i --save #zeit/next-less
npm i --save #zeit/next-sass
then update next.config.js file such as below that will support CSS import which fix the issue of loading correct styles upon loading:
const withCSS = require('#zeit/next-css')
const withLess = require('#zeit/next-less')
const withSass = require("#zeit/next-sass");
module.exports = withLess(withCSS(withSass({
webpack(config, options) {
config.module.rules.push({
test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
use: {
loader: 'url-loader',
options: {
limit: 100000
}
}
});
return config
}
})));
Installation of fontawesome packages & import CSS
Install required packages:
npm i --save #fortawesome/fontawesome-svg-core
npm i --save #fortawesome/free-solid-svg-icons
npm i --save #fortawesome/react-fontawesome
Then you can use following code within your pages extending React.Component located under pages directory:
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { library } from '#fortawesome/fontawesome-svg-core';
import { fas } from '#fortawesome/free-solid-svg-icons'
import '#fortawesome/fontawesome-svg-core/styles.css';
library.add(fas);
Then this is the way you can use fonts:
<FontAwesomeIcon icon={["fas", "user-tie"]} />
I may be wrong.

Categories

Resources