I have a React/Next.js component Onboarding where I'm using withPageAuthRequired from #auth0/nextjs-auth0 that looks like
export default function Onboarding() {
return (
<Layout>
<h2>Onboarding</h2>
</Layout>
)
}
export const getServerSideProps = withPageAuthRequired()
It works perfectly in the app itself, but Storybook fails to build due to errors such as
node_modules/#auth0/nextjs-auth0/dist/node_modules doesn't exist or is not a directory.
I tried a few Storybook add-ons, but they didn't work at all to make withPageAuthRequired work with Storybook. The only thing that worked was when I made a copy of the Onboarding file where I didn't use withPageAuthRequired and just imported that component into Storybook. However, this is not an optimal solution since the two files are basically copies of each other, and I don't want to do this for every page of my app.
Does anybody know what to do here or if there's a workaround?
Related
We have a yarn 2 monorepo setup with the following workspaces:
/root
/app (nextjs)
/components (individual react functional components)
/storybook
/constants
Currently, /app has the i18next translation files stored local to the workspace, but I would like to move that into the constants workspace so that all workspaces can share the same translations. I had no issue moving the translations there and loading them in both the /app and /storybook workspaces.
Also, currently, all translations happen only in /app. The /components workspace has no translations, and the translated text is passed in props to the dumb components. So, a component in /app looks something like this:
import ListBox from "#root/components/ListBox";
import {useTranslation} from "react-i18next";
export default const Page() {
const [t] = useTranslation();
const label = t("listBoxLabel"); // <-- exists in en.json as a key
return (
<div>
<ListBox label={label} />
</div>
)
}
As such, storybook also has to provide the "label" prop to render the component in stories, doing this in pretty much the same manner.
What I would like to do is instead translate the text at the /components workspace level, so that the translations can be done in one place, where it's used, to reduce prop drilling and also simplify things.
Something like this:
/components/ListBox.js:
import {useTranslation} from "react-i18next";
export default const ListBox() {
const [t] = useTranslation();
const label = t("listBoxLabel"); // <-- exists in en.json as a key
return <p>{label}</p>
}
When I run this code, it just prints out the translation key "listBoxLabel", in both storybook and the nextjs app.
I was able to fix storybook by wrapping stories with I18nextProvider and changing the dependencies in the /components workspace for i18next and react-i18next to move them from a normal dependency to a peer dependency, and storybook properly renders the translation. However, then the NextJS /app throws an error that the react-i18next Module Not Found when it imports the /components/ListBox.js code. It seems to require the /components workspace keep a normal dependency for that, but doesn't translate it in that case. If I remove the /components dependencies altogether, /storybook won't compile and start for the same reason.
Duplicating this exact code in the app or storybook, however, displays the correct translation. So, it has something to do with importing it from a sibling workspace in the monorepo, and I'm not sure exactly how to go about fixing that for the nextjs app.
Just a note: I don't use the next-i18next component. Instead, I am simply using react-i18next directly, without any providers configured. I did attempt to wrap the app with the I18nextProvider component similar to the storybook stories, but it didn't work.
Does anyone have any ideas where to look further or what to try for this? I would think loading a component from a workspace component library where the translations happen within the library would be a common scenario, but I haven't been able to find anyone else running into this issue.
I don't know exactly what's causing this, but it appears to be a nextjs, webpack, or yarn bug. I discovered the problem was related to this in my tsconfig.js file in the #root/app workspace:
{
"compilerOptions": {
"paths": {
"#root/components/*": ["../components/*"]
}
}
}
I was able to fix this by removing this setting, but it broke other code (some components were typescript), so I just explicitly declared those component modules in the custom.d.ts file as modules.
Where the next/yarn bug comes in: after I removed this line, and restarted the dev server, the i18n translations were still broken. Until I went and touched the components/ListBox.js file. This caused something to rebuild within next, and the translations showed up.
The ListBox.js file is not typescript, so I don't understand why this causes a problem.
While trying to resolve this issue, yarn kept getting into a bad state, next was telling me I didn't have typescript installed when I did, and multiple other tedious random errors...what a mess.
I'm trying to build my Next.js project but it keeps giving me this error in the terminal:
Error: Build optimization failed: found page without a React Component as default export in
pages/components/context/Context
That's the React context API file, there isn't supposed to be any default export there. Is this a bug or what?
You should move your components outside the pages folder. pages/ should only be used for page components as Next.js routing is based on its structure.
Next.js has a file-system based router built on the concept of pages.
When a file is added to the pages directory it's automatically available as a route.
By default, Next.js assumes anything under the pages folder is a page component and will try to build each file as a page.
Even though the above is the default behaviour, you can configure your Next.js app to include non-page files in the pages directory.
To do so, you can modify the pageExtensions entry in the next.config.js file as shown below. Then rename your page components to have a file extension that includes .page (_document.page.js, _app.page.js, index.page.js, etc).
module.exports = {
pageExtensions: ['page.tsx', 'page.ts', 'page.jsx', 'page.js']
}
With this configuration, Next.js will ignore any file that doesn't contain .page for the purpose of building pages/API routes and routing.
In my case, I had an empty file index.js in a folder. Using Nextjs Default Router
It seems to be not declared default export keyword in context component.
Try it as follow:
const Context = ()=>{
...
}
export default Context
I had the same error.
If you comment out all other code but leave this NextJS won't get mad at you:
export default function Home1() {
return <>{/* nothing */}</>;
}
I like to keep older index files and components locally and on github so this is a nice hack. I just copy all of the existing code add it to a new file and then add 1 to it for example:
index1.js
You can also leave a comment to kind of bring you and other devs up to speed as to why you did this for example:
//good for history of index implementation and associated syntax logic
I'm trying to build my Next.js project but it keeps giving me this error in the terminal:
Error: Build optimization failed: found page without a React Component as default export in
pages/components/context/Context
That's the React context API file, there isn't supposed to be any default export there. Is this a bug or what?
You should move your components outside the pages folder. pages/ should only be used for page components as Next.js routing is based on its structure.
Next.js has a file-system based router built on the concept of pages.
When a file is added to the pages directory it's automatically available as a route.
By default, Next.js assumes anything under the pages folder is a page component and will try to build each file as a page.
Even though the above is the default behaviour, you can configure your Next.js app to include non-page files in the pages directory.
To do so, you can modify the pageExtensions entry in the next.config.js file as shown below. Then rename your page components to have a file extension that includes .page (_document.page.js, _app.page.js, index.page.js, etc).
module.exports = {
pageExtensions: ['page.tsx', 'page.ts', 'page.jsx', 'page.js']
}
With this configuration, Next.js will ignore any file that doesn't contain .page for the purpose of building pages/API routes and routing.
In my case, I had an empty file index.js in a folder. Using Nextjs Default Router
It seems to be not declared default export keyword in context component.
Try it as follow:
const Context = ()=>{
...
}
export default Context
I had the same error.
If you comment out all other code but leave this NextJS won't get mad at you:
export default function Home1() {
return <>{/* nothing */}</>;
}
I like to keep older index files and components locally and on github so this is a nice hack. I just copy all of the existing code add it to a new file and then add 1 to it for example:
index1.js
You can also leave a comment to kind of bring you and other devs up to speed as to why you did this for example:
//good for history of index implementation and associated syntax logic
I'm trying to figure out why the loadeddata/loadedmetadata event is not firing in my application. Actually, sometimes it does fire but it's inconsistent. I suspect there is some kind of race condition going on here but after a lot of trial and error and quite a lot of frustration, I'm out of ideas.
So, the idea is simple. I have an <audio> element and I want to run some logic when it is loaded.
This seems to work when I try it in a non-Nextjs React application. Example here
However, when I run the same thing in my Next.js React application locally I observe the aforementioned behaviour, so I suspect that this could be nextjs specific?
This can be minimally reproduced by:
Running npx create-next-app nextjs-blog --use-npm --example "https://github.com/vercel/next-learn-starter/tree/master/learn-starter"
Replacing the existing index.js with:
export default function Home() {
const handleMetadata = () => {
alert("hi")
}
return (
<div className="container">
<main>
<audio
id="audio"
onLoadedData={handleMetadata}
onLoadedMetadata={handleMetadata}
src="https://www.soundhelix.com/examples/mp3/SoundHelix-Song-2.mp3"
/>
</main>
</div>
)
}
Repeatedly refreshing the browser window
you should load the compoent which use audio with no ssr.like this:
import dynamic from 'next/dynamic'
const AudioPlayer = dynamic(import('../components/Home'), {
ssr: false
})
This isn't a direct answer but I wanted to share that #YAN7 answer above solved a similar issue for me. I was developing a component in Storybook that was using GSAP scroll trigger to scrub play a video. It worked perfectly in Storybook, but when I went to import it and use it in the UI/Next Js project, it wouldn't work as expected. Occasionally I managed to get the animation effect to work, but most of the time I couldn't. After a lot of console logging, I realised the only significant difference between the two examples was one was in Next and the other wasn't. Which eventually lead me here. I dynamically imported my component into Next as in YAN7's example and it worked perfectly. Many thanks YAN7! I hope this comment helps other GSAP + Next devs in the future
Due to some poor planning and some problems with domain registration I'm building a quick react app that's only function is to redirect to another site when the page loads. To do this I created a component like so:
class App extends React.Component {
componentDidMount() {
window.location.replace("insert url here");
}
render() {
return (
<div className="App">
</div>
);
}
}
export default App;
This method works perfectly when in development, but does not perform the redirect when the project is built by netlify. Is there a way to fix this and if so why does this happen?
After looking at it further I realized the issue was with netlify. I'm posting because I discovered a couple of things that could make building react projects with netlify a little bit complicated and I want others to be aware. ALWAYS change the build directory from public/ to build/ with a react application and make sure your build command is either npm run build or CI=npm run buiild or your production scripts will not be added to your main html file properly.