Next.js can't be used for apps running on Smart TV (e.g., on Samsung Tizen platform) or for other client-side rendered apps with dynamic data requirements.
It would be great if Next.js could be used for client-side only apps and still support dynamic routing and automatic code-splitting.
Next.js introduces a mode for building app as a single-page application (SPA). getInitialProps works just like before, but is executed on the client only.
The new option for SPA mode is added to _next.config.js_:
module.exports = {
…,
spa: true
};
The open question is how to handle both SPA mode and SSG. It looks like it's still possible to do it on a per-page basis (suggested in this RFC). Although there's no clear benefit of using a hybrid app for Smart TV use case as TV apps are hosted locally on the device.
Static export is not an option because the app has dynamic data requirements.
SSR doesn't make sense because the app is hosted locally on the TV device. It's not a technical option either because Node.js isn't available on the TV.
So, the alternative that is left is running the app without Next.js.
This RFC mentions the support of "client-side only applications" as one of the goals.
Nuxt.js supports a dedicated mode for building SPA.
Smart TV apps are web apps that are executed by TV's browser engine:
Some Smart TV platforms like webOS TV support hosted web apps, others like Tizen prohibit such kind of apps.
👋 @grushetsky,
I might be wrong, but I'm not sure why using Next.js in 'SPA mode' is a problem now. You can achieve this by limiting your app to just one page:
// pages/index.js
import dynamic from "next/dynamic";
const SpaRoot = dynamic(
() => import("../components/SpaRoot"),
{ ssr: false },
);
const IndexPage = () => {
return <SpaRoot />;
};
export default IndexPage;
And then use next build && next export to produce the production app.
components/SpaRoot can contain any dynamic logic you want as it is only going to load on the client. Eg. you can use your own router or data fetching there. Next.js will play a role of the devserver and will produce you a static bundle too. Things will work similarly to CRA, but with more freedom to customise things if needed. We use Next.js in such 'mode' in a couple of apps that were previously pure webpack-based SPAs.
@kachkaev, hey! 👋
Thank you for the suggestion! Let me try to dissect this idea.
First, there's a limit of a single page. It might sound reasonable that a single page is enough for a single-page application, but that's not exactly the case. 🙂 With file-system routing, each page is mapped to the corresponding route. This behaviour is enabled by default along with the built-in router, Link component, prefetching, etc. It's undesirable to lose all these features. In the context of single-page application "Next.js page" is probably a confusing name, but conceptually it is as beneficial for SPA as it is for SSG or SSR case.
Second, what about automatic code-splitting? It's a sane thing to do even for an app hosted locally on the TV (to reduce parse time, for example). One can implement code-splitting manually, but then again a handy built-in feature of Next.js is being lost.
Third, if there's an argument in favour of SPA mode it seems that switching between SSR and client-side only mode should be as flawless as possible for current Next.js users. Thus, using the existing app structure and getInitialProps for data population will help to ease the switching.
I'm not sure how one could leverage fs-based routing with getInitialProps and other lifecycle page methods. Not saying this is impossible, but feels quite hard to me to figure out what's allowed and what's not allowed in this mode.
As of code splitting, you can do that even if when your app has only one Next.js page. See https://github.com/zeit/next.js#dynamic-import and https://github.com/zeit/next.js/tree/canary/examples/with-dynamic-import
I'm not sure how one could leverage fs-based routing with getInitialProps and other lifecycle page methods. Not saying this is impossible, but feels quite hard to me to figure out what's allowed and what's not allowed in this mode.
It is a concern. That's why the suggestion is to match those features to their existing semantics and defaults as much as possible so that developers wouldn't need to adapt a lot:
Link is used for transitioning between routes (including dynamic routes).next/router (as an object, with useRouter or via withRouter HOC).getInitialProps receives the same context object with the same properties as it already does on the client when navigating routes using Link.This list goes on and on, there are many other aspects to consider. So, in order to make it easier to introduce client-side only rendering it is suggested to keep the parity for all current features. And for cases that can't be handled on the client (or just don't make sense) introduce API changes or special notes. The assumption is that there's not going to be lots of these special cases.
Please, let me know if any major roadblock isn't taken into account.
As of code splitting, you can do that even if when your app has only one Next.js page. See https://github.com/zeit/next.js#dynamic-import and https://github.com/zeit/next.js/tree/canary/examples/with-dynamic-import
Thank you for pointing this out. It is certainly possible. Yet again one can't leverage code-splitting based on files in "_pages_" folder, it should be implemented on its own.
What about Next's static export would not work on a smart TV? Going by the proposal, since it was implemented in the latest canary build, you can use either Next.js's APIs or React's APIs to choose exactly when data fetching happens.
getInitialPropsgetStaticPropsgetServerPropsuseEffect (or getDerivedStateFromProps in certain edge-cases)In this sense, it seems like developing for a Smart TV is similar to deploying a dynamic client-rendered web-application to a CDN which is possible today through static export. I spent a few min digging through the Samsung docs but I didn't really know what APIs you were referring to in this issue so I may be off base.
getDerivedStateFromProps -> actually just useEffect in a component is more correct. getDerivedStateFromProps is for edge cases where normal state management doesn't work.
In this sense, it seems like developing for a Smart TV is similar to deploying a dynamic client-rendered web-application to a CDN which is possible today through static export.
@baer, it turns out I didn't realize how exactly next export works. For whatever reason, I supposed that the navigation between pages of an exported app leads to page reloading upon route change. As you all know that isn't the case, thus, an exported app should work fine.
I coined a Smart TV demo app that uses many of the features I previously mentioned (Link, dynamic routing, data fetching, custom __app.js_, etc.) It runs on TV and I can navigate the app keeping the shared state across pages. Dynamic routing is broken though. I'm going to dig into this problem and check if other features work fine. If the problem is going to be resolved, I'll create a PR with an example of using Next.js for Tizen Smart TV app.
Thanks to everyone for the help!
@timneutkens, it is suggested to leave this issue opened until we come up with a sample app.
@grushetsky - I've found that some systems really don't like [] in paths. One of the many examples of this is lint-staged. I have no idea what the _real_ issue is for smart TVs, but that's something worth exploring. Also, before the (awesome) Next.js team rolled out the filesystem-based dynamic routing, I was doing a lot of this by hand. I wrote up a PR and issue with all the gory details here. Hopefully, you'll be able to get things working as they are but, there are ways to do it yourself if you really need it.
@baer, thank you for the insight!
I have a similar request, for a different need. I'm making a static website, building and exporting on content change from my CMS for production.
However I'd like to setup a preview site to reflect dynamic changes without triggering a build on every content change, as I don't need pre-rendering for this environment.
So I would like to just keep using getInitialProps instead of duplicating the code both in useEffect and getInitialProps.
I'm coming from the Vue environment and I think that this feature request is similar to the Nuxt SPA mode (https://nuxtjs.org/guide#single-page-applications-spa-), correct me if I'm wrong
hi @kachkaev,
Thanks a lot for posting that suggestion. That seems like a way to do it for sure.
But doesn't that seem like a pretty big hack, though? I'm new to Next, but if you structure your app like that, don't you lose out on many of the core features of Next? And then you can only use that build for your SPA. You'd have to have another Next app for your web app.
The Nuxt --spa flag linked by @thomasboulongne would be incredible here. In my case, I assumed I could build a webpack bundle with Next for Electron/Cordova/Capacitor.
Looks like https://github.com/zeit/next.js/blob/canary/examples/with-electron/renderer/next.config.js can be adapted to Cordova/Capacitor to get the job done.
it is suggested to leave this issue opened until we come up with a sample app.
Going to close this as it's unlikely someone will come in and PR a full smart tv example. The current auto export example + the new getStaticProps should probably be enough to achieve what you're talking about. No spa mode needed as a Next.js app with 1 page is already an SPA, especially with useEffect you can already client-render only if you want to.
Most helpful comment
Going to close this as it's unlikely someone will come in and PR a full smart tv example. The current auto export example + the new getStaticProps should probably be enough to achieve what you're talking about. No
spamode needed as a Next.js app with 1 page is already an SPA, especially withuseEffectyou can already client-render only if you want to.