next export with getServerSideProps #15674
Replies: 9 comments 10 replies
-
I've published a draftish, unsafe, untested Babel plugin that could help removing
Still not sure where to put it so it is triggered during export, but unit test are ok. The idea would be to use https://github.com/hashicorp/prebuild-webpack-plugin before calling |
Beta Was this translation helpful? Give feedback.
-
I am not very satisfied with the Babel approach after more digging. First it is difficult to setup, I've tried to use And I still can't consider relying on So the cleanest way to handle this would be to add an option to Digging into Next code, the following steps would be needed:
Example:
Regarding
|
Beta Was this translation helpful? Give feedback.
-
Wanted to add another +1 to this as a useful scenario. Specifically for the case of the same code base being deployed in different ways. In our scenario it seems allowing the presence of getServerSideProps in the codebase when exporting (but of course leaving it inactive in that scenario) would achieve our desired results.
Update on workaround for the "same codebase deploy as ssr or ssg": Works at the unit level, still testing end to end:
|
Beta Was this translation helpful? Give feedback.
-
Note that you may want to check what is bundled into the client export in this scenario, because as far as I understand, Next has some custom logic to remove server-related code from the client bundle when encountering |
Beta Was this translation helpful? Give feedback.
-
I put together a little babel plugin to help address this issue: https://github.com/erzr/next-babel-conditional-ssg-ssr |
Beta Was this translation helpful? Give feedback.
-
Wanted to add some more weight to this. One usecase for having a better fallback option so you can use For the PWA, you may want routes to be server-side rendered. However, if you then deploy that same code to iOS/Android using something like Capacitor, then you'd be doing an Having both in the code base is actually fairly natural, since those routes won't ever even fire when running in this case because all navigation is done client-side, but data fetching/etc. can be done using the exact same code in many cases (if making API calls rather than doing node operations) Going to check out some of these babel plugins, thanks @erzr! |
Beta Was this translation helpful? Give feedback.
-
Hey, just posting my workaround for mixing ssg and ssr routes with static export. After checking out other proposed solutions - I just ended up creating two separate directories Not pretty but fortunately not a blocker 🤷. And have an advantage of not having to hack webpack/babel - which is hard eg because of this: afterwind-io/preprocessor-loader#16 Btw. symlinks/links on directory & symlinks on files did not work. But hard links on files do. // scripts/link.ts
#!/usr/bin/node
import arg from 'arg'
import fs from 'fs-extra'
import glob from 'globby'
export type LinkOptions = {
mode: 'ssr' | 'ssg'
}
// this just switches between ssg and ssr version of the app pages.
// but you can also rewrite it to link both for ssr and opnly sgg for ssg.
// or use filenames like `page.ssr.ts` naming from single directory, filter it, and rename it during linking
export async function linkPages({ mode }: LinkOptions) {
const source = `src/pages-${mode}`
const target = `src/pages`
await fs.emptyDir(target)
const paths = await glob(source, { absolute: false, fs })
await Promise.all(paths.map(path => fs.ensureLink(path, path.replace(source, target))))
console.log(`Linked pages from ${source} to ${target}.`)
}
// run as cli script if this directory was called
if (require.main?.filename === __filename) {
const { '--mode': mode } = arg({
'--mode': String,
})
if (!mode) {
throw new Error(`--mode is required`)
}
if (mode !== 'ssr' && mode !== 'ssg') {
throw new Error(`--mode should be ssr or ssg`)
}
linkPages({ mode })
} To handle caching correctly (I have this issue also with webpack-preprocessor-loader & custom babel plugin solution) I use two separate dist directories eg. // next.config.js
module.exports = {
distDir: process.env.DIST_DIR
} And simple usage can be like: # build ssr
DIST_BUILD=.next-ssr
ts-node -T scripts/link --mode ssr
next build
# build & export sss
DIST_BUILD=.next-ssg
ts-node -T scripts/link --mode ssg
next build
next export |
Beta Was this translation helpful? Give feedback.
-
I found a way to export an application that has export const getServerSideProps = process.env.SKIP_SSR ? undefined : myFunctionToGetProps; But this is still a hack that requires a separate build of the project. SKIP_SSR=1 next build && next export |
Beta Was this translation helpful? Give feedback.
-
With Capacitor your app has to be built out using After doing some digging I found out that using The goal I have is so when I generate the native version of the app, it will contain the beauties of SSR with the possibility of SEO (especially for Open Graph social cards) but allow the app to be used the same on mobile and when/if a user wants to share a link it will still show a Social card upon sharing. I've looked into the pitfalls of getInitialProps and it states that Static generation is not possible, but it is usable on separate pages (which is good) and the only "negative" use I see for it is that it's likely going into the deprecation stage sooner or later. |
Beta Was this translation helpful? Give feedback.
-
Feature request
Is your feature request related to a problem? Please describe.
Why using both next export and
getServerSideProps
I develop apps that may be deployed on premise. For the same codebase, I'd like to leverage as many deployment options as possible.
next export
is the simplest of them. The interesting part is that it doesn't depend on Node, or on the build environment: I can deliver it as is to a client that don't have the ability to install Node.js on its server/dev machine.It does happen more than one can think, even in 2020 especially in big/old companies where introducing a new technology is a complicated process, or that do not use SaaS applications at this point."normal" deployment with a Node server and SSR, for other companies
I may need to deploy the same app on dozens of companies, I really do need to keep a "no dependency to Node" strategy around.
Edit: other relevant use cases:
getServerSideProps
for some optional feature, and thus break your export. So even if you just wantnext export
, without ever usinggetServerSideProps
, you may have some troubleProblem
next export
will just fail if a page is usinggetServerSideProps
.Limitations
I am aware that
next export
is a a secondary feature. However, when you use it for an app, you do use it and it become a very important part of the deployment process.I am also aware that supporting
next export
andgetServerSideProps
altogether would definitely create confusion for end user. Mostly because static export seems to be confused with Next's build-time server-side rendering+incremental refresh, so people forget that they don't have a server in this scenario.Of course, for this to work, you need your
getServerSideProps
function to be optional. It should either be limited to a performance boost (eg caching stuff in Apollo, redirecting quickly), or "duplicated" in the client code when it doesn't run.Describe the solution you'd like
Possibles solutions, in order of preference:
Don't throw an error, just a big warning, when exporting pages with
getServerSideProps
. And of course ignore the function itself.We already ignore API routes during next export so we could ignore
getServerSideProps
tooDon't deprecate
getInitialProps
, instead consider it as advanced feature that can be used to handle multiple scenarios in the same page, and maybe improve it to make it easier to differentiate the current rendering scenario (client, server, static export). Currently you have to reach the old documentation to get it, and play around with contextreq
to guess the current environment.Add an option to allow exporting a page that include
getServerSideProps
, egallowStaticExport
,optionalGetServerSideProps
,makeSureThatYourPageWorkWithoutGetServerSidePropsToo
, whateverCreate a new callback,
getIsomorphicProps
, that should work both client-side and server-side (unrealistic, because you wouldn't be able to use React hook, or access the server request, so you wouldn't be able to code smth clean, but you get the idea)Create a new callback,
getPrecomputedServerSideProps
, that is explicitely meant to be optionalDescribe alternatives you've considered
Using
getInitialProps
is a palliative, see our withPrivateAccess HOC that supports all scenarios.Other possible alternative proposed by @jescalan: create a Babel plugin/script that removes
getServerSideProps
from the code and imported modules, and tweakexport
command like so"export": "node ./scripts/remove-server-props.js && next export
.But again IMO if export doesn't fail when there are API routes in the code it probably should'n't fail when there are
getServerSideProps
in a page.Additional context
The apps I develop are almost softwares, so few pages, but high complexity on each page. SSR is cool when you host yourself, but static export is also cool in this scenario, especially when you host on-premise as it is almost similar to an executable you can reuse on any machine.
I can't predict which deployment scenario will be used at the time I write the code, I often get the info mid-project.
Also, I use Apollo massively. It's a good fit for this multi-target export scenario: server-side, you can prefill the cache by running queries. But client-side, Apollo is also able to rerun the query if it failed during server-render or was never run in the first place (basically when it encounter a cache miss).
Eventually, when running Cypress tests, you can't mock server side rendering calls. Since SSR can't be disabled on the fly, one possible path is to use
next export
when your app supports it alongside SSR.Related discussions
next export
, you have to pick one if you want i18n Next export is broken with v6.0.0 i18next/next-i18next#780Beta Was this translation helpful? Give feedback.
All reactions