NextJS SSR in Capacitor
Asked Answered
P

3

7

we use Next.js with server-side rendering (SSR) and we'd like to wrap our app with Capacitor.js so that we can ship it to both Android and iOS devices. Sadly, this only seems to be possible when using static site generation (SSG) and I cannot find anything on how to even attempt to make SSR work.

A couple of threads seem to hint that this is possible: How to package a hosted web app with Ionic Capacitor (not sure what type of rendering is used here) and https://github.com/MicrosoftDocs/cordova-docs/blob/master/articles/getting-started/create-a-hosted-app.md (this was for Cordova). I have never used Nuxt.js before but some hints that it could be possible with that framework as well here: Using Capacitor 3 with Nuxtjs SSR

Essentially, is it possible to use Capacitor's Webview to display a hosted app instead of having to first build it statically? Could this be something that Capacitor 3 now allows?

Should this be impossible, what would be your recommendation for having a mobile app knowing that we have built our web (and mobile responsive) product in Next.js, with heavy usage of getServerSideProps (i.e. SSR). Any help would be greatly appreciated.

Pend answered 18/11, 2021 at 16:35 Comment(0)
A
0

I am currently investigating the same. Looking to wrap an existing responsive web application based on nextjs using SSR.

in this blog I read in the comments that you can essentially point capacitor to any existing URL (so also your already running website).

I have not tested it though yet. My biggest questions right now would be:

  1. Could we still use native functions (such as push notifications, which is one of the main reasons of bundling it as an app) then? problably would need to integrate the required libs in my existing web app and check if we are running in capacitor environment somehow.
  2. How does Apple handle such cases upon submissions? I have read that they do reject apps that mainly just wrap existing web sites without offering any app-like advantages.
Antakiya answered 3/12, 2021 at 8:19 Comment(5)
Thanks for the reply. For now, and due to time constraints and resources we have gone for a classic [PWA]((web.dev/install-criteria) ) with custom install. It fills the gap for now but does not address the question. However, I got a response here github.com/ionic-team/capacitor/discussions/3487 from Max Lynch saying that it should be possible using the server prop.Pend
To answer your other questions: 1) I believe that if you were to use capacitor plugins on the web, and they are able to correctly detect the platform you are on if on device it would be able to bridge through to the native functionality (at least one of the posts above seemed to hint that this might need some tweaks). For 2) Hard to tell, I have submitted Capacitor wrapped apps before so as long as you don't have something Apple blocks (e.g. payment in-app), I'd say you should be good. I'll report back if I get the time to set up a repo with a basic use case.Pend
Thanks Miguel, I recently did a test run using the server.url config. Works quiet well, at least to get it installed. But there will be some more work needed to make it feel a bit more native. Especially navigation handling is not well by default, e.g. back button on android closes the app instead of navigating back. But that's something that can be worked around for sure... :)Antakiya
That's great to hear. Aside from the navigation issues, what does your app structure look like? Mainly, if not exported from Next, do you just create a plain HTML index.html file for the app to run? For the back button, hopefully this helps: #20374349.Pend
Has this pushed through? looking to run my NextJS with SSR app to be converted to a native mobile app using capacitorCape
L
0

I managed to do it in react and accomplish it in next in react I had to find injected native-bridge.js which is in npm package @capacitor/android/capacitor/src/main/java/com/getcapacitor/Bridge.java
in the function below and after coping output of the below function I had to disable bridgeJS or if you want the whole function

    private JSInjector getJSInjector() {
        try {
            String globalJS = JSExport.getGlobalJS(context, config.isLoggingEnabled(), isDevMode());
            String bridgeJS = "";
//            String bridgeJS = JSExport.getBridgeJS(context); 
            String pluginJS = JSExport.getPluginJS(plugins.values());
            String cordovaJS = JSExport.getCordovaJS(context);
            String cordovaPluginsJS = JSExport.getCordovaPluginJS(context);
            String cordovaPluginsFileJS = JSExport.getCordovaPluginsFileJS(context);
            String localUrlJS = "window.WEBVIEW_SERVER_URL = '" + localUrl + "';";

            return new JSInjector(globalJS, bridgeJS, pluginJS, cordovaJS, cordovaPluginsJS, cordovaPluginsFileJS, localUrlJS);
        } catch (Exception ex) {
            Logger.error("Unable to export Capacitor JS. App will not function!", ex);
        }
        return null;
    }

in my js files then I import it which is hard but works

const script = document.createElement('script')
    script.onload = rendertodom
    script.onerror = rendertodom
    script.src = '/native-bridge.js'
    document.body.append(script)

    function rendertodom () {
    import('./App').then(({default:App})=> {
    ReactDOM.render(
        <App/>,
      document.getElementById('root')
    )
  })
}

the struggling part in next is rendering dynamically where a plugin is needed like the app above or importing native bridge if on native before importing rest of app

I use a function for knowing its android from capacitor which I can't do before native so function is in index

if(isNativ(window)) load capcitor // sudo code from real code above
const isNative = (win) => {
  let _a, _b;
  if (win === null || win === void 0 ? void 0 : win.androidBridge) {
    return true;
  }
  else return !!((_b = (_a = win === null || win === void 0 ? void 0 : win.webkit) === null || _a === void 0 ? void 0 : _a.messageHandlers) === null || _b === void 0 ? void 0 : _b.bridge);
};
Lodgment answered 28/2, 2022 at 6:13 Comment(0)
C
0

No, it isn't possible with Capacitor. You need a backend that runs your Next.js server and your will connect to it. The server can't be bundled into the Capacitor app.

Centreboard answered 10/4, 2023 at 19:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.