In production mode, after building, when open subpath directly, Next JS app gives 404.
For example, when I open domain.com/page, gives - 404. But, when I open domain.com/en/page it works.
My next.config.js file:
module.exports = {
i18n:{
locales:["en", "ru"],
defaultLocale: "en",
}
}
One of my page components:
import { MainLayout } from "../components/MainLayout";
import en from "../locales/en/en.js";
import ru from "../locales/ru/ru.js";
import { useRouter } from "next/router";
export default function About() {
let router = useRouter();
const { locale } = router;
const t = locale === "en" ? en : ru;
return (
<MainLayout title={"About page"}>
<div className="container">
<div className="content">
<h1>{t.about}</h1>
</div>
</div>
</MainLayout>
);
}
In your _app.js
You have to write this line;
export default appWithTranslation(YourApp);
And you should define localePath in your i18n object in next.config.js
like this :
localePath: path.resolve("./public/locales")
After you can access your translations in component or page like this;
const { t } = useTranslation('common');
I know that this is an old question, but I'm leaving this answer from stackoverflow for anyone that is having this error using Docker, in my case it was the solution to my problem.
Be sure to copy the next.config.js file in your Dockerfile:
COPY ./next.config.js /app/next.config.js
Related
Context
I currently have created a project using React-admin and NextJS.
Problem
Whenever I refresh the page I'm redirected to the 404 page - It has started after I had removed the hash from the URL (localhost:3000/#/). It only works well when I'm at the localhost:3000 page.
Code:
// into src/admin/ReactAdmin.tsx file
import { Admin, Resource } from 'react-admin'
import { createBrowserHistory as createHistory } from 'history'
const history = createHistory()
import {
RestrictionList,
RestrictionEdit,
RestrictionCreate,
} from './components/restricao/'
import baseDataProvider from './DataProvider'
const App = () => (
<Admin dataProvider={baseDataProvider} history={history}>
<Resource
name='source'
list={RestrictionList}
edit={RestrictionEdit}
create={RestrictionCreate}
/>
</Admin>
)
export default App
//into next.config.js file
module.exports = {
trailingSlash: true,
}
// into src/pages/index.tsx file
import dynamic from 'next/dynamic'
const ReactAdmin = dynamic(() => import('../admin/ReactAdmin'), {
ssr: false,
})
const HomePage = () => <ReactAdmin />
export default HomePage
Have you used next export in your build?
If yes, you need to add this config in your next.config.js:
async rewrites() {
return [
{
source: '/:any*',
destination: '/',
},
]
}
I am a Gatsby newbie and I'm following this tutorial: https://www.gatsbyjs.com/docs/creating-plugins/ to learn to create a gatsby local plugin using react-intl. I put the plugin in the plugins folder in the root of the project.
This is the demo code of the plugin (Demo Project Repo: https://github.com/85Ryan/gatsby-local-plugin-demo.git)
// ./src/wrap-page-element.js
import * as React from 'react'
import { IntlProvider } from 'react-intl'
const message = {
welcome: 'Welcome',
home: 'Home',
}
const wrapPageElement = ({ element }) => {
const locale = 'en'
return (
<IntlProvider locale={locale} key={locale} messages={message}>
{element}
</IntlProvider>
)
}
export { wrapPageElement }
// gatsby-browser.js
export { wrapPageElement } from './src/wrap-page-element'
// gatsby-ssr.js
export { wrapPageElement } from './src/wrap-page-element'
When I build the Gatsby site, it crashes with the error WebpackError: [React Intl] Could not find requiredintlobject. <IntlProvider> needs to exist in the component ancestry.
But when I publish the plugin to npm, it works fine.
Can anyone help me to find where my problem is?
Thanks!
You are re-exporting wrapPageElement a second time in your file:
// gatsby-browser.js
export { wrapPageElement } from './src/wrap-page-element'
This replaces the earlier export that included <IntlProvider />.
I made one react app. My app works as expected. This app's target is practice AWS-COGNITO. For Cognito validation I am using amazon-cognito-identity-js package. I made one helper function where I validate the Congnito. and reuse it in different component. I split my Nav bar into two components. From Congnito current user I made one callback function and use it in useEffect, and dependencies put the callback function, by default getAuthenticatedUser is null. I add condition where it fetch the data, if getAuthenticatedUser then redirect to signin and signup page. I deployed my app to s3 bucket and this the link. This app runs first time, When I refresh it then got error: 404 Not Found. I really don't know what is the issue and somehow the path react path get disappear. I share my code in code-sandbox.
This is my conditional path
import React from "react";
import SigninLinks from './SigninLinks';
import SignoutLinks from './SignoutLinks';
import useHandlder from '../configHandler/useHandler';
const Nav = () => {
const { getAuthenticatedUser } = useHandlder();
const Links = getAuthenticatedUser() === null ? <SignoutLinks /> : <SigninLinks />
return (
<nav className="nav-wrapper grey darken-3">
<div className="container">
<h2 className="brand-logo">Logo</h2>
{
Links
}
</div>
</nav>
);
};
export default Nav;
This is my handler functions
import React, { useCallback, useEffect } from 'react';
import { CognitoUserPool } from 'amazon-cognito-identity-js';
const Pool_Data = {
UserPoolId: "us-east-1_9gLKIVCjP",
ClientId: "629n5o7ahjrpv6oau9reo669gv"
};
export default function useHandler() {
const userPool = new CognitoUserPool(Pool_Data)
const getAuthenticatedUser = useCallback(() => {
return userPool.getCurrentUser();
},
[],
);
useEffect(() => {
getAuthenticatedUser()
}, [getAuthenticatedUser])
const signOut = () => {
return userPool.getCurrentUser()?.signOut()
}
return {
userPool,
getAuthenticatedUser,
signOut
}
};
It's paths issue. You get 404 on /path not in root /. Check S3 settings for hosting static sites. On S3 make sure static website hosting is enabled:
You react app loads on /index.html JavaScript then redirects and takes over the path. You need S3 to resolve path to index.html, then it will work.
My Problem :
I expect my FirebaseProvider function to provide an object containing all functions, through the app. The problem is that all functions are well provided through my files, except my last new function : fetchTest.
Explainations :
If I click the TestPage.js button I get Uncaught TypeError: fetchTest is not a function.
I saw many posts on stackoverflow about this type of error, but none did help me. -> I think the original problem is the index.js is not called. The console.log("firebaseprovider") (in index.js) does not appear in console, yet the other files of the project in web-app/src/views/ have the same imports and exports than TestPage.
Since App.js code worked fine on all the other files, I don't know how console.log("firebaseprovider") is never displayed in the navigator console. (edit: no matter which page I go, this console.log never appears)
<FirebaseProvider> seems to not provide TestPage.js.
Do you have an idea ?
What I've tried :
placing a console.log in TestPage.js : it shows every function written in index.js but not fetchTest. It seems to not be properly exported through api object.
in TestPage.js trying console.log("api.fetchTest") : console displays undefined.
add a second testing function in index.js, whithout parameters, which just does console.log("test")
compare imports/exports and api declarations with other files in web-app/src/views/
create a handleSubmit() function in TestPage.js to not put the functions directly in return
delete node_modules and then yarn install
yarn workspace web-app build and then relaunch yarn workspace web-app start
(This is a Yarn Workspaces project containing a common/ and a web-app/ folders)
common/src/index.js:
import React, { createContext } from 'react';
import {FirebaseConfig} from 'config';
const FirebaseContext = createContext(null);
const FirebaseProvider = ({ children }) => {
console.log("firebaseprovider"); // is not displayed in the console
let firebase = { app: null, database: null, auth: null, storage:null }
if (!app.apps.length) { // I tried to comment out this line (and the '}') -> no difference
app.initializeApp(FirebaseConfig); // no difference when commented out
firebase = {
app: app,
database: app.database(),
auth: app.auth(),
storage: app.storage(),
// [ ... ] other lines of similar code
api : { // here are functions to import
fetchUser: () => (dispatch) => fetchUser()(dispatch)(firebase),
addProfile: (details) => (dispatch) => addProfile(userDetails)(dispatch)(firebase),
// [ ... ] other functions, properly exported and working in other files
// My function :
fetchTest: (testData) => (dispatch) => fetchTest(testData)(dispatch)(firebase),
}
}
}
return (
<FirebaseContext.Provider value={firebase}>
{children}
</FirebaseContext.Provider>
)
}
export { FirebaseContext, FirebaseProvider, store }
web-app/src/views/TestPage.js:
import React, { useContext } from "react";
import { useDispatch } from "react-redux";
import { FirebaseContext } from "common";
const TestPage.js = () => {
const { api } = useContext(FirebaseContext);
console.log(api); // Displays all functions in api object, but not fetchTest
const { fetchTest } = api;
const dispatch = useDispatch();
const testData = { validation: "pending" };
return <button onClick={ () => {
dispatch(fetchTest(testData)); // Tried with/without dispatch
alert("done");
}}>Test button</button>
}
export default TestPage;
web-app/src/App.js:
import React from 'react';
import { Router, Route, Switch } from 'react-router-dom';
// ... import all pages
import { Provider } from 'react-redux';
import TestPage from './views/CreateSiteNeed'; // written same way for the other pages
import { store, FirebaseProvider } from 'common';
function App() {
return (
<Provider store={store}>
<FirebaseProvider>
<AuthLoading>
<Router history={hist}>
<Switch>
<ProtectedRoute exact component={MyProfile} path="/profile" />
<!-- [ ... ] more <ProtectedRoute /> lines, form imported Pages line 3. -->
<ProtectedRoute exact component={TestPage} path="/testpage" />
</Switch>
</Router>
</AuthLoading>
</FirebaseProvider>
</Provider>
);
}
export default App;
I hope some people will find this post helpful, thanks
Here was the problem :
Firstly :
I'm using Redux, so fetchTest() has its testActions.js and testReducer.js files, which are functionnal. But I did forget to update my store.js :
// [ ... ] import all reducers
import { testReducer as testData } from '../reducers/testReducer'; // was'nt imported
const reducers = combineReducers({
auth,
usersdata,
// [ ... ] other imported reducers
testData // My test reducer
}
// The rest is a classic store.js code
Secondly :
As I'm using Yarn Workspaces, I had to compile the code in common/dist/index.js to make it accessible through the whole entire code (even for local testing).
Here is the command to compile the code (-> to include all redux edits made above) and make it accessible to web-app workspace :
yarn workspace common build && yarn workspace web-app add common#1.0.0 --force
Explanations on the second part of the command (yarn workspace web-app add common#1.0.0 --force) :
The web-app/package.json file contains { "dependencies": { ... "common":"1.0.0" ... }}
I have a VPS with Apache + Cpanel.
I can't configure Nginx over it, so the only way, as far as I know, is to 'static export' first then deploy it.
Turns out I can't access the product page by link pasted on url bar directly (not by click a link text).
The link is look like this : www.example.com/products/4 or www.example.com/products/213
My first suggestion is because I 'static export' the project.
I use next-routes with <Link />
My code
import React, { Component } from 'react';
import { withRouter } from 'next/router';
import { connect } from 'react-redux';
import fetch from 'isomorphic-fetch';
import Navbar from '../components/Navbar';
import Footer from '../components/Footer';
import CheckoutBody from '../components/CheckoutBody';
class Product extends Component {
static async getInitialProps({ query }) {
let { id } = { ...query };
if (id === undefined) id = 14;
const res = await fetch(`http://www.example.com/api/product?id=${id}`);
const data = await res.json();
return { campaignDetail: data };
}
render() {
let { lang } = this.props;
return (
<React.Fragment>
<Navbar />
<CheckoutBody
key={this.props.productDetail.id}
productDetail={this.props.productDetail}
lang={lang}
/>
<Footer />
</React.Fragment>
);
}
}
export default Product ;
Same question but different problem: https://github.com/zeit/next.js/issues/9893
I have tried this to .htaccess. It is not working. I am very newbie to regex and htaccess.
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule !.*\.html$ %{REQUEST_FILENAME}.html [L]
What should I do?
Is it what it's called dynamic routes?
The issue might be related to using next export rather than rewrite rule configuration. What we found is nextjs router pathname is not populated with the expected route on first hit if you use next export. Until this issue is fixed within nextjs, you can use a provider in _app.js that wraps your components and adjusts the route or put this before the return statement inside you _app.js default function:
import { useRouter } from 'next/router'
const { asPath, push, pathname } = useRouter()
if (asPath.split('?')[0] != pathname.split('?')[0] && !pathname.includes('[')) {
// Work around for next export breaking SPA routing on first hit
console.log('Browser route ' + asPath + ' did not match nextjs router route ' + pathname)
push(asPath)
return <div>Loading...</div>
}