Nextjs로 Emotionjs을 사용한 파일 이름을 style.tsx 또는 style.jsx, style.ts로 정한 후 import해서 build시 "Error occurred prerendering page '/examplePage'" 문제 해결하기

Maliethy·2022년 2월 5일
0

typscript-error

목록 보기
4/4

1. issue

Nextjs + Emotionjs + Typescript을 사용하여 만든 프로젝트에서 여러 페이지에서 공통으로 사용하는 레이아웃인 AppLayout으로 만든 component에서 style코드를 다음과 같이 style.tsx로 분리하니 다음과 같은 에러가 나타났다.
error case - layouts folder structure

node version = v16.13.2(lts)

/package.json

  "dependencies": {
    "@emotion/react": "^11.1.5",
    "@emotion/styled": "^11.1.5",
    "@meronex/icons": "^4.0.0",
    "@next/bundle-analyzer": "^10.2.0",
    "@reduxjs/toolkit": "^1.5.1",
    "@types/react-cookies": "^0.1.0",
    "antd": "^4.16.0",
    "axios": "^0.21.1",
    "babel-plugin-import": "^1.13.3",
    "formik": "^2.2.8",
    "formik-antd": "^2.0.1",
    "less-loader": "^9.0.0",
    "lodash": "^4.17.21",
    "next": "^11.1.3",
    "next-compose-plugins": "^2.2.1",
    "next-cookies": "^2.0.3",
    "next-plugin-antd-less": "^1.2.1",
    "next-redux-wrapper": "^6.0.2",
    "react": "^17.0.2",
    "react-cookies": "^0.1.1",
    "react-daum-postcode": "^2.0.6",
    "react-dom": "^17.0.2",
    "react-redux": "^7.2.4",
    "react-scroll-hooks": "^0.1.1",
    "react-top-loading-bar": "^2.0.1",
    "redux": "^4.1.0",
    "redux-logger": "^3.0.6",
    "typescript": "^4.2.4",
    "xlsx": "^0.17.1",
    "yup": "^0.32.9"
  },
  "devDependencies": {
    "@babel/core": "^7.14.0",
    "@emotion/babel-plugin": "^11.7.2",
    "@next/eslint-plugin-next": "^12.0.1",
    "@types/node": "^15.3.0",
    "@types/react": "^17.0.5",
    "@typescript-eslint/eslint-plugin": "^4.24.0",
    "@typescript-eslint/parser": "^4.24.0",
    "css-loader": "^6.5.1",
    "eslint": "^7.26.0",
    "eslint-config-next": "12.0.1",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-prettier": "^4.0.0",
    "file-loader": "^6.2.0",
    "nodemon": "^2.0.7",
    "prettier": "^2.3.0",
    "url-loader": "^4.1.1"
  }

error message

        ...
Error occurred prerendering page "/batchOrder/uploadCNPlusExcelFile". Read more: https://nextjs.org/docs/messages/prerender-error
Error: Minified React error #130; visit https://reactjs.org/docs/error-decoder.html?invariant=130&args[]=undefined&args[]= for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
    at a.b.render (/Users/juyoung/projects/modu-oms-admin-antd/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:45:32)
    at a.b.read (/Users/juyoung/projects/modu-oms-admin-antd/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:41:83)
    at Object.exports.renderToString (/Users/juyoung/projects/modu-oms-admin-antd/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:52:138)
    at Object.renderPage (/Users/juyoung/projects/modu-oms-admin-antd/node_modules/next/dist/server/render.js:596:45)
    at Function.getInitialProps (/Users/juyoung/projects/modu-oms-admin-antd/.next/server/pages/_document.js:601:19)
    at Object.loadGetInitialProps (/Users/juyoung/projects/modu-oms-admin-antd/node_modules/next/dist/shared/lib/utils.js:69:29)
    at renderDocument (/Users/juyoung/projects/modu-oms-admin-antd/node_modules/next/dist/server/render.js:609:48)
    at renderToHTML (/Users/juyoung/projects/modu-oms-admin-antd/node_modules/next/dist/server/render.js:647:34)
    at async /Users/juyoung/projects/modu-oms-admin-antd/node_modules/next/dist/export/worker.js:273:36
    at async Span.traceAsyncFn (/Users/juyoung/projects/modu-oms-admin-antd/node_modules/next/dist/telemetry/trace/trace.js:60:20)

Error occurred prerendering page "/batchOrder/uploadOrderList". Read more: https://nextjs.org/docs/messages/prerender-error
Error: Minified React error #130; visit https://reactjs.org/docs/error-decoder.html?invariant=130&args[]=undefined&args[]= for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
    at a.b.render (/Users/juyoung/projects/modu-oms-admin-antd/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:45:32)
    at a.b.read (/Users/juyoung/projects/modu-oms-admin-antd/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:41:83)
    at Object.exports.renderToString (/Users/juyoung/projects/modu-oms-admin-antd/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:52:138)
    at Object.renderPage (/Users/juyoung/projects/modu-oms-admin-antd/node_modules/next/dist/server/render.js:596:45)
    at Function.getInitialProps (/Users/juyoung/projects/modu-oms-admin-antd/.next/server/pages/_document.js:601:19)
    at Object.loadGetInitialProps (/Users/juyoung/projects/modu-oms-admin-antd/node_modules/next/dist/shared/lib/utils.js:69:29)
    at renderDocument (/Users/juyoung/projects/modu-oms-admin-antd/node_modules/next/dist/server/render.js:609:48)
    at renderToHTML (/Users/juyoung/projects/modu-oms-admin-antd/node_modules/next/dist/server/render.js:647:34)
    at async /Users/juyoung/projects/modu-oms-admin-antd/node_modules/next/dist/export/worker.js:273:36
    at async Span.traceAsyncFn (/Users/juyoung/projects/modu-oms-admin-antd/node_modules/next/dist/telemetry/trace/trace.js:60:20)
info  - Generating static pages (20/20)

> Build error occurred
Error: Export encountered errors on following paths:
        /batchOrder/batchOrderStatusLists
        /batchOrder/registerNewExcelSchema
        /batchOrder/uploadCNPlusExcelFile
        /batchOrder/uploadOrderList
        /cancel
        /centerEmployeeManagement
        /exchange
        /myInfo
        /noneExport
        /noneExport/checkNoneExport
        /order
        /pwdChange
        /return
        /syncProductOrderID
        /syncProductOrderID/syncSelfLogisticProductOrderID
        /waitConfirmUserLists
    at /Users/juyoung/projects/modu-oms-admin-antd/node_modules/next/dist/export/index.js:487:19
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Span.traceAsyncFn (/Users/juyoung/projects/modu-oms-admin-antd/node_modules/next/dist/telemetry/trace/trace.js:60:20)
    at async /Users/juyoung/projects/modu-oms-admin-antd/node_modules/next/dist/build/index.js:833:17
    at async Span.traceAsyncFn (/Users/juyoung/projects/modu-oms-admin-antd/node_modules/next/dist/telemetry/trace/trace.js:60:20)
    at async /Users/juyoung/projects/modu-oms-admin-antd/node_modules/next/dist/build/index.js:707:13
    at async Span.traceAsyncFn (/Users/juyoung/projects/modu-oms-admin-antd/node_modules/next/dist/telemetry/trace/trace.js:60:20)
    at async Object.build [as default] (/Users/juyoung/projects/modu-oms-admin-antd/node_modules/next/dist/build/index.js:77:25)

/styles/AppLayout/index.tsx 코드는 다음과 같다.

/styles/AppLayout/index.tsx

import {
  GlobalLayout,
  SiderTitle,
} from './style';


function AppLayout({ children }) {

  return( 
  <Layout>
      <GlobalLayout />
         <SiderTitle>
                ... 
         </SiderTitle>
 </Layout>);
}

export default AppLayout;

/styles/AppLayout/style.tsx

import styled from '@emotion/styled';
import { Global, css } from '@emotion/react';

export const GlobalLayout = () => (
  <Global
    styles={css`
      .site-layout {
        width: 100vw;
        height: 100vh;
      }

      .ant-menu-dark .ant-menu-inline.ant-menu-sub {
        background: #fafafa24;
      }
      .ant-menu-dark .ant-menu-item > span > a {
        line-height: 20px;
        font-size: 12px;
        color: rgba(255, 255, 255, 0.6);
        font-weight: 600;
        padding-bottom: 15px;
      }

      .ant-layout-sider {
        margin-top: 50px;
      }
      .progress-line {
        top: 50px !important;
        z-index: 11 !important;
      }
  />
);

AppLayout을 사용하는 페이지 코드 예시는 다음과 같다.

/pages/index.tsx

import {
  GlobalLayout,
  PageContainer,
} from '@styles/index';
import AppLayout from '@styles/AppLayout';

function Index() {
  return (
    <AppLayout getListsDoneOrError={GetOrderListsDone || GetOrderListsError}>
      <GlobalLayout />
      <PageContainer>
         ...
      </PageContainer>
    </AppLayout>
  );
}

export default Order;

Emotionjs 공식문서에서 타입스크립 관련 설정은 다음과 같이 TSConfig compilerOptions이 다음 설정을 포함하면 된다고 나온다.

"jsx": "react-jsx",
"jsxImportSource": "@emotion/react"
https://emotion.sh/docs/typescript

/tsconfig.json

{
  "compilerOptions": {
    "types": ["node", "@emotion/react/types/css-prop"],
    "jsx": "preserve",//nextjs에서 자동으로 설정됨
    "jsxImportSource": "@emotion/react",//Emotionjs 공식문서를 따라 이 부분 추가
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
     "baseUrl": ".",
    "paths": {
      "@hooks/*": ["hooks/*"],
      "@components/*": ["components/*"],
      "@layouts/*": ["layouts/*"],
      "@utils/*": ["utils/*"],
      "@typings/*": ["typings/*"],
      "@public/*": ["public/*"],
      "@redux/*": ["redux/*"],
      "@data/*": ["data/*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx" ],
  "exclude": ["node_modules"]
}

또한 typescript 사용자 중 이미 babel를 쓰고 있다면 @emotion/babel-plugin를 설치하는 것이 좋다고 공식문서에는 나왔어 다음과 같이 .babelrc를 설정했다.

On the other hand, there’s no reason not to use @emotion/babel-plugin if you are already using Babel to transpile your TypeScript code.

.babelrc

{
  "presets": [
    [
      "next/babel",
      {
        "preset-react": {
          "runtime": "automatic",
          "importSource": "@emotion/react"
        }
      }
    ]
  ],
  "plugins": [["import", { "libraryName": "antd", "style": true }], ["@emotion/babel-plugin"]]//["import", { "libraryName": "antd", "style": true }] 부분은
  next-plugin-antd-less 설정

}

2. solution

다음과 같이 /styles/AppLayout/style.tsx파일 확장자를 /styles/AppLayout/style.js로 변경하니 에러가 해결되었다.

solve case - layouts folder structure

빌드가 성공하면서 next build를 할 때 또한 tsconfig.json의 include안에 styles안의 파일들의 경로가 자동으로 추가되었다.

  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx",
    "styles/excel.tsx",
    "styles/center.ts",
    "styles/excel.ts",
    "styles/home.js",
    "styles/index.tsx",
    "styles/mapping.tsx",
    "styles/signUp.js",
    "styles/userInfo.js",
    "styles/style.js"
  ],

반면 파일명을 /styles/AppLayout/style.jsx, /styles/AppLayout/style.tsx로 변경해 빌드하면 모두 에러가 났다. /styles/AppLayout/style.tsx를 인식하지 못해서 Nextjs server에서 Prerender Error가 난 듯하다.

에러 원인을 찾기 위해 먼저 styles라는 폴더 안에 있어서 생기는 문제인지 확인하기 위해 AppLayout(/styles/AppLayout/index.tsx)을 components 폴더에 넣고 appLayout.style.tsx(/styles/AppLayout/style.tsx와 동일)을 styles 폴더에 분리하니 또한 에러가 해결되었다.
AppLayout at components folder
appLayout.style.tsx at styles folder

appLayout.style.tsx 파일을 components폴더 안의 AppLayout 폴더에 넣어도 에러가 안나고 인식이 된다.
appLayout.style.tsx at components folder

그러나 appLayout.style.tsx이라는 이름을 style.tsx로 바꾸면 다시 에러가 났다.
change name appLayout.style.tsx to style.tsx at components folder

이는 styles 폴더 안에서도 마찬가지로 appLayout.style.tsx이라는 이름과 함께 AppLayout폴더를 styles폴더에 넣으면 에러가 안나지만 style.tsx로 바꾸면 에러가 난다.
AppLayout at styles folder

style이라는 이름이 빌드시 인식되지 않는 문제인 듯해서 test로 이름을 바꾸어 시도해보니 역시나 빌드가 성공했다.
change name style.tsx to test.tsx

style.tsx에 다음과 같은 writeText변수를 선언하고 AppLayout에서 import하면 빌드가 성공한다.

/components/AppLayout/style.tsx

export const writeText = 'this is test';

/components/AppLayout/style.tsx

import {
  GlobalLayout,
  SiderTitle,
} from './style';


function AppLayout({ children }) {

  return( 
  <Layout>
      <GlobalLayout />
         <SiderTitle>
                {writeTitle}
         </SiderTitle>
 </Layout>);
}

export default AppLayout;

한편 style.tsx에 다음과 같은 styled component인 WriteText변수를 선언하고 AppLayout에서 import하면 또한 빌드가 성공한다.

/components/AppLayout/style.tsx

export const WriteTitle = styled.div`
  font-size: 30px;
`;

/components/AppLayout/style.tsx

import {WriteTitle} from './style';


function AppLayout({ children }) {

  return( 
  <Layout>
      <GlobalLayout />
         <SiderTitle>
                  <WriteTitle>this is test</WriteTitle>
         </SiderTitle>
 </Layout>);
}

export default AppLayout;

@emotion/react의 Global과 css를 사용해 만든 style component 또한 빌드 성공이다.
/components/AppLayout/style.tsx

import { Global, css } from '@emotion/react';

export const WriteTitle = () => (
  <Global
    styles={css`
      .site-layout {
        width: 100vw;
        height: 100vh;
      }
    `}
  />
);

결국 style.tsx라는 이름이 문제였다는 건데 https://github.com/vercel/next.js/issues/25276를 보면 nextjs 11v가 webpack4에서 webpack5으로 바뀌는 과정에서 동적 css를 생성하는 부분에 문제가 있다는 현상이 있다고 하지만 이것이 원인인지는 모르겠다.

ps. 에러 원인을 아시는 능력자 분들의 조언 구합니다!

참고:
https://nextjs.org/docs/messages/prerender-error
https://github.com/vercel/next.js/tree/canary/examples/with-emotion
https://www.typescriptlang.org/docs/handbook/module-resolution.html
https://stackoverflow.com/questions/70185127/how-to-fix-prerender-error-when-deploying-nextjs-on-vercel

profile
바꿀 수 있는 것에 주목하자

0개의 댓글