Skip to content

Commit

Permalink
fix: replace isBrowser() with home made feature detection (#1054)
Browse files Browse the repository at this point in the history
* fix: replace isBrowser() with home made feature detection

* fix: refactor TextEncoder usecase

* fix: proper copyright year for new file
  • Loading branch information
alexander-fenster authored Jul 12, 2021
1 parent cbe2d3f commit 2c8e56d
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 72 deletions.
84 changes: 33 additions & 51 deletions src/fallback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,30 @@
* limitations under the License.
*/

// Not all browsers support `TextEncoder`. The following `require` will
// provide a fast UTF8-only replacement for those browsers that don't support
// text encoding natively.
import {isBrowser} from './isbrowser';
let needTextEncoderPolyfill = false;

if (
isBrowser() &&
// eslint-disable-next-line node/no-unsupported-features/node-builtins
(typeof TextEncoder === 'undefined' || typeof TextDecoder === 'undefined')
) {
needTextEncoderPolyfill = true;
}
if (
typeof process !== 'undefined' &&
process?.versions?.node &&
process?.versions?.node.match(/^10\./)
) {
// Node.js 10 does not have global TextDecoder
// TODO(@alexander-fenster): remove this logic after Node.js 10 is EOL.
// eslint-disable-next-line @typescript-eslint/no-var-requires
const util = require('util');
Object.assign(global, {
TextDecoder: util.TextDecoder,
TextEncoder: util.TextEncoder,
});
}
if (needTextEncoderPolyfill) {
require('fast-text-encoding');
/* global window */
/* global AbortController */

import {
hasWindowFetch,
hasTextEncoder,
hasTextDecoder,
isNodeJS,
hasAbortController,
} from './featureDetection';

if (!hasTextEncoder() || !hasTextDecoder()) {
if (isNodeJS()) {
// Node.js 10 does not have global TextDecoder
// TODO(@alexander-fenster): remove this logic after Node.js 10 is EOL.
// eslint-disable-next-line @typescript-eslint/no-var-requires
const util = require('util');
Object.assign(global, {
TextDecoder: util.TextDecoder,
TextEncoder: util.TextEncoder,
});
} else {
require('fast-text-encoding');
}
}

import * as protobuf from 'protobufjs';
Expand Down Expand Up @@ -129,11 +124,11 @@ export class GrpcClient {
fallback?: boolean | 'rest' | 'proto';
} = {}
) {
if (isBrowser()) {
if (!isNodeJS()) {
if (!options.auth) {
throw new Error(
JSON.stringify(options) +
'You need to pass auth instance to use gRPC-fallback client in browser. Use OAuth2Client from google-auth-library.'
'You need to pass auth instance to use gRPC-fallback client in browser or other non-Node.js environments. Use OAuth2Client from google-auth-library.'
);
}
this.auth = options.auth as OAuth2Client;
Expand Down Expand Up @@ -352,17 +347,11 @@ export class GrpcClient {
},
]
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let cancelController: AbortController, cancelSignal: any;
if (isBrowser() || typeof AbortController !== 'undefined') {
// eslint-disable-next-line no-undef
cancelController = new AbortController();
} else {
cancelController = new NodeAbortController();
}
if (cancelController) {
cancelSignal = cancelController.signal;
}

const cancelController = hasAbortController()
? new AbortController()
: new NodeAbortController();
const cancelSignal = cancelController.signal;
let cancelRequested = false;

const headers = Object.assign({}, authHeader);
Expand Down Expand Up @@ -450,9 +439,8 @@ export class GrpcClient {
url = `${grpcFallbackProtocol}://${servicePath}:${servicePort}/$rpc/${protoServiceName}/${rpcName}`;
}

const fetch = isBrowser()
? // eslint-disable-next-line no-undef
window.fetch
const fetch = hasWindowFetch()
? window.fetch
: (nodeFetch as unknown as NodeFetchType);
const fetchRequest = {
headers,
Expand Down Expand Up @@ -512,12 +500,6 @@ export class GrpcClient {

return {
cancel: () => {
if (!cancelController) {
console.warn(
'AbortController not found: Cancellation is not supported in this environment'
);
return;
}
cancelRequested = true;
cancelController.abort();
},
Expand Down
50 changes: 50 additions & 0 deletions src/featureDetection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* global window */

const features = {
windowFetch:
typeof window !== 'undefined' &&
window?.fetch &&
typeof window?.fetch === 'function',
// eslint-disable-next-line node/no-unsupported-features/node-builtins
textEncoder: typeof TextEncoder !== 'undefined',
// eslint-disable-next-line node/no-unsupported-features/node-builtins
textDecoder: typeof TextDecoder !== 'undefined',
nodeJS: typeof process !== 'undefined' && process?.versions?.node,
abortController: typeof AbortController !== 'undefined',
};

export function hasWindowFetch() {
return features.windowFetch;
}

export function hasTextEncoder() {
return features.textEncoder;
}

export function hasTextDecoder() {
return features.textDecoder;
}

export function isNodeJS() {
return features.nodeJS;
}

export function hasAbortController() {
return features.abortController;
}
19 changes: 0 additions & 19 deletions src/isbrowser.ts

This file was deleted.

4 changes: 2 additions & 2 deletions src/warnings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

import {isBrowser} from './isbrowser';
import {isNodeJS} from './featureDetection';

const emittedWarnings = new Set<string>();

Expand All @@ -26,7 +26,7 @@ export function warn(code: string, message: string, warnType?: string) {
}
emittedWarnings.add(code);

if (isBrowser()) {
if (!isNodeJS()) {
console.warn(message);
} else if (typeof warnType !== 'undefined') {
process.emitWarning(message, {
Expand Down

0 comments on commit 2c8e56d

Please sign in to comment.