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

window is not defined #186

Open
xxyyzz2050 opened this issue Dec 23, 2018 · 32 comments
Open

window is not defined #186

xxyyzz2050 opened this issue Dec 23, 2018 · 32 comments

Comments

@xxyyzz2050
Copy link

xxyyzz2050 commented Dec 23, 2018

I'm using babel transpiler

function StitchAuthImpl(requestClient, browserAuthRoutes, authStorage, appInfo, jsdomWindow) {
        if (jsdomWindow === void 0) { jsdomWindow = window; }
        ...
}

//error: window is not defined

@jsflax
Copy link
Contributor

jsflax commented Dec 28, 2018

Hi @xxyyzz2050 ,

Could you give us a bit more information? What step in the transpiration process are you at? What is the full stack trace?

Thanks.

@xxyyzz2050
Copy link
Author

ok, I use Nuxt framework & latest version of Node.js and npm

@maredudd
Copy link

maredudd commented Jan 2, 2019

@jsflax I imagine that this might be due to using the SDK for SSR. I'm having the same issue with Next.js.

If fails on this line: client.auth.loginWithCredential(new AnonymousCredential()):

ReferenceError: window is not defined
    at new StitchAuthImpl (/xxx/node_modules/mongodb-stitch-browser-core/dist/cjs/core/auth/internal/StitchAuthImpl.js:28:39)
    at new StitchAppClientImpl (/xxx/node_modules/mongodb-stitch-browser-core/dist/cjs/core/internal/StitchAppClientImpl.js:15:21)
    at Function.Stitch.initializeAppClient (/xxx/node_modules/mongodb-stitch-browser-core/dist/cjs/core/Stitch.js:71:22)

This would be expected since window is undefined on the server side. I tried using the server SDK to retrieve the data on the server side but that fails since fs doesn't exist This results in the following code:

import {
  Stitch,
  RemoteMongoClient,
  AnonymousCredential
} from 'mongodb-stitch-server-sdk'

showing an error due to the missing dependency:


* fs in ./node_modules/fs-extra/lib/index.js, ./node_modules/fs-extra/lib/empty/index.js and 2 others

Are the SDKs expected to support SSR? Is there a workaround for this or is Stitch not an option with SSR?

Thanks.

@agstover
Copy link

agstover commented Jan 6, 2019

I've been trying to figure out how Stitch can be used with SSR as well, particularly NextJS. Would one have to instantiate both a Stitch-Server SDK instance and a Stitch-Browser SDK instance, use the server instance if !window and use the browser instance if there is?

This also presents an issue with setting up sessions so that initial requests for logged in users can be server rendered. As an example of an alternative Auth flow, the official NextJS + Firebase Auth example works like this: 1) Login occurs client-side, 2) Request an Auth Token from Firebase client-side, 3) Pass Auth token to /login.js route, 4) Use Firebase to decode token, 5) Set HTTP Only cookie session with user info. Every subsequent request is immediately authenticated.

I'm not sure how this can be done with Stitch. Auth Token gets stored in local storage, but is there a way to get it? And if you could deliver it to the server, could you use it with Stitch-Server SDK to authenticate user server side and create a session?

@Ruegen
Copy link

Ruegen commented Jan 10, 2019

I'm getting the same issue with Next.js
client.auth.loginWithCredential(new AnonymousCredential())
I'm guessing it needs access to the window object which won't be available since it's pre-rendered?

@Ruegen
Copy link

Ruegen commented Jan 10, 2019

I've been trying to figure out how Stitch can be used with SSR as well, particularly NextJS. Would one have to instantiate both a Stitch-Server SDK instance and a Stitch-Browser SDK instance, use the server instance if !window and use the browser instance if there is?

This also presents an issue with setting up sessions so that initial requests for logged in users can be server rendered. As an example of an alternative Auth flow, the official NextJS + Firebase Auth example works like this: 1) Login occurs client-side, 2) Request an Auth Token from Firebase client-side, 3) Pass Auth token to /login.js route, 4) Use Firebase to decode token, 5) Set HTTP Only cookie session with user info. Every subsequent request is immediately authenticated.

I'm not sure how this can be done with Stitch. Auth Token gets stored in local storage, but is there a way to get it? And if you could deliver it to the server, could you use it with Stitch-Server SDK to authenticate user server side and create a session?

I used a stateful component that waits until the mount lifecycle (I'm using react hooks, useEffect) which only loads once the component mounts. This solves the problem for me in Next.js.. won't help with anything server side rendering...

@jsflax
Copy link
Contributor

jsflax commented Jan 10, 2019

In the future, we hope to have a universal JS SDK. However, in the interim, @agstover is right. A solution could be to make your own isomorphic multiplexer file, i.e., an isomorphic-stitch.js file that does if node return nodesdk else browser sdk.

@xxyyzz2050
Copy link
Author

Thank you @maredudd , yes the issue is due to SSR mode, thanks to you I now knew that there is a server version for SSR and I will try it

@jsflax good idea

@phillipmalboeuf
Copy link

+1 for SSR support

@Ruegen
Copy link

Ruegen commented Apr 1, 2019

Trying to use Next.js with Stitch requires SSR support. Even one of the fetch dependancies isn't written for SSR so an alternative to whatwg-fetch would be better?

@adamchel
Copy link
Contributor

adamchel commented Apr 2, 2019

Hi @phillipmalboeuf and @Ruegen , have you tried using mongodb-stitch-server-sdk? It's almost the same as the browser SDK, but it uses node-fetch instead of whatwg-fetch, but excludes some redirect auth functionality.

Let us know if that would be sufficient. Otherwise, we can look into offering a more general solution.

The problem with bundling a polymorphic fetch library in the browser SDK is the fact that some JS frameworks (such as NativeScript) will not let you bundle JavaScript libraries that contain NodeJS-based dependencies. See #207

@phillipmalboeuf
Copy link

phillipmalboeuf commented Apr 2, 2019

Thanks @adamchel, using mongodb-stitch-server-sdk is not the solution, it's difficult to have to juggle between two librairies. Even having something like this gives me a ReferenceError: self is not defined error:

export const client = process.env.production
  ? require('mongodb-stitch-server-core').Stitch.initializeDefaultAppClient('***')
  : require('mongodb-stitch-browser-core').Stitch.initializeDefaultAppClient('***')
export const db = client.getServiceClient(process.env.production
  ? require('mongodb-stitch-server-services-mongodb-remote').RemoteMongoClient.factory
  : require('mongodb-stitch-browser-services-mongodb-remote').RemoteMongoClient.factory, '***').db('***')

The current system setup isn't SSR capable, and it's not just a matter of the fetch library. I believe the credentials storage method would need to be polymorphic as well.
I'll see if I can open a PR sometime this week and do deeper dive:)

Update
Would axios be fine as a polymorphic fetch library? NativeScript seems fine with it: https://www.nativescript.org/blog/make-http-requests-to-remote-web-services-in-a-nativescript-vue-app

@Ruegen
Copy link

Ruegen commented Apr 2, 2019

Hi @adamchel, yes I’ve tried it however like Phillip I got the same errors. I got around it by only loading the package in on the client side - which involves a fair bit of trickery (not pretty), the server side can’t use the client side and vice versa. It would be better to have it load for SSR which would resolve a great deal of issues.

@phillipmalboeuf I believe the client side uses localstorage to save the credentials automatically.

@adamchel
Copy link
Contributor

adamchel commented Apr 2, 2019

Thanks for the feedback everyone!

So, it's hard for us to provide truly isomorphic networking and storage because new javascript libraries with new requirements and nuances pop up all the time, and it's difficult for us to keep up. In the past we actually switched to an isomorphic fetch library to support more JS libraries, but then it caused problems with other JS libraries. This is just the state of the JS ecosystem 🤷‍♂️. That's why we've generally opted to provide the most basic storage and networking capabilities.

If you'd like to go on a deeper dive, it might be useful for you to know that we have abstracted the storage and network layer of the SDK into simple Transport and Storage protocols.

See:

If you know the limitations/requirements of the framework you're working with, you can implement a Transport or Storage that works for your environment, and specify it when configuring your Stitch client.

import { Stitch, StitchAppClientConfiguration } from "mongodb-stitch-browser-sdk";

// these currently do not exist
import { IsomorphicNetworkTransport } from "my-stitch-isomorphic-network-transport";
import { IsomorphicStorage } from "my-stitch-isomorphic-storage";

let client = Stitch.initializeAppClient(
    "your-client-app-id", 
    new StitchAppClientConfiguration.Builder()
        .withTransport(new IsomorphicNetworkTransport())
        .withStorage(new IsomorphicStorage())
        .build()
);

You can look at our existing Storage and Transport implementations as a reference, and we'd be happy to answer any questions you may have or any issues that come up:

image

image

Although this is something we'd personally like to work more on, we are juggling many other priorities. Building your own Transport and Storage (and opening a PR if you'd like) will probably be the fastest way to get the SDK working in some of these third party libraries where isomorphic libraries are necessary.

If you'd like to have a say in Stitch's product roadmap and the features that we should work on, please add a new issue or vote on existing issues at https://mongodb.canny.io/mongodb-stitch !

@phillipmalboeuf
Copy link

Oh interesting @adamchel, didn't realize the withTransport/withStorage configurations existed! Will take a look and keep you updated.

@phillipmalboeuf
Copy link

@adamchel The problem is that even importing the packages mongodb-stitch-server-core or mongodb-stitch-browser-core causes problems with SSR. And without them, we can't call the initializeDefaultAppClient function no matter the Storage or Transport implementation.

With that said I've tried building a client still with new CoreStitchAppClient(), but it looks like there is no implementation of StitchAuthRequestClient in the core package, so hit a wall with that and not sure how to proceed:(

@phillipmalboeuf
Copy link

phillipmalboeuf commented Apr 4, 2019

Is there a way to use StitchAppClientConfiguration without having to use mongodb-stitch-server-core or mongodb-stitch-browser-core?

@adamchel
Copy link
Contributor

adamchel commented Apr 4, 2019

What are the SSR issues when just using mongodb-stitch-server-core or mongodb-stitch-browser-core? Is it the dependencies?

@phillipmalboeuf
Copy link

phillipmalboeuf commented Apr 4, 2019

@adamchel the dependencies are a good place to start.
So I wrote this, might be the best way to test SSR compability (a .tsx/.jsx file):

import { Stitch } from 'mongodb-stitch-browser-sdk'
import React from 'react'
import ReactDOM from 'react-dom/server'

const client = Stitch.initializeDefaultAppClient('****')

const html = ReactDOM.renderToString(<div>
  {client.auth.isLoggedIn.toString()}
</div>)

console.log(html)

Running this in node returns a ReferenceError: self is not defined error from the whatwg-fetch package but I suspect it might not be the only culprit here.

@phillipmalboeuf
Copy link

Hey @adamchel, @Ruegen, @maredudd, @agstover, so I got to a weird solution for this. It needs a couple of steps (note that I'm writing TypeScript and bundling with Parcel):

First, change all your references to the stitch sdk to 'mongodb-stitch-server-sdk'. Stick with me here:p

Second, in your package.json add an alias to point the sdk back to the browser:

{...,
  "alias": {
    "mongodb-stitch-server-sdk": "mongodb-stitch-browser-sdk"
  },
  {
    ...,
    "mongodb-stitch-browser-sdk": "^4.3.2",
    "mongodb-stitch-server-sdk": "^4.3.2",
    ...
  },
  ...
}

Third, if you're on TS add to your tsconfig.json an alias path:

{
  "compilerOptions": {
    ...,
    "baseUrl": ".",
    "paths": {
      "mongodb-stitch-server-sdk": ["node_modules/mongodb-stitch-browser-sdk"]
    }
  }
}

And VOILÀ, bundling this for the browser and bundling this for Node and running those works just fine!
This works because unlike bundling for the browser where the packages are all merged in, Node keeps the packages in a node_modules folder, and retrieves them from there. So Node looks for mongodb-stitch-server-sdk while the browser gets the aliased mongodb-stitch-browser-sdk packaged in!

I haven't tried this with Next.js but I imagine it might work, let me know.

@phillipmalboeuf
Copy link

And for those on next.js, you can do it the same way but you'll need to add a webpack alias resolve to your next.config.js file, like so! :

module.exports = {
  webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
    if (!isServer) { config.resolve.alias = {
      ...config.resolve.alias,
      'mongodb-stitch-server-sdk': 'mongodb-stitch-browser-sdk'
    } }
    return config;
  }
};

Let me know!

@adamchel
Copy link
Contributor

Hey @phillipmalboeuf thanks for taking a look and finding a workaround for this! I'm sure this will be very helpful for a lot of users.

We still would like to eventually have a more clean and robust solution for SSR, so I'll leave this issue open until we get a chance to investigate this further.

@gierloff
Copy link

We are using VueJS/NuxtJS for our project. We have a rest api with MongoDB/Mongoose, but we would really like to skip the server part and just use Nuxt with MongoDB Stitch. But we are getting the same error with “self” not defined.
“Couldn’t you just use Firebase?” - rather not, because Firebase has annoying data validation and doesn’t accept data types like undefined or class objects. MongoDB stitch does which is really awesome!
So we are hoping for a solution to the SSR incompatibility!

@Mattertorian
Copy link

I can verify that the workaround @phillipmalboeuf discovered also work with Nuxt js with the following small modification. In the nuxt.config.js file:
build: { extend(config, ctx) { if (!ctx.isServer) { config.resolve.alias = { ...config.resolve.alias, 'mongodb-stitch-server-sdk': 'mongodb-stitch-browser-sdk' } } return config; } }
Thus the only difference is that the webpack extension is different from Next js.
You will still need to replace all import of 'mongodb-stitch-browser-sdk' with 'mongodb-stitch-server-sdk' as well as add the alias in package.json.

Looking forward to the day where the SDK supports SSR.

@pnadon
Copy link

pnadon commented May 19, 2019

I can verify that the workaround @phillipmalboeuf discovered also work with Nuxt js with the following small modification. In the nuxt.config.js file:
build: { extend(config, ctx) { if (!ctx.isServer) { config.resolve.alias = { ...config.resolve.alias, 'mongodb-stitch-server-sdk': 'mongodb-stitch-browser-sdk' } } return config; } }
Thus the only difference is that the webpack extension is different from Next js.
You will still need to replace all import of 'mongodb-stitch-browser-sdk' with 'mongodb-stitch-server-sdk' as well as add the alias in package.json.

Looking forward to the day where the SDK supports SSR.

@Mattertorian I'm curious to see how integrating Stitch into your NuxtJS app worked out for you. I'm also looking to use Stitch with NuxtJS and the Google maps API, so I can send directions to the serve and it can return relevant information from the database.

@neonguru
Copy link

neonguru commented Jun 6, 2019

I didn't read this whole thread, but I have stitch working with SSR (angular universal), by switching the following package dependencies:

"mongodb-stitch-browser-sdk": "^4.3.2",

To:

"mongodb-stitch-browser-core": "~4.2.0",
"mongodb-stitch-browser-sdk": "~4.2.0",
"mongodb-stitch-browser-services-mongodb-remote": "~4.2.0",
"mongodb-stitch-core-sdk": "~4.2.0",
"mongodb-stitch-core-services-mongodb-remote": "~4.2.0",

4.4.0 still has the problem.
Angular Universal uses the same source on client and server, but I filter out outside calls like stitch on the server, and defer them till it gets to the client.
The problem with the newer versions appears to be the that stitch devs added a dependency:

"whatwg-fetch": "^3.0.0"

to mongodb-stitch-browser-core. If they can get by with the ^2.0.4 version, then they can circumvent that libraries improper access to the self var, when just loading the library.

For a fetch issue reference see: JakeChampion/fetch#657

@api-pushstart
Copy link

I am trying to do this with next.js . Where should I initialize the stitch app? Currently, I am getting error -

default app can only be set once; currently set to 'my app id'

@ivanjeremic
Copy link

ivanjeremic commented May 16, 2020

I think the way stitch currently works needs to be changed, It needs to be 100% API and no SDK, So Login/Registration and so on needs to have a REST endpoints out of the box, (If GraphQL activated Mutations out of the box for Login, Register etc...)

@daveteu
Copy link

daveteu commented May 30, 2020

I am trying to do this with next.js . Where should I initialize the stitch app? Currently, I am getting error -

default app can only be set once; currently set to 'my app id'

Need to understand if you use any of the build in authentication methods in Stitch, you can conclude it's easier to do it client side, and load the sdk using nextjs dynamic loading. Stitch maintains the session in order to provide you with all the authenticated goodies like customised access to the functions and attached clusters.

If you really need SSR option, the easiest way for you is to do custom authentication, and send to Stitch for custom JWT authentication. Don't waste development time trying for workarounds.

Stitch is serverless, I ditched SSR to go full serverless. Response time for Client > Stitch > Atlas > Stitch > Client is much faster than Client > NodeJs > Stitch > Atlas > Stitch > NodeJS > Client.

@ivanjeremic
Copy link

I have not tested it yet but hitting the Stitch Client API directly should solve many problems in Nextjs, https://github.com/mongodb/stitch-specifications/blob/master/source/sdks/sdks.rst#userpasswordauthproviderclient.

We could create Nextjs API routes in the /api folder, for example, nextapp.com/api/login

In this route, we send a request to https://stitch.mongodb.com/api/client/v2.0/app/<client_app_id>/auth/providers/<provider_name>/login

the response will be access_token, refresh_token, user_id, device_id that we can handle then, has anyone an idea what the best method would be at this point to store or handle it?

@mattjennings
Copy link

@ivanjeremic I've been looking everywhere for all of the auth API endpoints, thank you! These should be in the official documentation.

As for where to store it, I've been storing them in cookies. I store the user data, access_token and expiry date in one cookie, and the refresh_token in an http-only cookie. Then, I setup a /refresh-token endpoint that my client hits whenever it expires to get the new access_token (and updates the cookie).

You can refresh the token by sending a post request to https://stitch.mongodb.com/api/client/v2.0/auth/session with an Authorization: "Bearer <refresh token>" header.

@ivanjeremic
Copy link

ivanjeremic commented Jun 8, 2020

@ivanjeremic I've been looking everywhere for all of the auth API endpoints, thank you! These should be in the official documentation.

As for where to store it, I've been storing them in cookies. I store the user data, access_token and expiry date in one cookie, and the refresh_token in an http-only cookie. Then, I setup a /refresh-token endpoint that my client hits whenever it expires to get the new access_token (and updates the cookie).

You can refresh the token by sending a post request to https://stitch.mongodb.com/api/client/v2.0/auth/session with an Authorization: "Bearer <refresh token>" header.

The documentation is really horrible in Stitch, no idea how they want to compete with Strapi or Hasura with no community chat & bad documentation, if after rebranding to Realm nothing gets better I don't see it becoming a thing. All they have is a Forum where you need the approval of your posts, they need a chat on Discord or Slack.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests