Skip to content

Commit c2c40c9

Browse files
committed
Make driver package work with Webpack
Improved feature detection and tweaked package.json in order to make Webpack not load NodeJS modules. Feature detection is also changed to account for possibly empty Node modules, like net ot dns. Previous packaging was the same for Node and browser and feature detection happened at runtime. Webpack, however, tried to resolve modules at compile time and failed. New "browser" entry in package.json tells bundlers to return empty objects for Node modules.
1 parent 9acaeac commit c2c40c9

13 files changed

+163
-137
lines changed

package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@
2121
"browser": "gulp browser && gulp test-browser"
2222
},
2323
"main": "lib/index.js",
24+
"browser": {
25+
"dns": false,
26+
"buffer": false,
27+
"net": false,
28+
"readline": false,
29+
"crypto": false,
30+
"tls": false
31+
},
2432
"unpkg": "lib/browser/neo4j-web.js",
2533
"jsdelivr": "lib/browser/neo4j-web.js",
2634
"types": "types/index.d.ts",

src/v1/internal/buf.js

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@
1616
* See the License for the specific language governing permissions and
1717
* limitations under the License.
1818
*/
19-
20-
/** This module defines a common API for dealing with binary data that
21-
* works for both browsers (via ArrayBuffer/DataView) and for NodeJS
22-
*(via Buffer API).
23-
*/
2419

25-
let _node = require("buffer");
20+
import Platform from './platform';
21+
import node from 'buffer';
22+
23+
/**
24+
* This module defines a common API for dealing with binary data that
25+
* works for both browsers (via ArrayBuffer/DataView) and for NodeJS
26+
*(via Buffer API).
27+
*/
28+
2629
/**
2730
* Common base with default implementation for most buffer methods.
2831
* Buffers are stateful - they track a current "position", this helps greatly
@@ -513,7 +516,7 @@ class CombinedBuffer extends BaseBuffer {
513516
*/
514517
class NodeBuffer extends BaseBuffer {
515518
constructor(arg) {
516-
const buffer = arg instanceof _node.Buffer ? arg : newNodeJSBuffer(arg);
519+
const buffer = newNodeJSBuffer(arg);
517520
super(buffer.length);
518521
this._buffer = buffer;
519522
}
@@ -562,22 +565,18 @@ class NodeBuffer extends BaseBuffer {
562565
}
563566

564567
function newNodeJSBuffer(arg) {
565-
if (typeof arg === 'number' && typeof _node.Buffer.alloc === 'function') {
568+
if (arg instanceof node.Buffer) {
569+
return arg;
570+
} else if (typeof arg === 'number' && typeof node.Buffer.alloc === 'function') {
566571
// use static factory function present in newer NodeJS versions to allocate new buffer with specified size
567-
return _node.Buffer.alloc(arg);
572+
return node.Buffer.alloc(arg);
568573
} else {
569574
// fallback to the old, potentially deprecated constructor
570-
return new _node.Buffer(arg);
575+
return new node.Buffer(arg);
571576
}
572577
}
573578

574-
// Use HeapBuffer by default, unless Buffer API is available, see below
575-
let _DefaultBuffer = HeapBuffer;
576-
try {
577-
// This will throw an exception if we're not running on NodeJS or equivalent
578-
require.resolve("buffer");
579-
_DefaultBuffer = NodeBuffer;
580-
} catch(e) {}
579+
const _DefaultBuffer = Platform.nodeBufferAvailable() ? NodeBuffer : HeapBuffer;
581580

582581
/**
583582
* Allocate a new buffer using whatever mechanism is most sensible for the current platform.

src/v1/internal/ch-config.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
* limitations under the License.
1818
*/
1919

20-
import hasFeature from './features';
20+
import Platform from './platform';
2121
import {SERVICE_UNAVAILABLE} from '../error';
2222

2323
const DEFAULT_CONNECTION_TIMEOUT_MILLIS = 5000; // 5 seconds by default
@@ -45,7 +45,7 @@ function extractEncrypted(driverConfig) {
4545
// check if encryption was configured by the user, use explicit null check because we permit boolean value
4646
const encryptionNotConfigured = driverConfig.encrypted == null;
4747
// default to using encryption if trust-all-certificates is available
48-
if (encryptionNotConfigured && hasFeature('trust_all_certificates')) {
48+
if (encryptionNotConfigured && Platform.trustAllCertificatesAvailable()) {
4949
return true;
5050
}
5151
return driverConfig.encrypted;
@@ -56,7 +56,7 @@ function extractTrust(driverConfig) {
5656
return driverConfig.trust;
5757
}
5858
// default to using TRUST_ALL_CERTIFICATES if it is available
59-
return hasFeature('trust_all_certificates') ? 'TRUST_ALL_CERTIFICATES' : 'TRUST_CUSTOM_CA_SIGNED_CERTIFICATES';
59+
return Platform.trustAllCertificatesAvailable() ? 'TRUST_ALL_CERTIFICATES' : 'TRUST_CUSTOM_CA_SIGNED_CERTIFICATES';
6060
}
6161

6262
function extractTrustedCertificates(driverConfig) {

src/v1/internal/ch-node.js

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {EOL} from 'os';
2626
import {NodeBuffer} from './buf';
2727
import {ENCRYPTION_OFF, isEmptyObjectOrNull} from './util';
2828
import {newError} from './../error';
29+
import Platform from './platform';
2930

3031
let _CONNECTION_IDGEN = 0;
3132

@@ -392,13 +393,9 @@ class NodeChannel {
392393
}
393394
}
394395
}
395-
let _nodeChannelModule = {channel: NodeChannel, available: true};
396396

397-
try {
398-
// Only define this module if 'net' is available
399-
require.resolve("net");
400-
} catch(e) {
401-
_nodeChannelModule = { available : false };
402-
}
397+
const _nodeChannelModule = Platform.nodeSocketAvailable()
398+
? {channel: NodeChannel, available: true}
399+
: {available: false};
403400

404-
export default _nodeChannelModule
401+
export default _nodeChannelModule;

src/v1/internal/connection-providers.js

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ import {READ, WRITE} from '../driver';
2222
import Session from '../session';
2323
import RoutingTable from './routing-table';
2424
import Rediscovery from './rediscovery';
25-
import hasFeature from './features';
26-
import {DnsHostNameResolver, DummyHostNameResolver} from './host-name-resolvers';
2725
import RoutingUtil from './routing-util';
2826

2927
const UNAUTHORIZED_ERROR_CODE = 'Neo.ClientError.Security.Unauthorized';
@@ -261,13 +259,6 @@ export class LoadBalancer extends ConnectionProvider {
261259
routingTable.forgetRouter(address);
262260
}
263261
}
264-
265-
static _createHostNameResolver() {
266-
if (hasFeature('dns_lookup')) {
267-
return new DnsHostNameResolver();
268-
}
269-
return new DummyHostNameResolver();
270-
}
271262
}
272263

273264
export class SingleConnectionProvider extends ConnectionProvider {

src/v1/internal/features.js

Lines changed: 0 additions & 61 deletions
This file was deleted.

src/v1/internal/host-name-resolvers.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919

2020
import urlUtil from './url-util';
21+
import nodeDns from 'dns';
2122

2223
class HostNameResolver {
2324

@@ -54,16 +55,11 @@ export class ConfiguredHostNameResolver extends HostNameResolver {
5455

5556
export class DnsHostNameResolver extends HostNameResolver {
5657

57-
constructor() {
58-
super();
59-
this._dns = require('dns');
60-
}
61-
6258
resolve(seedRouter) {
6359
const parsedAddress = urlUtil.parseDatabaseUrl(seedRouter);
6460

6561
return new Promise((resolve) => {
66-
this._dns.lookup(parsedAddress.host, {all: true}, (error, addresses) => {
62+
nodeDns.lookup(parsedAddress.host, {all: true}, (error, addresses) => {
6763
if (error) {
6864
resolve(resolveToItself(seedRouter));
6965
} else {

src/v1/internal/platform.js

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/**
2+
* Copyright (c) 2002-2018 "Neo4j,"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
import {isEmptyObjectOrNull} from './util';
21+
22+
let _trustOnFirstUseAvailable = null;
23+
let _trustAllCertificatesAvailable = null;
24+
let _dnsLookupAvailable = null;
25+
let _nodeSocketAvailable = null;
26+
let _nodeBufferAvailable = null;
27+
28+
export default class Platform {
29+
30+
static trustOnFirstUseAvailable() {
31+
if (_trustOnFirstUseAvailable == null) {
32+
try {
33+
// We are verifying that we have a version of getPeerCertificate
34+
// that supports reading the whole certificate, eg this commit:
35+
// https://github.com/nodejs/node/commit/345c40b6
36+
require.resolve('tls');
37+
const getPeerCertificateFunction = require('tls').TLSSocket.prototype.getPeerCertificate;
38+
const numberOfParameters = getPeerCertificateFunction.length;
39+
_trustOnFirstUseAvailable = numberOfParameters >= 1;
40+
} catch (e) {
41+
_trustOnFirstUseAvailable = false;
42+
}
43+
}
44+
return _trustOnFirstUseAvailable;
45+
}
46+
47+
static trustAllCertificatesAvailable() {
48+
if (_trustAllCertificatesAvailable == null) {
49+
try {
50+
require.resolve('tls');
51+
const getPeerCertificateFunction = require('tls').TLSSocket.prototype.getPeerCertificate;
52+
_trustAllCertificatesAvailable = getPeerCertificateFunction && typeof getPeerCertificateFunction === 'function';
53+
} catch (e) {
54+
_trustAllCertificatesAvailable = false;
55+
}
56+
}
57+
return _trustAllCertificatesAvailable;
58+
}
59+
60+
static dnsLookupAvailable() {
61+
if (_dnsLookupAvailable == null) {
62+
try {
63+
require.resolve('dns');
64+
const lookupFunction = require('dns').lookup;
65+
_dnsLookupAvailable = lookupFunction && typeof lookupFunction === 'function';
66+
} catch (e) {
67+
_dnsLookupAvailable = false;
68+
}
69+
}
70+
return _dnsLookupAvailable;
71+
}
72+
73+
static nodeSocketAvailable() {
74+
if (_nodeSocketAvailable == null) {
75+
try {
76+
require.resolve('net');
77+
const netModule = require('net');
78+
_nodeSocketAvailable = !isEmptyObjectOrNull(netModule);
79+
} catch (e) {
80+
_nodeSocketAvailable = false;
81+
}
82+
}
83+
return _nodeSocketAvailable;
84+
}
85+
86+
static nodeBufferAvailable() {
87+
if (_nodeBufferAvailable == null) {
88+
try {
89+
require.resolve('buffer');
90+
const bufferModule = require('buffer');
91+
_nodeBufferAvailable = !isEmptyObjectOrNull(bufferModule);
92+
} catch (e) {
93+
_nodeBufferAvailable = false;
94+
}
95+
}
96+
return _nodeBufferAvailable;
97+
}
98+
}

src/v1/internal/utf8.js

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@
2323
import {alloc, CombinedBuffer, HeapBuffer, NodeBuffer} from './buf';
2424
import {StringDecoder} from 'string_decoder';
2525
import {newError} from './../error';
26+
import textEncoding from 'text-encoding';
27+
import Platform from './platform';
28+
import node from 'buffer';
2629

2730
let platformObj = {};
2831

32+
if (Platform.nodeBufferAvailable()) {
2933

30-
try {
31-
// This will throw an exception is 'buffer' is not available
32-
require.resolve("buffer");
3334
const decoder = new StringDecoder('utf8');
34-
const node = require('buffer');
3535

3636
// use static factory function present in newer NodeJS versions to create a buffer containing the given string
3737
// or fallback to the old, potentially deprecated constructor
@@ -67,10 +67,8 @@ try {
6767
}
6868
}
6969

70-
} catch (e) {
70+
} else {
7171

72-
// Not on NodeJS, add shim for WebAPI TextEncoder/TextDecoder
73-
var textEncoding = require('text-encoding');
7472
let encoder = new textEncoding.TextEncoder("utf-8");
7573
let decoder = new textEncoding.TextDecoder("utf-8");
7674

@@ -83,7 +81,7 @@ try {
8381
return decoder.decode(buffer.readView(Math.min(length, buffer.length - buffer.position)));
8482
}
8583
else {
86-
// Decoding combined buffer is complicated. For simplicity, for now,
84+
// Decoding combined buffer is complicated. For simplicity, for now,
8785
// we simply copy the combined buffer into a regular buffer and decode that.
8886
var tmpBuf = alloc(length);
8987
for (var i = 0; i < length; i++) {
@@ -94,6 +92,7 @@ try {
9492
}
9593
}
9694
}
95+
9796
}
9897

9998
let streamDecodeCombinedBuffer = (combinedBuffers, length, decodeFn, endFn) => {

0 commit comments

Comments
 (0)