Skip to content
This repository has been archived by the owner on Apr 14, 2023. It is now read-only.

NativeScript support #668

Closed
PhilippS93 opened this issue Oct 7, 2019 · 10 comments
Closed

NativeScript support #668

PhilippS93 opened this issue Oct 7, 2019 · 10 comments

Comments

@PhilippS93
Copy link

When using the proposed setup for Apollo Subscription setup in NativeScript (see: here), I get the following error (short extract):

Can't reexport the named export 'doTypesOverlap' from non EcmaScript module (only default export is available)
@ ../node_modules/subscriptions-transport-ws/dist/server.js
@ ../node_modules/subscriptions-transport-ws/dist/index.js
@ ../node_modules/apollo-link-ws/lib/bundle.esm.js
@ ./app/graphql.module.ts
@ ./app/app.module.ngfactory.js
@ ./main.ts

ERROR in ../node_modules/graphql/index.mjs 50:0-122
Can't reexport the named export 'execute' from non EcmaScript module (only default export is available)
@ ../node_modules/subscriptions-transport-ws/dist/server.js
@ ../node_modules/subscriptions-transport-ws/dist/index.js
@ ../node_modules/apollo-link-ws/lib/bundle.esm.js
@ ./app/graphql.module.ts
@ ./app/app.module.ngfactory.js
@ ./main.ts

ERROR in ../node_modules/graphql/index.mjs 59:0-96:42
Can't reexport the named export 'extendSchema' from non EcmaScript module (only default export is available)
@ ../node_modules/subscriptions-transport-ws/dist/server.js
@ ../node_modules/subscriptions-transport-ws/dist/index.js
@ ../node_modules/apollo-link-ws/lib/bundle.esm.js
@ ./app/graphql.module.ts
@ ./app/app.module.ngfactory.js
@ ./main.ts

ERROR in ../node_modules/graphql/index.mjs 59:0-96:42
Can't reexport the named export 'findBreakingChanges' from non EcmaScript module (only default export is available)
@ ../node_modules/subscriptions-transport-ws/dist/server.js
@ ../node_modules/subscriptions-transport-ws/dist/index.js
@ ../node_modules/apollo-link-ws/lib/bundle.esm.js
@ ./app/graphql.module.ts
@ ./app/app.module.ngfactory.js
@ ./main.ts

ERROR in ../node_modules/graphql/index.mjs 59:0-96:42
Can't reexport the named export 'findDangerousChanges' from non EcmaScript module (only default export is available)
@ ../node_modules/subscriptions-transport-ws/dist/server.js
@ ../node_modules/subscriptions-transport-ws/dist/index.js
@ ../node_modules/apollo-link-ws/lib/bundle.esm.js
@ ./app/graphql.module.ts
@ ./app/app.module.ngfactory.js
@ ./main.ts

ERROR in ../node_modules/graphql/index.mjs 59:0-96:42
Can't reexport the named export 'findDeprecatedUsages' from non EcmaScript module (only default export is available)
@ ../node_modules/subscriptions-transport-ws/dist/server.js
@ ../node_modules/subscriptions-transport-ws/dist/index.js
@ ../node_modules/apollo-link-ws/lib/bundle.esm.js
@ ./app/graphql.module.ts
@ ./app/app.module.ngfactory.js
@ ./main.ts

ERROR in ../node_modules/graphql/index.mjs 57:0-91
Can't reexport the named export 'formatError' from non EcmaScript module (only default export is available)
@ ../node_modules/subscriptions-transport-ws/dist/server.js
@ ../node_modules/subscriptions-transport-ws/dist/index.js
@ ../node_modules/apollo-link-ws/lib/bundle.esm.js
@ ./app/graphql.module.ts
@ ./app/app.module.ngfactory.js

This is related to: this and this.

Are there any plans for future implementation of NativeScript support?

Thank you,
Philipp

@tafelnl
Copy link

tafelnl commented Nov 20, 2019

Did you ever happen to find a workaround or a fix for this?

@PhilippS93
Copy link
Author

Did you ever happen to find a workaround or a fix for this?

As a workaround, we are currently using Firebase Cloud Messaging to update our users.

@vytautas-pranskunas-
Copy link

UP

@Marc-Cilliers
Copy link

Having this same problem after updating to NativeScript 6.5.0

@michaelyuen
Copy link

Not knowing NativeScript, this may or may not be related. The errors originally reported are consistent with those I encountered, and the issue ended up being my webpack config. See further detail: apollographql/apollo-link#1274 (comment)

@dudipsh
Copy link

dudipsh commented Jun 27, 2020

UP

@PhilippS93
Copy link
Author

Not knowing NativeScript, this may or may not be related. The errors originally reported are consistent with those I encountered, and the issue ended up being my webpack config. See further detail: apollographql/apollo-link#1274 (comment)

This seems to work, thanks!

@dudipsh
Copy link

dudipsh commented Mar 20, 2021

@PhilippS93, @vytautas-pranskunas- @tafelnl

This is the solution that work for me!

1: install "nativescript-websockets": "^1.5.6", and "subscriptions-transport-ws": "^0.9.18",
2: add support to webpack

plugins: [
      // Define useful constants like TNS_WEBPACK
      new webpack.NormalModuleReplacementPlugin(
          /^ws$/,
          'nativescript-websockets'
      ),

3: require ws in 'main.ts'
const WS = require('nativescript-websockets'); var WebSocket = require('nativescript-websockets');

4: creare graphql.module.ts

import {NgModule, NO_ERRORS_SCHEMA} from '@angular/core';
import {NativeScriptHttpClientModule, NativeScriptModule} from "@nativescript/angular";

import {HTTP_INTERCEPTORS, HttpClient, HttpClientModule, HttpHeaders} from '@angular/common/http';

// @ts-ignore
import {Apollo, APOLLO_OPTIONS} from 'apollo-angular';
import {Subject} from 'rxjs';
import {WebSocketLink} from "@apollo/client/link/ws";

import {RouterModule} from "@angular/router";
import {tap} from "rxjs/internal/operators";

import {getMainDefinition} from '@apollo/client/utilities';

const uri = environment.graphqlUrl + '/graphql';
const socketUrl = environment.graphqlSocketUrl


const errorSubject = new Subject<any>();
const getErrorSubject = () => errorSubject.asObservable();
import {HttpLink} from 'apollo-angular/http';

import {ApolloLink, InMemoryCache, split} from '@apollo/client/core';
import {onError} from "@apollo/client/link/error";
import {RetryLink} from "@apollo/client/link/retry";
import {environment} from "../environments/environment";
import {UserService} from "./shared/services/user.service";
import {setContext} from "@apollo/client/link/context";
import {SubscriptionService} from "./core/subscription.service";


const HTTP_STATUS = {

    NO_CONNECTION: 0,
    INTERNAL_SERVER_ERROR: 500,
    SERVICE_UNAVAILABLE: 503,
    GATEWAY_TIMEOUT: 504,
    BAD_GATEWAY: 502,
    UNAUTHORIZED: 401,
    FORBIDDEN: 403,
    OK: 200,
    CREATED: 201,
};

@NgModule({
    imports: [
        RouterModule,
        NativeScriptHttpClientModule,
    ],
    providers: [],
    schemas: [
        NO_ERRORS_SCHEMA
    ]

})


export class GraphQLModule {
    constructor(
        apollo: Apollo,
        httpLink: HttpLink,
        userService: UserService,
        subscriptionService: SubscriptionService,
    ) {
        const http = httpLink.create({
            uri
        });
        const error = onError(({networkError, graphQLErrors}) => {
            console.log('ERROR@@@@')
            console.log(networkError)
            console.log(graphQLErrors)
        })

        const wsClient = subscriptionService.getWSClient(socketUrl, {
            // uri: socketUrl,
            lazy: true,
            reconnect: true,
            options: {
                reconnect: true,
                connectionParams: {
                    authorization: userService.getAuthToken(),
                },
            },
            connectionParams: async () => {
                return {
                    authorization: await userService.getTokenPromise()
                };
            },
            // webSocketImpl: WebSocket,
            reconnectionAttempts: 99,
        }, WebSocket) as any;

        // wsClient.subscriptionClient.use([subscriptionMiddleware])

        const retryLink = new RetryLink({
            delay: {
                initial: 1000,
                max: Infinity,
            },
            attempts: {
                max: 10,
                retryIf: (error) => {
                    console.log(error)
                    return error.status === HTTP_STATUS.SERVICE_UNAVAILABLE ||
                        error.status === HTTP_STATUS.GATEWAY_TIMEOUT
                }
            },
        });

        const authLink = setContext((_, {headers}) => {
            // get the authentication token from local storage if it exists
            const token = userService.getAuthToken()
            // return the headers to the context so httpLink can read them
            return {
                headers: {
                    ...headers,
                    authorization: token || '',
                }
            }
        });

        const link = split(
            ({query}) => {
                const {kind, operation}: any = getMainDefinition(query);
                return kind === 'OperationDefinition' && operation === 'subscription';
            },
            wsClient,
            authLink.concat(http)
        );
        getErrorSubject().subscribe((data) => {
            console.log(data)

        }, (error) => console.log(error));

        apollo.create({
            link: ApolloLink.from([retryLink, link]),
            cache: new InMemoryCache({
                addTypename: false,
                // dataIdFromObject: (object: any) => object._id
            }),
            // defaultOptions: {
            //     watchQuery: {
            //         errorPolicy: 'all'
            //     }
            // }
        });


    }
}

5: create subscription.service.ts

import {Injectable} from '@angular/core';
import {SubscriptionClient} from 'subscriptions-transport-ws';
import {BehaviorSubject, Subject} from 'rxjs';
import {SocketStatus} from "./socket-status.enum";
import {SocketStatusCodeEnum} from "./socket-status";
import {WebSocketLink} from "@apollo/client/link/ws";

// DOT REMOVE THIS!!! //
require('nativescript-websockets');
var WebSocket = require('nativescript-websockets');
// DOT REMOVE THIS!!! //


@Injectable()
export class SubscriptionService {
    private wsc: SubscriptionClient;
    public wsl: WebSocketLink;
    ws: WebSocket
    status$: BehaviorSubject<SocketStatus> = new BehaviorSubject<SocketStatus>(null);
    status;
    constructor() {

    }

    public get getStatus() {
        return this.status$.asObservable();
    }

    public getWSClient(uri, options, ws) {
        if (this.wsc) {
            return this.wsc;
        }
        if (uri && !this.wsc) {
            this.ws = ws;
            this.wsc = new SubscriptionClient(uri, options, ws);
        }
        if (this.wsc) {
            this.bindEvent();
        }
        return this.wsc;
    }

    public close() {
        if (this.wsc) {
           this.wsc.close();
        }
    }

    private bindEvent() {
        const status = new SocketStatus()

        this.wsc.onConnecting(() => {
            status.name = 'Online';
            status.statusCode = SocketStatusCodeEnum.ON_CONNECTING;
            console.log(status)
            this.status$.next(status);
        });
        this.wsc.onConnected(() => {
            status.name = 'Online';
            status.statusCode = SocketStatusCodeEnum.ON_CONNECTED;
            this.status = status;
            console.log(status)

            this.status$.next(status);
        });
        this.wsc.onReconnecting(() => {
            status.name = 'Reconnecting';
            status.statusCode = SocketStatusCodeEnum.ON_RECONNECTING;
            this.status = status;
            console.log(status)

            this.status$.next(status);
        });
        this.wsc.onReconnected(() => {
            status.name = 'OnLine';
            status.statusCode = SocketStatusCodeEnum.ON_RECONNECTED;
            this.status = status;
            console.log(status)

            this.status$.next(status);
        });
        this.wsc.onDisconnected(() => {
            status.name = 'Disconnected';
            status.statusCode = SocketStatusCodeEnum.ON_DISCONNECTED;
            this.status = status;
            console.log(status)

            this.status$.next(status);
        });
        this.wsc.onError(() => {
            status.name = 'Error';
            status.statusCode = SocketStatusCodeEnum.ON_ERROR;
            this.status = status;
            console.log(status)

            this.status$.next(status);
        });
    }
}

6: finally add GraphQLModule, to app.module

use subscription

setOnMessageEvents$(token) {
      this.graphQLService.onMessageEvents$(token).subscribe((res) => {
          if (res) {
              console.log(res)
          }
        })
    }

@t1amat9409
Copy link

@dudipsh thanks for the solution above, seems to be working for me as well. Just one Q, does your cache works? does it write to AppSettings.set[DataType]?

@dudipsh
Copy link

dudipsh commented May 20, 2021

@dudipsh thanks for the solution above, seems to be working for me as well. Just one Q, does your cache works? does it write to AppSettings.set[DataType]?

yes, you need to add this

 cache: new InMemoryCache({
            resultCaching: true,
            addTypename: false,
            dataIdFromObject: (object: any) => object._id,
            typePolicies: {
                Query: {
                    fields: {
                        files: {
                            merge: true,
                        }
                    }
                },

                Task: {
                  keyFields: ["_id"],   <= this one
                },
 .....

@glasser glasser closed this as completed Mar 3, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants