Troubleshooting error: Uncaught ReferenceError when using openpgp.js on Cloudflare worker with Node.js: How to resolve navigator is not defined?

I recently created a Cloudflare Worker using the Typescript template, with minimal changes to the build configuration. The worker needs to utilize openpgp.js, which is supposed to be supported on Node.js based on the given link.

After successfully building it with npm run build, I encountered an error when attempting to build with wrangler dev:

webpack 5.38.1 compiled successfully in 1147 ms
Error: Something went wrong with the request to Cloudflare...
Uncaught ReferenceError: navigator is not defined
  at line 237 in ./node_modules/openpgp/dist/lightweight/openpgp.min.mjs
  at line 827 in __webpack_require__
  at line 625 in ./src/crypto.ts
  at line 827 in __webpack_require__
  at line 749 in ./src/handler.ts
  at line 827 in __webpack_require__
  at line 1064
  at line 1069
  at line 1071
 [API code: 10021]

While browsing for solutions, I came across a recommendation to use browser-env to expose the global variable navigator. However, upon trying this approach, I encountered a cascade of errors leading to module not found issues:

ERROR in ./node_modules/window/node_modules/tough-cookie/lib/cookie.js 34:11-26
Module not found: Error: Can't resolve 'util' in '/Users/renato/programming/projects/renato-worker/node_modules/window/node_modules/tough-cookie/lib'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.
...
ERROR in /Users/renato/programming/projects/renato-worker/src/index.ts
./src/index.ts 4:23-36
[tsl] ERROR in /Users/renato/programming/projects/renato-worker/src/index.ts(4,24)
      TS7016: Could not find a declaration file for module 'browser-env'. '/Users/renato/programming/projects/renato-worker/node_modules/browser-env/src/index.js' implicitly has an 'any' type.
  Try `npm i --save-dev @types/browser-env` if it exists or add a new declaration (.d.ts) file containing `declare module 'browser-env';`

My attempt to install types/browser-env resulted in a 404 error, leading me to rethink the solution provided. The documentation for browser-env also warned against a particular usage:

https://github.com/jsdom/jsdom/wiki/Don't-stuff-jsdom-globals-onto-the-Node-global

A common antipattern we see when people use jsdom is copying globals from a jsdom window onto the Node.js global, and then trying to run the code---intended for a browser---inside Node.js. This is very bad and you should not do it.

The alternative suggestion of using detect-node did not seem applicable to my situation, as the issue appears to relate more to the compilation process than differentiating between a browser or Node environment.

At this point, I am at a standstill. Would appreciate any insights from those proficient in tools like webpack, node.js, Typescript, browser APIs, wrangler, and Cloudflare API to help identify the root cause and suggest possible solutions.

Answer №1

After facing challenges for a while, I discovered that the issue stems from how Cloudflare validates Javascript code before deploying it on their platform (even in preview mode).

They restrict the use of certain APIs, including the navigator object which is typically not accessible in backend Javascript.

This poses a problem when utilizing openpgp.js as it relies on the navigator to identify the userAgent and determine the number of available cores.

I attempted to address this by submitting a pull request to centralize access to the navigator, making it easier to replace with tools like webpack. However, the PR was rejected as it was deemed unnecessary - simply substituting navigator with {} should suffice to make everything work seamlessly.

For more insights, refer to the pull request. A quick solution would be to add something similar to this snippet in your webpack.config.json file:

  plugins: [
    new webpack.ProvidePlugin({
      'navigator': ['{}'],
    }),
  ]

The developer behind openpgp.js shows eagerness to eliminate the reliance on navigator in upcoming releases, rendering this workaround obsolete soon!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Guide to adjusting the color of Fluent UI icon when hovering with mouse?

I've been implementing Fluent UI in my current project. When initializing my button, I use this straightforward JavaScript code: iconProps: { iconName: 'NewFolder', styles: { root: { color: 'orang ...

Is it possible for a method within a variable in Typescript to invoke another method?

I need to execute a random function in my code. Here is what I have: module A { ... export function foo(): number { let b = new B(); let possibleFunctions = [ b.possibleFunction1, b.possibleFunction2 ...

Utilize a function to wrap the setup and teardown code in Jest

I am attempting to streamline some common setup and teardown code within a function as shown below: export function testWithModalLifecycle() { beforeEach(() => { const modalRootDom = document.createElement('div') modalRootDom.id = M ...

Jest encountered an error while trying to run the test suite: No message was given

Currently, I am in the process of converting my existing tests to utilize TypeScript with ts-jest. Although I have managed to locate all the necessary files, every single test is failing and producing the following error: FAIL src/components/Buttons/__t ...

Trouble arises with the date-picker component in Angular

There's a specific concept known as "campaign duration" where you can select a date between the first and last day of the month. If you choose a date outside this range, such as a date from the following month, the Backend API will respond with an "In ...

As time passes, the Azure Service Bus Consumer experiences a decline in performance

My issue involves managing different topics with subscriptions, each tied to a consumer. Over time, I've noticed a decline in the number of messages received. Despite trying to utilize maxconcurrentcalls, it seems to only be effective at the start. My ...

Getting React, Redux, and Typescript all collaborating together

Recently, I made the transition from using Angular to learning React and Redux. My first challenge arose when trying to integrate Redux into my React project. I set up a simple state, action, reducer, and store in my index.tsx file: export interface AppSt ...

What is the best approach for utilizing Inheritance in Models within Angular2 with TypeScript?

Hey there, I am currently dealing with a Model Class Question and a ModelClass TrueFalseQuestion. Here are the fields: question.model.ts export class Question { answerId: number; questionTitle: string; questionDescription: string; } truefals ...

Retrieve all exports from a module within a single file using Typescript/Javascript ES6 through programmatic means

I aim to extract the types of all module exports by iterating through them. I believe that this information should be accessible during compile time export const a = 123; export const b = 321; // Is there a way to achieve something similar in TypeScript/ ...

Utilizing Angular Pipes for Utilizing Location

The Location service in Angular is described as "A service that applications can use to interact with a browser's URL." One of its methods, getState(), provides "the current state of the location history," while another method, subscribe(), allows us ...

Learning to implement forwardRef in MenuItem from Material-UI

Encountering an error when pressing Select due to returning MenuItem in Array.map. Code const MenuItems: React.FC<{ items: number[] }> = (props) => { const { items } = props; return ( <> {items.map((i) => { return ( ...

What sets apart the various download options for Typescript, such as npm, NuGet, and Marketplace?

While working in VS Pro, I am a beginner developer in TypeScript (as well as React and Node...). I am focused on truly understanding how these technologies integrate and function together, rather than simply copying commands and code snippets into files. ...

Tips for implementing mixins in a Nuxt.js application using the nuxt-property-decorator package

Recently, I worked on a project where I utilized Nuxt.js with TypeScript as the language. In addition, I incorporated nuxt-property-decorator. I'm currently trying to grasp the concept of the 'mixins' property in the code snippet below: mi ...

How to eliminate subdomains from a string using TypeScript

I am working with a string in TypeScript that follows the format subdomain.domain.com. My goal is to extract just the domain part of the string. For example, subdomain.domain.com should become domain.com. It's important to note that the 'subdoma ...

VueJS TypeScript with ChartJS - Unexpected Token '}' Parsing Error

I have integrated Chart.js into my Vue project. After installing chart.js and @types/chart.js using npm, I included a chart.d.ts file with the line declare module 'chart.js'; . Encountered an error which can be viewed https://i.sstatic.net/8npR ...

Building a user interface with React JS to iterate over an array using the map function, passing each item as a parameter

I have been instructed to create an interface for my code related to .map, but I am unsure about how to proceed. I have been searching for examples without any luck so far. I have isolated the specific code with ###. Any assistance in this matter would be ...

Obtain precise measurements of a modified image using the Sharp library

My Cloud Function successfully resizes images uploaded to Cloud Storage using Sharp. However, I am facing an issue with extracting metadata such as the exact height and width of the new image. I am contemplating creating a new function that utilizes diff ...

How can I retrieve List<T> from a Razor Page using TypeScript?

Within my ViewModel, I have an Items collection: public class ItemViewModel{ public List<Item> Items {get;set;} } In the Index.cshtml file: @if(Model.Items != null){ <li><a id="item-id-link" href="#" data-items="@Model.Items"> ...

Tips for eliminating a single occurrence with Array.prototype.filter()

I am facing an issue in my React app with the deleteNumberFromList method. This function is designed to remove a specific number from the array by utilizing a setter hook: const [valuesList, setValuesList] = useState<number[]>([]); const deleteNumbe ...

Extracting data from an array using Angular

Currently, I am developing an Angular application that involves handling an array structured like the one below. [ { Code: "123", Details:[ { Id: "1", Name: "Gary" }, { ...