Problem with using Emotion with Gatsby.js - javascript

I am following this tutorial of Gatsby about using Emotion. https://www.gatsbyjs.org/docs/recipes/styling-css#using-emotion
I installed the Emotion using npm install --save gatsby-plugin-emotion #emotion/core #emotion/styled and set up my gatsby-config.js file like this
module.exports = {
plugins: [`gatsby-plugin-emotion`],
}
But when I was using it like the tutorial did, I encountered a problem where the inline-css of the component is [object Object]
My component looks like this
import React from "react"
import { css } from "#emotion/core"
export default ({ children }) => (
<main
css={{
backgroundColor: "red",
}}
>
{children}
</main>
)
and I tried to rewrite using a different approach
import React from "react"
import { css } from "#emotion/core"
export default ({ children }) => (
<main
css={css`
background-color: red;
`}
>
{children}
</main>
)
this time the inline-css of the component is a paragraph
You have tried to stringify object returned from `css` function. It isn't supposed to be used directly (e.g. as value of the `className` prop), but rather handed to emotion so it can handle it (e.g. as value of `css` prop).
have no ideas why these two approach didn't work

This worked for me (without thorough understanding):
Approach 01
Replace this:
import React from "react"
import { css } from "#emotion/core"
with this:
/** #jsx jsx */
import { css, jsx } from "#emotion/core"
Approach 02
Update gatsby-config.js to contain the plugin gatsby-plugin-emotion:
module.exports = {
plugins: [
`gatsby-plugin-emotion`,
],
}
This needs a restart of the gatsby development process.

Related

Can not find _app.js in nextJs

I am using npx create-next-app to create my NextJs project and now I want to add global style for it by bootstrap
After downloading bootstrap, it suggested me adding global style in pages/_app.js but I found no file like it. Thanks for helping me
when you make a new Nextjs project you don't have this file
you should create this file in root pages
_app.js or _app.tsx (if you use typescript)
const MyApp=()=>{
return(
enter code here
)
}
export default MyApp
You create your pages/_app.js, you place code below
import React from 'react';
export default function App({ Component, pageProps }) {
return (
<Component {...pageProps} />
);
}
To add bootstrap, you create styles folder in /public, you add your .css file of bootstrap (imagine it's bootstrap.css). After, you add import to your app.js file, and the example below:
import React from 'react';
import "../styles/bootstrap.css";
export default function App({ Component, pageProps }) {
return (
<Component {...pageProps} />
);
}
The possible reason you don't have app.js is because you didn't build your project yet
Add _document.js file in pages/_document.js, you can add your global style in this file index.jsx see documentation:
Custom Document Next.js

Disable no-use-before-define rule for a specific variable/function name

I use Mui as the design-system of my react project and have therefore often this component architecture:
import React from 'react'
import { makeStyles } from '#material-ui/core'
const Component = () => {
const classes = useStyles()
return (
<div className={classes.root}>
<!-- ... -->
</div>
)
}
const useStyles = makeStyles((theme) => {
return {
root: {
background: theme.palette.background.gradient,
minHeight: '100vh'
}
}
})
But when I add eslint I got the error 'useStyles' was used before it was defined. I know that I can disable this rule for all variables by using the config:
"no-use-before-define": ["error", { "variables": false }]
But is there a way to disable it only for variables/functions with the name useStyles?
A good way out of this is to use module functionality of JavaScript.
Instead of creating this at the bottom of your file, create structure as such
MyReactComponent
|- index.js
|- styles.js
This allows you to import your styles.js (your styles function) file at the top of your file keeping your code clean. Don't worry about having to do complex imports, I suggest you to use webpack's function Resolve, allowing you to create simplified imports.
import MyReactComponent from 'Components/MyReactComponent'
You don't have to mention index.js in the import as it's the default file that engine will look for.

React Context API not working from custom NPM component library

I've built a ReactJS component library that I use for multiple projects installed via an NPM package using a sim link. I want to use the context API to pass data from a parent component served from the component library to my base project to be consumed by multiple consumer components also served from the component library. When I try the context is always undefined in my child components.
If I place my consumer component in my provider component within my library it works like a champ but this defeats what I'm trying to achieve. If I export both the provider and the consumer to my base project the consumer doesn't see the provider.
This is from my base project
import { Screen, COD, GenericSocketServer } from 'component-library'
export default class View extends React.PureComponent {
render() {
return (
<Screen className="screen odmb1">
<GenericSocketServer>
<COD />
</GenericSocketServer>
</Screen>
)
}
}
This is my provider code exported from my 'component-library'
import React from 'react';
import MyContext from "./context";
import COD from './../cod';
export default class GenericSocketServer extends React.Component {
render() {
return (
<MyContext.Provider value={{ foo: 'bar' }}>
<COD />
{this.props.children}
</MyContext.Provider>
);
}
}
This is my content code used in 'component-library'
import React from 'react'
const MyContext = React.createContext()
export default MyContext
This is my consumer component exported from 'component-library'
import MyContext from "../GenericSocketServer/context"
class COD extends React.Component {
render() {
return (
<React.Fragment>
<MyContext.Consumer>
{(context) => {
/*
context comes back undefined
I expect { foo: 'bar' }
*/
console.log('context :', context)
return (
<p>This should work</p>
)}}
</MyContext.Consumer>
</React.Fragment>
)
}
}
Context always comes back undefined as if it doesn't see the parent provider. I think I'm ether doing something wrong initializing the context myself or for some reason the two components I'm importing just don't share the same context. Please help!! Not sure if I should give up on this and just use redux.
Maybe you are making multiple instances of the component providing the context. Let's say you have a component Sound, which starts by:
const { Provider, Consumer } = React.createContext();
If you import this library from your main project, the context will be created at the global space. You then use it to render your document tree. But in another component you also imported this library, which had to be resolved during webpack transpilation. It thus has its own copy of the above lines and a context object created in its own space. The problem occurs when you try to use the Consumer, because the Provider was only made by the main project for the first context object, and the second context's provider instance was never instantiated, thus returns undefined.
A solution to the problem is to enforce a single context object, which you can achieve by telling the second component's webpack that the provider-owning library is an external, so when webpack reaches e.g. the "import sound" line, it will not go further and will assume this dependency is resolved at runtime. When runtime comes, it will take it from the same place where the main project is taking it. To do this in webpack, e.g. for above "sound" library, add this to your other component (not main project):
{
...
externals: {
...
'sound': 'sound'
}
...
}
Also in your component package.json:
{
...
peerDependencies: {
"sound": "^1.2.3"
}
}
Apart from Darko's answer, esm and cjs export is also a possible reason for context to fail in a package. If you use the hook in esm and the provider in cjs, you will not get the value for that context.
I recently had a similar issue where I was trying to consume the value of a context inside my library components but using the provider (imported from the package) in the host app.
I managed to solve the issue just by making react and react-dom external and peerDependencies when bundling in rollup.
should your code of consumer be
<React.Fragment>
<MyContext.Consumer>
{value => /* render something based on the context value */}
</MyContext.Consumer>
</React.Fragment>
as stated from the official react doc : https://zh-hant.reactjs.org/docs/context.html
when you define
you can use it like

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.

Material UI component `theme.spacing` not defined once built

I am building a Material-UI text editor using draft.js and wrapping all the functionality in Material-UI components.
I've gotten comfortable using ~3.9 but for this project decided to update to 4.0. Maybe I'm missing something here but this usually works for me with no issues
const styles = theme => ({
paper: {
paddingBottom: theme.spacing(2)
},
...
})
import { withStyles } from "#material-ui/styles"
...
export class EditorComponent extends Component {
...
render() {
const { classes } = this.props
}
}
export default withStyles(styles, { withTheme: true })(EditorComponent)
This works while running in a webpack-dev-server but when I build to javascript and attempt to import it into another project and use it I get this error in the console...
Uncaught TypeError: theme.spacing is not a function
I can't seem to find anything relevant googling this issue.
Here is the repo if looking at my build script would help
https://github.com/jrdn91/material-ui-rte
Turns out that pulling in withStyles or makeStyles etc. from #material-ui/styles does not include the default theme. There are wrapped version of these included in #material-ui/core/styles which do include the default theme.
So changing from import { withStyles } from "#material-ui/styles" to import { withStyles } from "#material-ui/core/styles" will fix this issue.
Referenced from this page
https://material-ui.com/customization/default-theme/#material-ui-core-styles-vs-material-ui-styles

Categories

Resources