Skip to content
This repository was archived by the owner on Jan 21, 2026. It is now read-only.

Commit 4c05cae

Browse files
authored
perf(deps): avoid semver where possible (#1309)
avoid loading the semver dependency.
1 parent ffbabfe commit 4c05cae

3 files changed

Lines changed: 33 additions & 45 deletions

File tree

src/cls.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
// limitations under the License.
1414

1515
import {EventEmitter} from 'events';
16-
import * as semver from 'semver';
1716

1817
import {AsyncHooksCLS} from './cls/async-hooks';
1918
import {AsyncListenerCLS} from './cls/async-listener';
@@ -27,8 +26,6 @@ import {UNCORRELATED_ROOT_SPAN, DISABLED_ROOT_SPAN} from './span-data';
2726
import {Trace, TraceSpan} from './trace';
2827
import {Singleton} from './util';
2928

30-
const asyncHooksAvailable = semver.satisfies(process.version, '>=8');
31-
3229
export interface RealRootContext {
3330
readonly span: TraceSpan;
3431
readonly trace: Trace;
@@ -115,11 +112,6 @@ export class TraceCLS implements CLS<RootContext> {
115112
constructor(config: TraceCLSConfig, private readonly logger: Logger) {
116113
switch (config.mechanism) {
117114
case TraceCLSMechanism.ASYNC_HOOKS:
118-
if (!asyncHooksAvailable) {
119-
throw new Error(
120-
`CLS mechanism [${config.mechanism}] is not compatible with Node <8.`
121-
);
122-
}
123115
this.CLSClass = AsyncHooksCLS;
124116
this.rootSpanStackOffset = 4;
125117
break;

src/index.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ const filesLoadedBeforeTrace = Object.keys(require.cache);
1616

1717
// This file's top-level imports must not transitively depend on modules that
1818
// do I/O, or continuation-local-storage will not work.
19-
import * as semver from 'semver';
2019
import {Config, defaultConfig} from './config';
2120
import * as extend from 'extend';
2221
import * as path from 'path';
@@ -28,6 +27,16 @@ import {TraceCLSMechanism} from './cls';
2827
import {StackdriverTracer} from './trace-api';
2928
import {TraceContextHeaderBehavior} from './tracing-policy';
3029

30+
if (process && process.version) {
31+
const minNodeVersion = 10;
32+
const major = Number(process.version.match(/v(\d+)/)![1]);
33+
if (major < minNodeVersion) {
34+
throw Error(
35+
`trace-agent supports a minimum Node.js version of ${minNodeVersion}. Read our version support policy: https://github.com/googleapis/cloud-trace-nodejs#supported-nodejs-versions`
36+
);
37+
}
38+
}
39+
3140
export {Config, PluginTypes};
3241

3342
let traceAgent: StackdriverTracer;
@@ -88,11 +97,8 @@ function initConfig(userConfig: Forceable<Config>): TopLevelConfig {
8897
const getInternalClsMechanism = (clsMechanism: string): TraceCLSMechanism => {
8998
// If the CLS mechanism is set to auto-determined, decide now
9099
// what it should be.
91-
const ahAvailable = semver.satisfies(process.version, '>=8');
92100
if (clsMechanism === 'auto') {
93-
return ahAvailable
94-
? TraceCLSMechanism.ASYNC_HOOKS
95-
: TraceCLSMechanism.ASYNC_LISTENER;
101+
return TraceCLSMechanism.ASYNC_HOOKS;
96102
}
97103
return clsMechanism as TraceCLSMechanism;
98104
};

src/plugins/plugin-http.ts

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import * as httpModule from 'http';
1616
import {Agent, ClientRequest, ClientRequestArgs, request} from 'http';
1717
import * as httpsModule from 'https';
18-
import * as semver from 'semver';
1918
import * as shimmer from 'shimmer';
2019
import {URL, UrlWithStringQuery} from 'url';
2120

@@ -31,12 +30,7 @@ const ERR_HTTP_HEADERS_SENT_MSG = "Can't set headers after they are sent.";
3130
// URL is used for type checking, but doesn't exist in Node <7.
3231
// This function works around that.
3332
// eslint-disable-next-line @typescript-eslint/no-explicit-any
34-
const isURL = semver.satisfies(process.version, '>=7')
35-
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
36-
(value: any): value is URL => value instanceof URL
37-
: // eslint-disable-next-line
38-
(value: any): value is URL => false;
39-
// tslint:enable:no-any
33+
const isURL = (value: any): value is URL => value instanceof URL;
4034

4135
function getSpanName(options: ClientRequestArgs | URL) {
4236
// c.f. _http_client.js ClientRequest constructor
@@ -268,28 +262,26 @@ function patchHttp(http: HttpModule, api: Tracer) {
268262
return makeRequestTrace('http:', request, api);
269263
});
270264

271-
if (semver.satisfies(process.version, '>=8.0.0')) {
272-
// http.get in Node 8 calls the private copy of request rather than the one
273-
// we have patched on module.export, so patch get as well.
274-
shimmer.wrap(http, 'get', (): typeof http.get => {
275-
// Re-implement http.get. This needs to be done (instead of using
276-
// makeRequestTrace to patch it) because we need to set the trace
277-
// context header before the returned ClientRequest is ended.
278-
// The Node.js docs state that the only differences between request and
279-
// get are that (1) get defaults to the HTTP GET method and (2) the
280-
// returned request object is ended immediately.
281-
// The former is already true (at least in supported Node versions up to
282-
// v9), so we simply follow the latter.
283-
// Ref:
284-
// https://nodejs.org/dist/latest/docs/api/http.html#http_http_get_options_callback
285-
return function getTrace(this: never) {
286-
// eslint-disable-next-line prefer-rest-params
287-
const req = http.request.apply(this, arguments);
288-
req.end();
289-
return req;
290-
};
291-
});
292-
}
265+
// http.get in Node 8 calls the private copy of request rather than the one
266+
// we have patched on module.export, so patch get as well.
267+
shimmer.wrap(http, 'get', (): typeof http.get => {
268+
// Re-implement http.get. This needs to be done (instead of using
269+
// makeRequestTrace to patch it) because we need to set the trace
270+
// context header before the returned ClientRequest is ended.
271+
// The Node.js docs state that the only differences between request and
272+
// get are that (1) get defaults to the HTTP GET method and (2) the
273+
// returned request object is ended immediately.
274+
// The former is already true (at least in supported Node versions up to
275+
// v9), so we simply follow the latter.
276+
// Ref:
277+
// https://nodejs.org/dist/latest/docs/api/http.html#http_http_get_options_callback
278+
return function getTrace(this: never) {
279+
// eslint-disable-next-line prefer-rest-params
280+
const req = http.request.apply(this, arguments);
281+
req.end();
282+
return req;
283+
};
284+
});
293285
}
294286

295287
// https.get depends on Node http internals in 8.9.0 and 9+ instead of the
@@ -310,9 +302,7 @@ function patchHttps(https: HttpsModule, api: Tracer) {
310302

311303
function unpatchHttp(http: HttpModule) {
312304
shimmer.unwrap(http, 'request');
313-
if (semver.satisfies(process.version, '>=8.0.0')) {
314-
shimmer.unwrap(http, 'get');
315-
}
305+
shimmer.unwrap(http, 'get');
316306
}
317307

318308
function unpatchHttps(https: HttpsModule) {

0 commit comments

Comments
 (0)