[RFC] Node.js v16 Upgrade Plan
See original GitHub issueOverview
OpenSearch Dashboards is currently running an EOL Node.js version, Node.js v10.24.1. This current version of Node carries with it several high severity security vulnerabilities, as well as forces us to use older version of critical dependencies that carry their own share security vulnerabilities. The intent of the core Dashboards team is to upgrade to Node.js v16.9.1 which goes into LTS support in October 2021. The OpenSearch project is following the SemVer standard for versioning; therefore, the Node.js v16 upgrade is considered a breaking change and will require a version bump of Dashboards to 2.0.0Scope
The scope of the Node 16 upgrade is to do the minimum amount of dependency, code, and testing changes to allow for the core Dashboards team to address many of the CVEs that are present currently and blocked by our current Node.js version. While there may be many opportunities to make changes or upgrade packages because of the new version of Node, they would be out of scope of the work done to upgrade Dashboards to Node.js v16.Upgrade Proposal
The Node.js v16 upgrade will take the form of 3 phases that will be cycled through for each new plugin and developer wanting to upgrade. The 3 phases are somewhat coupled which makes working on the phases asynchronously difficult.Phase 1: Dependency Version Parity
This phase consists primarily of bringing all of Dashboards’ dependencies up to parity with what Node.js v16 expects/requires. Node v16 is many major versions higher than what we were working with before and will require upgrades to several dependencies. These changes will introduce cascading breaking changes to other dependencies, as well as to some code implementations in Dashboards.Below is a table of dependencies that are required to upgrade to Node.js v16 for core Dashboards:
Dependencies | Current Version | Upgrade Version | Notes | Function in Dashboards |
---|---|---|---|---|
lmdb-store | 0.6.10 | 1.6.7 | The primary issue introduced by Node.js v16 upgrade is that the sub-dependency msgpackr-extract is not supported by Node 16 and requires lmdb-store to be bumped to latest. |
lmdb-store is a key-value store library being used by our osd-optimizer package for cluster caching |
node-sass | v5 | 6.0.1 | node-sass is deprecated and should be changed to dart-sass; however, there was a version of node-sass that was supported by Node.js v16 and that was version 6.0.1. Bumping node-sass rather than swapping out to dart-sass seems to be less work and there are other open questions surrounding the use of dart-sass with regards to EUI. | node-sass is the primary library for using Sass. Currently deprecated in favor of dart-sass |
sass-loader | 8.0.2 | 10.2.0 | Bumping node-sass up to v6.0.1 causes the need to upgrade sass-loader to a newer version that supports both node-sass v6.0.1 and node.js v16.9.1. | helper library for all things Sass |
@types/webpack-env | 1.15.2 | 1.15.3 | This version bump was required because of a bug with Node.js interfacing with webpack. The error was: error TS2430: Interface 'NodeJS.Module' incorrectly extends interface '__WebpackModuleApi.Module |
Type definitions for typescript that correspond to webpack and are to be used in conjunction with webpack |
tslib | N/A | 2.0.0 | The tslib module is explicitly required for Node.js v16 and was not added in our package.json | runtime library for typescript that contains all of the typescript helper functions |
@types/node | >=10.17.17 <10.20.0 | 16.9.1 | It’s required to update to the latest type definition package for node that corresponds to the Node.js major version being used | Type definitions for typescript that correspond to Node major versions |
The majority of the errors pertaining to dependency version errors and version mismatches will manifest themselves as build errors and package compatibility errors. Some of the errors will manifest as type/code logical errors but those will be handled in the next phase.
Phase 2: Breaking code changes
The next major obstacle is the plethora of breaking code changes introduced both by the new version of Node.js itself and the new versions of other dependencies. This phase requires a good amount of familiarity with breaking changes across major versions of dependencies. The three major types of code changes are listed below:- Syntax strictness with regards to null and undefined behavior
- Node.js v16 has become much more strict with the handling of possible null and undefined behaviors.
- The majority of these types of errors are fixed by passing the
non-null assertion operator
if you are sure that the value being passed in code is not going to be null - e.g.
- childProcess.stdin!.end(stdin, ‘utf8’); // TypeScript note: As long as the proc stdio[1] is ‘pipe’, then stdin will not be null
- Node has an issue with stdin and stderr null possibilities and requires the
non-null assertion operator
to no longer break the build - Type mismatches and type strictness
- There are lambdas throughout the code base that are using variables with no explicit type
- Variables being typed as unknown so they break type definitions for certain interfaces
- Generally the error messages take the form of
Type<unknown> cannot be assigned to Type<type>
- There are cases of the type definitions expected by
@types/node
not matching the actual types - E.g.
urlUtils.encodeQuery
expects key/value pairs with values of typestring | string[] | null
,
however@types/node
says thaturl.query
has values of typestring | string[] | undefined
.
After investigating this, it seems that no matter what the values will be of typestring | string[]
- Feature deprecation and new data interfaces
- Webpack config file has deprecated an object property in favor of another in newer versions
- webpack-config:
prependData
changed toadditionalData
- The
additionalData
property requires an additionalcontent
parameter - The
lmdb-store
version bump leads to a required rewrite of ourcache.ts
file in theosd-optimizer
package - This is required because in v0.6.10, there was no data interface for the store. This lead to elastic creating their own data interface abstraction
- interface Lmdb<T> {
get(key: string): T | undefined;
put(key: string, value: T, version?: number, ifVersion?: number): Promise<boolean>;
remove(key: string, ifVersion?: number): Promise<boolean>;
openDB<T>(options: { name: string; encoding: ‘msgpack’ | ‘string’ | ‘json’ | ‘binary’ }): Lmdb<T>;
getRange(options?: {
start?: T;
end?: T;
reverse?: boolean;
limit?: number;
versions?: boolean;
}): Iterable<{ key: string; value: T }>;
} - In
lmdb-store
v1.6.7, they have introduced new interfaces that must be used in our caching implementation. - The
lmdb-store
types are: LmdbStore.RootDatabase
LmdbStore.Database
- A rewrite of some of the member methods of the
Cache
class is required to satisfy the more strict exception handling requirements of Node
Phase 3: Runtime Errors
Runtime errors tend to be the hardest types of errors to track down in this process and they usually occur either as you attempt to run Dashboards usingyarn start
or they crop up while Dashboards is running itself. Node 16 Cluster error:
There seems to be an issue with importing the
cluster
module in the worker.ts
file in core. log [16:54:15.757] [fatal][root] TypeError: _cluster.default.setupPrimary is not a functionWhen switching the import from
import cluster from ‘cluster’
to import * as cluster from ‘cluster’
we get the following error.Unhandled Promise rejection detected:
TypeError: Cannot read properties of undefined (reading ‘apply’)
at BinderFor.on (/home/ubuntu/OpenSearch-Dashboards/src/cli/cluster/binder.ts:47:8)
at BinderFor.on (/home/ubuntu/OpenSearch-Dashboards/src/cli/cluster/binder_for.ts:41:11)
at Worker.start (/home/ubuntu/OpenSearch-Dashboards/src/cli/cluster/worker.ts:228:24)
at ClusterManager.startCluster (/home/ubuntu/OpenSearch-Dashboards/src/cli/cluster/cluster_manager.ts:181:14)
at FSWatcher.<anonymous> (/home/ubuntu/OpenSearch-Dashboards/src/cli/cluster/cluster_manager.ts:249:12)
API Error:
The following 2 errors occur when starting dashboards with
yarn start
after upgrading lmdb-store
, node-sass
, and sass-loader
. It stops Dashboards from loading the home app because the capabilities api call never succeeds.NetworkError when attempting to fetch resource.
Version:
1.1
.
0
Build
:
9007199254740991
Error
:
NetworkError
when
attempting to fetch resource
.
HttpFetchError@http
:
//localhost:5603/ime/9007199254740991/bundles/core/core.entry.js:18398:5
fetchResponse@http
:
//localhost:5603/ime/9007199254740991/bundles/core/core.entry.js:18274:13
Uncaught (in promise) TypeError: NetworkError when attempting to fetch resource.Looks like the above errors pertain to the api/core/capabilities API request
HttpFetchError http_fetch_error.ts:38
fetchResponse fetch.ts:156
osdBootstrap osd_bootstrap.ts:57
AsyncFunctionThrow self-hosted:697
POST http://localhost:5603/azc/api/core/capabilities net::ERR_EMPTY_RESPONSE
Issue Analytics
- State:
- Created 2 years ago
- Comments:15 (14 by maintainers)
Top Results From Across the Web
Node v16.15.0 (LTS)
Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.
Read more >Node.js v19.3.0 Documentation
Enabling the feature; Configuring a package; Upgrading the global versions; Offline workflow. Supported package managers; Common questions.
Read more >Node v17.5.0 (Current)
Adds experimental support to the fetch API. This adds a --experimental-fetch flag that installs the fetch , Request , Response and Headers ...
Read more >The Difference Between Node.js 10 LTS and Node.js 12 LTS
Upgrade npm to v6.5.0 (Jordan Harband) #25234. fs: Use internalBinding('fs') internally instead of process.binding('fs') ...
Read more >Errors | Node.js v19.3.0 Documentation
mjs:line:column , if the frame represents a call in a user program (using ES module system), or its dependencies. The string representing the...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
@AMoo-Miki So, v16 will be Active LTS on 2021-10-26 which will be before the time we follow through on this RFC. If an organization wants to disallow active LTS, that seems like their problem, not ours.
Every time Dashboard’s adopts a new version of Node it’s a new major version (according to SemVer). Every new major can cause heartburn for our users and those who want to develop plugins for Dashboards. The least we can do is give them the longest interval between needing to take TUMS.
Please make sure to include changes to https://github.com/opensearch-project/opensearch-build when node is upgraded. It likely means building different docker images.