Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tree shaking for getStaticProps not working #27741

Closed
nicholaschiang opened this issue Aug 3, 2021 · 7 comments
Closed

Tree shaking for getStaticProps not working #27741

nicholaschiang opened this issue Aug 3, 2021 · 7 comments
Labels
bug Issue was opened via the bug report template. please add a complete reproduction The issue lacks information for further investigation

Comments

@nicholaschiang
Copy link
Contributor

What version of Next.js are you using?

10.1.2

What version of Node.js are you using?

12.18.3

What browser are you using?

Firefox

What operating system are you using?

Ubuntu 20.04 LTS (Pop_OS! 20.04 LTS)

How are you deploying your application?

Vercel

Describe the Bug

Tree shaking for getStaticProps doesn't work properly when re-exporting reusable props functions:

// lib/page.ts
import { GetStaticPathsResult } from 'next';

import { OrgJSON } from 'lib/model/org';
import { getOrgs } from 'lib/api/db/org';

export interface PageProps {
  orgs?: OrgJSON[];
}

export async function getPageProps(): Promise<{ props: PageProps }> {
  const orgs = (await getOrgs()).map((o) => o.toJSON());
  return { props: { orgs } };
}

export async function getPagePaths(): Promise<GetStaticPathsResult> {
  return { paths: [], fallback: true };
}

I then re-export those getPageProps and getPagePaths from that file in my pages:

// pages/[org]/settings/index.tsx
import { getPagePaths, getPageProps } from 'lib/page';
...
export const getStaticProps = getPageProps;
export const getStaticPaths = getPagePaths;

And the getPagePaths and getPageProps aren't properly tree shaken. They still try to appear in the client-side bundle; I know this because my build fails with the error:

12:15:38.782 | Failed to compile.
12:15:38.783 | ModuleNotFoundError: Module not found: Error: Can't resolve 'fs' in '/vercel/path0/node_modules/winston/dist/winston/transports'
12:15:38.783 | > Build error occurred
12:15:38.784 | Error: > Build failed because of webpack errors
12:15:38.784 | at /vercel/path0/node_modules/next/dist/build/index.js:17:924
12:15:38.784 | at async Span.traceAsyncFn (/vercel/path0/node_modules/next/dist/telemetry/trace/trace.js:5:584)
12:15:38.880 | Error: Command "yarn run build" exited with 1

That ☝️ error occurs because my API logger (Winston which uses fs which is only available in server-side environments) is being imported into lib/api/db/org.ts which is imported by lib/page.ts which is (incorrectly) not tree shaken by Next.js even though it is only used in getStaticProps.

Expected Behavior

Next.js should tree shake imports that are re-exported as getStaticProps or getStaticPaths (and not include them in the client-side bundle).

To Reproduce

See issue description.

@nicholaschiang nicholaschiang added the bug Issue was opened via the bug report template. label Aug 3, 2021
nicholaschiang added a commit to tutorbookapp/tutorbook that referenced this issue Aug 3, 2021
@masx200
Copy link

masx200 commented Aug 4, 2021

// pages/[org]/settings/index.tsx
import { getPagePaths, getPageProps } from 'lib/page';
//...
export {  getPageProps as getStaticProps};
export  {  getPagePaths as getStaticPaths};

@masx200
Copy link

masx200 commented Aug 4, 2021

I also encountered a similar problem. I used the refactoring function of vscode to extract all the code that only runs on the server to a new file, and the problem was solved.

@timneutkens timneutkens added the please add a complete reproduction The issue lacks information for further investigation label Aug 4, 2021
@timneutkens
Copy link
Member

Can you share a full reproduction? You can check the tree shaking here: https://next-code-elimination.vercel.app/. Your example of:

import { getPagePaths, getPageProps } from 'lib/page';

export const getStaticProps = getPageProps;
export const getStaticPaths = getPagePaths;

Is correctly shaken from the page file, so it's likely something else.

A separate module can't contain both client-side JS and server-side JS as the tree shaking of getStaticProps, getStaticPaths, and getServerSideProps only runs on the page file itself, if you end up doing something like:

import { getPagePaths, getPageProps, SomeComponent } from 'lib/page';

export const getStaticProps = getPageProps;
export const getStaticPaths = getPagePaths;

export default function Home() {
  // Note that SomeComponent is imported from `lib/page` which imports server-only modules like `fs`
  return <SomeComponent />
}

It will not work because the tree shaking only removes the getPagePaths and getPageProps import and does not actually change lib/page.

@glantucan
Copy link

glantucan commented Sep 15, 2021

@timneutkens
That makes sense, but I have separated modules containing only serve-rside code and get a similar error.
Is it that we can't use separated modules at all? I kind of need that, as I have some somewhat complex logic that has to be run on the getStaticProps and getStaticPaths of several pages and I abstracted and encapsulated it away in several separated modules that I import on my pages and invoke from those functions as needed, Those imported modules use fs and knex

I get a similar error on build if I don't do this on my next.config.js:

module.exports = {
  // ...
  webpack5: true, 
  webpack: (config, { webpack, isServer}) => {
    config.externals = config.externals.concat(['mssql', 'mysql2', 'oracle', 'oracledb', 'postgres', 
      'redshift', 'sqlite3', 'pg', 'pg-query-stream', 'tedious',  { knex: 'commonjs knex' } ]);
    if (!isServer) {
      config.resolve.fallback.fs = false;
    }
    return config;
  },
}

Which looks kind of of ugly to me. Basically because I don't understand it

Is there a nicer, DRY way to do that than copying all that logic on each getStaticProps or getStatcPaths?

@timneutkens
Copy link
Member

@glantucan you can import external files, you just have to make sure the files with server code are not also exporting client-side code.

Going to close this issue as my previous comment got a 👍

@denis-sokolov
Copy link

This seems to possibly be a duplicate of #16153.

@balazsorban44
Copy link
Member

This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@vercel vercel locked as resolved and limited conversation to collaborators Jan 27, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Issue was opened via the bug report template. please add a complete reproduction The issue lacks information for further investigation
Projects
None yet
Development

No branches or pull requests

6 participants