nativescript-angular
nativescript-angular copied to clipboard
"Error calling module function" with WebSocketLink (apollo-link-ws)
https://github.com/darkbasic/nativescript-repro2/blob/master/app/app.module.ts
const subscriptionLink = new WebSocketLink({
uri: 'ws://localhost:3000/subscriptions',
options: {
reconnect: true,
},
webSocketImpl: SocketIO,
});

Full Error: https://paste.ubuntu.com/p/NrffmYWRDJ/
Removing the previous snippet of code fixes the error.
I think it could be related to https://github.com/NativeScript/nativescript-angular/issues/1284
Hi @darkbasic,
The apollo-link-ws plugin seems not to be supported in NativeScript due to some DOM related dependencies. For using WebSocket's in NativeScript, you can use nativescript-websockets plugin.
Hi @tsonevn
const subscriptionLink = new WebSocketLink({
uri: 'ws://localhost:3000/subscriptions',
options: {
reconnect: true,
},
webSocketImpl: SocketIO,
});
As you can see from the previous code snippet I'm using SocketIO as webSocketImpl.
I also tried with nativescript-websockets without luck.
I cannot use plain nativescript-websockets (I still need to pass through WebSocketLink) because the websocket will be used for Graphql subscriptions.
export * from './server'; is the culprit:
https://github.com/apollographql/subscriptions-transport-ws/blob/master/src/index.ts
Even if we don't use nor even import SubscriptionServer, this is enough to trigger the error.
Commenting out export * from './server'; from subscriptions-transport-ws is enough to fix the issue, but this is not a solution I can pursue with the upstream, because they need to export it for node.js users.
If they'll accept such a PR I could export ony the client in a different namespace like subscriptions-transport-ws/client, but this is a workaround. Why does Nativescript trigger errors for a class which I didn't even import?
Not directly an angular issue but more of an apollo-link-ws issue. At any rate, this can be worked around using webpack's NormalModuleReplacementPlugin to swap in nativescript-websockets for /^ws$/. Not perfect, but it beats hacking apart a copy of apollo-link-ws.
@darkbasic
Thanks for sharing. One question: which websocket implementation did you end up using? SocketIO, nativescript or the default?
HI recently I have the same probleme, Im trying to implement, realtime with apollo client using angular, and at configure the subscriptions, getting ERROR, there is solution to this problem. I,m lost :(, how alternative i try to use https://market.nativescript.org/plugins/nativescript-subscriptions-transport-ws, but i didnt had success.
@Richard095 Hey, did you found a solution ?
@Richard095 Hey, did you found a solution ?
Hi, No, by time issues, i decided to change to SocketIO,It was a good option on Real-Time.
This seems to be the only way;)
Apparently yes, I had that problem a long time ago, however I think SocketIO is also going well. Only in this way was I able to continue with my project.
@Richard095, @darkbasic, @NickIliev Half a year later ... It works for me!!
webpack.config.js
plugins: [
// Define useful constants like TNS_WEBPACK
new webpack.NormalModuleReplacementPlugin(
/^ws$/,
'nativescript-websockets'
),
main.ts
const WS = require('nativescript-websockets');
var WebSocket = require('nativescript-websockets');
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, ApolloModule} 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 = 'http://192.168.1.21:3000/graphql';
const GRAPHQL_ENDPOINT = 'ws://192.168.1.21:3000/graphql';
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";
const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiZW1haWwiOiJkdWRpcHNoQGdtYWlsLmNvbSIsInZlcmlmaWVkIjp0cnVlLCJyb2xlcyI6W3siaWQiOjEsIm5hbWUiOiJERUZBVUxUX1JPTEVfQURNSU4iLCJkZXNjcmlwdGlvbiI6bnVsbCwicmVhZCI6WyIyMTQ3NDE4MDc1IiwiOCJdLCJ1cGRhdGUiOlsiMjE0NzQ4MzYwMSIsIjgiXSwiZGVzdHJveSI6WyIyMTQ3NDE4MDc1IiwiOCJdLCJyZWFkT3RoZXIiOlsiMjE0NzQ4MzYwMSIsIjgiXSwidXBkYXRlT3RoZXIiOlsiMjE0NzQxODA3NSIsIjgiXSwiZGVzdHJveU90aGVyIjpbIjIxNDc0MTgwNzUiLCI4Il0sImFwcGx5T25PdGhlcnMiOmZhbHNlLCJyb2xlTGV2ZWwiOjR9XSwibGVnYWxOYW1lIjoiRHVkaSBQYXJ0dXNoIiwiYWNjb3VudElkIjoxLCJhY2Nlc3NMZXZlbCI6NCwiYnVja2V0TmFtZSI6Ii90aW1lLXRhbGstYnVja2V0cy1jb21wYW55LXRlc3Rjb21wMSIsImVtcGxveWVlQ2hhdElkIjoiNjAzMjIxY2JkZWE5MjM4OGY5OTFiODI4IiwiY2hhdEFwcElkIjoiNjAzMjIxY2JkZWE5MjM4OGY5OTFiODI1IiwiY2hhdEJvdElkIjoiNjAzMjIxY2JkZWE5MjM4OGY5OTFiODI2IiwibXlDaGFubmVsSWQiOiI2MDMyMjFjY2RlYTkyMzg4Zjk5MWI4MmMiLCJpYXQiOjE2MTM5MDQ2NTIsImV4cCI6MTYxNDUwOTQ1Mn0.ISt0akAnQn6Adjd-nYXHcyapRT7zAwkcBIvz3s31gGs";
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,
) {
const http = httpLink.create({
uri
});
const error = onError(({networkError, graphQLErrors}) => {
console.log('ERROR@@@@')
console.log(networkError)
console.log(graphQLErrors)
})
const wsClient = new WebSocketLink({
uri: 'ws://192.168.1.21:3000/graphql',
options: {
reconnect: true,
connectionParams: {
authorization: token,
},
},
connectionParams: async () => {
return {
authorization: token
};
},
webSocketImpl: WebSocket,
reconnectionAttempts: 99,
});
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 auth = new ApolloLink((operation, forward) => {
operation.setContext({
headers: new HttpHeaders().set('authorization', `${token}`),
});
return forward(operation);
});
const link = split(
({query}) => {
const {kind, operation}: any = getMainDefinition(query);
return kind === 'OperationDefinition' && operation === 'subscription';
},
wsClient,
auth.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'
}
}
});
}
}
`
@Richard095, @darkbasic, @NickIliev Half a year later ... It works for me!!
main.tsconst WS = require('nativescript-websockets'); var WebSocket = require('nativescript-websockets');
graphql.module.tsimport {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, ApolloModule} 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 = 'http://192.168.1.21:3000/graphql'; const GRAPHQL_ENDPOINT = 'ws://192.168.1.21:3000/graphql'; 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"; const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiZW1haWwiOiJkdWRpcHNoQGdtYWlsLmNvbSIsInZlcmlmaWVkIjp0cnVlLCJyb2xlcyI6W3siaWQiOjEsIm5hbWUiOiJERUZBVUxUX1JPTEVfQURNSU4iLCJkZXNjcmlwdGlvbiI6bnVsbCwicmVhZCI6WyIyMTQ3NDE4MDc1IiwiOCJdLCJ1cGRhdGUiOlsiMjE0NzQ4MzYwMSIsIjgiXSwiZGVzdHJveSI6WyIyMTQ3NDE4MDc1IiwiOCJdLCJyZWFkT3RoZXIiOlsiMjE0NzQ4MzYwMSIsIjgiXSwidXBkYXRlT3RoZXIiOlsiMjE0NzQxODA3NSIsIjgiXSwiZGVzdHJveU90aGVyIjpbIjIxNDc0MTgwNzUiLCI4Il0sImFwcGx5T25PdGhlcnMiOmZhbHNlLCJyb2xlTGV2ZWwiOjR9XSwibGVnYWxOYW1lIjoiRHVkaSBQYXJ0dXNoIiwiYWNjb3VudElkIjoxLCJhY2Nlc3NMZXZlbCI6NCwiYnVja2V0TmFtZSI6Ii90aW1lLXRhbGstYnVja2V0cy1jb21wYW55LXRlc3Rjb21wMSIsImVtcGxveWVlQ2hhdElkIjoiNjAzMjIxY2JkZWE5MjM4OGY5OTFiODI4IiwiY2hhdEFwcElkIjoiNjAzMjIxY2JkZWE5MjM4OGY5OTFiODI1IiwiY2hhdEJvdElkIjoiNjAzMjIxY2JkZWE5MjM4OGY5OTFiODI2IiwibXlDaGFubmVsSWQiOiI2MDMyMjFjY2RlYTkyMzg4Zjk5MWI4MmMiLCJpYXQiOjE2MTM5MDQ2NTIsImV4cCI6MTYxNDUwOTQ1Mn0.ISt0akAnQn6Adjd-nYXHcyapRT7zAwkcBIvz3s31gGs"; 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, ) { const http = httpLink.create({ uri }); const error = onError(({networkError, graphQLErrors}) => { console.log('ERROR@@@@') console.log(networkError) console.log(graphQLErrors) }) const wsClient = new WebSocketLink({ uri: 'ws://192.168.1.21:3000/graphql', options: { reconnect: true, connectionParams: { authorization: token, }, }, connectionParams: async () => { return { authorization: token }; }, webSocketImpl: WebSocket, reconnectionAttempts: 99, }); 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 auth = new ApolloLink((operation, forward) => { operation.setContext({ headers: new HttpHeaders().set('authorization', `${token}`), }); return forward(operation); }); const link = split( ({query}) => { const {kind, operation}: any = getMainDefinition(query); return kind === 'OperationDefinition' && operation === 'subscription'; }, wsClient, auth.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' } } }); } } `
I don't understand