How to use dynamic FontAwesome icons in NextJs SSR? - next.js

I want to dynamically render FontAwesome icons within a NextJs project where a page is being rendered using SSR. I don't know which icons will be rendered until runtime, so I am wanting to render the icons by referring to them by using a string: I cannot import just them individually by name at build time.
// within my component
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
export function MyComponent({icon}) {
return (
...
<FontAwesomeIcon icon={icon}/>
...
);
}
In my page, I am trying this:
import { fas } from '#fortawesome/free-solid-svg-icons'
library.add(fas);
.. within my page JSX:
MyComponent<icon={'fa-solid fa-cube'}/>
When I run NextJs in development mode, I see in the server logs errors that look like:
Could not find icon { prefix: 'fas', iconName: 'cube' }
and I also get a browser error "Hydration failed because the initial UI does not match what was rendered on the server."
However, when I run a production build and serve that, the page renders ok.
How do I import all of the FontAwesome icons in NextJs and serve them dynamically using SSR?

There is an open issue discussing precisely this problem.
A temporary workaround is to require() the library instance instead of importing it (reference).

Related

How to dynamically load a css file in a react function component?

In my react application, in a component, I need to load a separate css file dynamically based on a condition and the css styles should get applied.
The condition here is in the url if I have a query string say "customStyleName" with some value , then this dynamic css file should get loaded. I am using css modules and loading a sass file for this component. But, when this query string "customStyleName" present in the url, this dynamic css file should be loaded and the styles would be overrides
I could manage to check the condition if customStyleName query string present in the url and load the css file using require() (dynamic imports didn't work here) and the styles get applied in my local. It's working fine in my local.
localhost:3000/ss/ext/onboarding?customStyleName='ss'
useEffect(() => {
const query = new URLSearchParams(window.location.search);
const customStyleName = query.get("customStyleName");
if (customStyleName) {
console.log("apply customStyleName");
require("./customStyles.css");
} else {
console.log("customStyleName empty");
return;
}
}, []);
But, in dev or other environments, it is loading the dynamic css file even though the necessary query string not present in the url. My react application is created using create-react-app.
when I checked in the developer tools, the css file is getting loaded in dev environments. I am confused why the same thing working perfectly in my local and its not in other environments. Any help would be appreciated. Thanks!

Imported modules without server side rendering feature

I have an issue with Next.js. When I'm trying to import a node module,
the module uses the window object and Next.js is throwing an error: window is not defined.
The module is imported like this:
import * as widgets from 'survey-widgets';
widgets.autocomplete(Survey);
I guess Next.js dynamic imports will not work in my case. Is there any way of doing it?
Try deferring all the code that uses window or any other api that is restricted to the browser, in useEffect, because the code in useEffect only runs in the browser.
If you can't do that, then make an intermediary module which you will use to import survey-widgets and re-export what you need. So in the end, you import that intermediary module dynamically.
import * as widgets from 'survey-widgets
export default widgets
For anyone looking for the solution for this, I solved it with NextJs Dynamic imports with no SSR.
What I did instead is importing my top level component using dynamic import like this:
const MyComponent= dynamic(
() => import('../components/hello3'),
{ ssr: false }
)
So the hello3 component will no longer be used in server side rendering and instead it will render on client side.
Then just use it like this:
<MyComponent/>

How do I use CSS Houdini in Next.js

I would like to use CSS Houdini in a Next.js project I am building. I have installed, via yarn, both the CSS Houdini package I want to use along with css-paint-polyfill. I am following the webpack instructions here https://houdini.how/usage
Here is my component:
import 'css-paint-polyfill';
import workletURL from 'url-loader!css-houdini-lines';
import styles from './Separator.module.css';
CSS.paintWorklet.addModule(workletURL);
export default function Separator() {
return <div className={styles.separator} />;
}
I am getting the dreaded
error - ReferenceError: window is not defined
at /home/tithos/code/web/new-tim/node_modules/css-paint-polyfill/dist/css-paint-polyfill.js:1:239
I tried putting the import for css-paint-polyfill in a useEffect, but the throw another error. I even tried const DynamicComponent = dynamic(() => import('../components/hello')) from https://nextjs.org/docs/advanced-features/dynamic-import, but I did not know how to reference the library.
Has any one solved this?
Seems like CSS Paint Polyfill eagerly accesses window, which means it will throw an error when in an environment which has no window, such as server phase of Next. There are multiple things you can do.
Modify your next.config.js to stub the aforementioned module when for Webpack when isServer is true. You can follow this page of the Next docs for this.
Create a dynamic component that's only imported on the client (I see you've tried this, but it should have worked, so maybe if you shared what you did in this regard, I could work out what's wrong with your approach).
Create an issue and send in a PR to the repository where the Polyfill is hosted to lazily access window depending on whether it's available or not.

Is there a way to import Components into index.tsx from the same directory of index.tsx

Is it possible to import React components from inside the page's directory ?
I can successfully import from outside /pages/[...]/.
/components/[...]/ works just fine for instance. And that is cool for re-usable components.
But if I want to split a single page's components into separate files as follows :
/components
- SomeReusableComponent.tsx
/pages/[...]/
- index.tsx
- SomePageComponent.tsx
And import it into my main component :
// /pages/[...]/index.tsx
import SomeReusableComp from '../components/SomeReusableComponent'
import SomePageComp from './SomePageComponent'
export default function MyPage(){
// page code
}
My build fails : Build optimization failed: found pages without a React Component as default export in
pages/
Is there a trick to do that ? Some setting or else to tell nextjs that this file is a dependency and not a page ?
No, unfortunately that is not possible. All files within the pages directory for a Next.js project must be entry points (that subsequently get turned into routes) and cannot be imported from any other files in your project. Next "collects" all of these files in pages and processes them in a special way, so there is no way to avoid that currently.
Typically for reusable parts that I want to use in multiple pages, I create a component that accepts children as a prop.
For example:
components/layout.js
export default function Layout({children}) {
return (
<div className="some-styling-for-pages">
{children}
</div>
)
}
pages/index.js
import Layout from '../components/layout'
export default function IndexPage() {
return <Layout>my page content</Layout>
}

Using global custom style sheet in Next Js

According to the documentation found here
To import a css file I can do the following in 'pages/_app.js':
import '../styles.css'
// This default export is required in a new `pages/_app.js` file.
export default function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
Easy enough.
From my understanding this over rides the App component with the global css.
The documentation says:
Next.js uses the App component to initialize pages. You can override it and control the page initialization. Which allows you to do amazing things like:
However when I first initialize an app with Next Js I get a root page of pages/index.js
This contains my start up page. There is no app.js file or App component anywhere here.
I'm confused as to how the App component is integrated into the regular index.js file.
My question is:
Is the pages/_app.js automatically some how wrapped around pages/index.js?
Or do I have to import the myApp component into the pages/index.js file?
My question is: Is the pages/_app.js automatically some how wrapped around pages/index.js? Or do I have to import the myApp component into the pages/index.js file?
Yes, next.js automatically wraps your application with the component defined in _app.js. If you don't have that file, next.js uses its default.
You need to follow a specific pattern when defining your App component in _app.js. You can check here to see how you should set a custom App component: https://nextjs.org/docs/advanced-features/custom-app

Resources