next-translate icon indicating copy to clipboard operation
next-translate copied to clipboard

Wrong detection of getInitialProps on _app.tsx

Open aganjali opened this issue 4 years ago • 8 comments

Hi everyone

seems that the lib detect getInitialProps on _app.js (or any other pages) with definition like below:

import { Provider } from 'react-redux' 
import store from '@store'

import type { AppProps } from 'next/app'
import '@styles/index.scss'

const MyApp: React.FC<AppProps> = ({ Component, pageProps }) => {
  

  return (
    <Provider store={store}>
      <Component {...pageProps} />
    </Provider>
  )
}

export default MyApp

with this definition model i get Warning: You have opted-out of Automatic Static Optimization due to getInitialProps in pages/_app. This does not opt-out pages with getStaticProps

and on the other pages than _app.js for example pages/index.tsx


import Head from 'next/head' 
import Link from 'next/link' 
interface Props {}

const Home: React.FC<Props> = () => {
   
  return (
    <div className="absolute inset-0 w-full h-full ">
      <Head>
        <title>Create Next App</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      
      >
        change from {test}
      </button>
      <Link href="/test">
        <a>test</a>
      </Link>
    </div>
  )
}

export default Home

i get this warning:

[next-translate] In Next 10.x.x there is an issue related to i18n and getInitialProps. We recommend to replace getInitialProps to getServerSideProps on /index.tsx. Issue: https://github.com/vercel/next.js/issues/18396

UPDATE: When i remove those React.FC<Props> the errors gone!

UPDATE: With code below also i get the warning [next-translate] In Next 10.x.x there is an issue related to i18n and getInitialProps. We recommend to replace getInitialProps to getServerSideProps on /index.tsx. Issue: https://github.com/vercel/next.js/issues/18396

import Head from 'next/head';

const Home = () => {
  return (
    <div className="flex-1 w-full  ">
      <Head>
        <title>Test</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
    </div>
  );
};
Home.getLayout = (page: React.ReactNode) => {
  <div className="absolute flex flex-col inset-0">{page}</div>;
};

export default Home;

aganjali avatar Feb 01 '21 14:02 aganjali

forgot to mention

  "dependencies": { 
    "next": "10.0.5", 
    "next-translate": "^1.0.2", 
    "react": "17.0.1",
    "react-dom": "17.0.1", 
  },

aganjali avatar Feb 01 '21 14:02 aganjali

Indeed I have the same issue, it might be a duplicate of this issue : #453.

theoludwig avatar Feb 08 '21 16:02 theoludwig

I am getting this warning when getting a production built of my app:

Warning: You have opted-out of Automatic Static Optimization due to getInitialProps in pages/_app. This does not opt-out pages with getStaticProps

While, there is no getInitialProps whatsoever anywhere in my app, I found out that it happens as soon as I make use of nextTranslate in my next.config.js, Also, I can confirm that everything works fine but, it turns all my pages even those which are fully static into server side rendered !!!!!

NextJs Version: 10.0.9 next-translate Version: 1.0.4

Shariaty avatar Mar 30 '21 09:03 Shariaty

for the guys having problems with this I can recommend to stay on 1.0.1. For me everything is still fine there

BjoernRave avatar Apr 17 '21 19:04 BjoernRave

This really needs to be fixed! @Shariaty what's your workaround?

Axedyson avatar Jun 11 '22 12:06 Axedyson

I'm getting the same issue with the latest release 😭

jahirfiquitiva avatar Jun 14 '22 22:06 jahirfiquitiva

I've done some digging around and I've found the source of this problem (at least in my case). The whole issue is centered around the hasHOC function inside of utils.ts. It produces some false detections, which in turn cause the next-translate to use the getInitialProps loader.

https://github.com/vinissimus/next-translate/blob/8a28e76bd75c958191db2fa8cb7b137625c4e774/src/plugin/utils.ts#L51

Problem 1: I was exporting a reference to my app instead of directly exporting the function


My _app.tsx looked something along these lines:

const MyApp: React.FC = () => {
  // ...
}

export default MyApp;

This caused the isRefLine and isPotentialHOC regexps to be evaluated as true (from my understanding, the ref is basically the name of your export, so anything containing the MyApp would be matched. As for isPotentialHOC, it simply checks for any assignment that has an opening bracket, so in this case, the line const MyApp: React.FC = () => { produces a match)

https://github.com/vinissimus/next-translate/blob/8a28e76bd75c958191db2fa8cb7b137625c4e774/src/plugin/utils.ts#L89-L104

What's interesting is that the isArrowFunc var should be evaluated as true, which would prevent this line from being treated as a HOC, but the regexp does not work correctly for variables with type annotations that contain non-alphanumeric characters (\w matches alphanumerics and underscore, so the dot in React.FC prevents the match) nor for multiline declarations (i.e. formatted by prettier).

image

This matches with the behaviour described by the issue author

When i remove those React.FC the errors gone!

All of this combined caused the filter function to accept this line. The hasHOC function at this point simply checks whether there were any matches (.length > 0), so it also returns true.

The hasHOC function is called from the plugin/index.js, and as it returns true, the hasGetInitialPropsOnAppJs is also being set to true, thus making the app use the getInitialLoader even though it is not used in _app.tsx

https://github.com/vinissimus/next-translate/blob/8a28e76bd75c958191db2fa8cb7b137625c4e774/src/plugin/index.ts#L61-L62

Changing my _app.tsx to the following resolved the first problem

export default function MyApp() {
 //
}

Problem 2: Static properties on the page object


Inside of my pages, I'm using the layout pattern (just like the author of the issue inside of his updated component). Basically, my pages look like this:

const MyPage: NextPage = () => {
  // ...
}

MyPage.getLayout = getBaseLayout();

export default MyPage;

Just like with the first problem, we have a ref (MyPage) and an opening bracket on the same line (const MyPage: NextPage = () => {), but this time it gets correctly recognised as an arrow function, because the type annotation contains only alphanumeric characters:

image

The new issue here is the line MyPage.getLayout = getBaseLayout(), which causes both isRefLine and isPotentialHOC to be evaluated as true, thus resulting in a false HOC detection, and causing the page to be loaded using getInitialProps

I have solved this problem with a simple change

const MyPage: NextPage = () => {
  // ...
}

// We no longer have the ref name and assignment with an opening bracket on the same line
const Layout = getBaseLayout();

// No opening bracket after the assignment, so isPotentialHOC is evaluated as false
MyPage.getLayout = Layout;

export default MyPage;

If your layouts are a simple assignment and not a function call then I guess this problem would not occur. Anyway, the 3 main takeaways from this are:

  • Use a direct export default function MyApp in your _app
  • If you have any static prop assignments on your page component make sure you do not have the page component name and an assignment containing an opening bracket on the same line
  • If you use type annotations in your exports (pages / app), make sure they contain only alphanumeric characters

I think this could be even simplified to "Make sure your code does not have the exported component name and an assignment with an opening bracket on the same line".

In my opinion the best way to fix this would be to ditch the regexp parsing in favour of actual code parsing and transforming, as proposed in #854, but using Babel could cause another problem, which is forcing users to opt-out of SWC. Another solution would be to tweak the regular expressions and document their limitations.

@aralroca maybe it would be worthwhile to include this information in the documentation?

miikebar avatar Jun 27 '22 18:06 miikebar

@aganjali @Divlo @Shariaty @BjoernRave @Axedyson @jahirfiquitiva @MrPumpking The idea of 2.0 version is to change the regular expressions in a better way. Currently, there are 2 proposals: with Babel parser and with TypeScript compiler.

We need feedback from the people to decide which one corrects more errors and does not generate new ones.

This bug should be fixed with the new version Can you test these two prereleases and give feedback?

With Babel: 2.0.0-experimental.1

With TypeScript compiler: 2.0.0-experimental.2

You can use this discussion to write your feedback:

https://github.com/aralroca/next-translate/discussions/881

Thank you so much!

aralroca avatar Sep 20 '22 11:09 aralroca

I believe this issue has been resolved with Next-translate 2.0, as we have rewritten the plugin and replaced the use of regex with a parser. This update has automatically addressed many of the issues related to attempting to parse items with regex.

I trust that this solution has fully resolved the matter, and as such, I will proceed to close the issue. Additionally, I would like to inform you that we have moved the plugin to this repository: https://github.com/aralroca/next-translate-plugin.

If, for any reason, you find that the issue has not been fully resolved, please feel free to reopen the issue on the next-translate-plugin repository.

Thank you very much.

aralroca avatar Feb 20 '23 17:02 aralroca