Allow node module relying on uuid() to execute in client and server - javascript

I have a node module that I am building, and I want it to be able to execute on the server (in nextjs server side rendering) and the client (call additional lifecycle methods in the UI). This same module also needs to work when used purely as a js library that can be included in a <script> tag on the page. This module depends on the uuid module, which has logic in it to check if it is running in a browser or server context, and use the proper random number generators/crypto libraries that are available in that context.
If I don't specify a target in my webpack config, the bundle works great in a client browser. It includes the webpack browser logic just fine. But it doesn't work in the server case - webpack removed the server capable logic in the uuid module.
If I target: 'node' in my webpack config - it executes just fine as a node module on the server and the client. It seemingly included all of the logic this time. But now it doesn't work if included just as a script tag on the page. I get ReferenceError: require is not defined from the file that depends on the uuid module.
It seems like the uuid module should handle these different environments just fine, but webpack is messing with that. How can I let that module resolve the proper implementation at runtime?
I unfortunately do not have a minimally reproducible example, or additional code to share at this time. I figured someone might have run into this with webpack (or even webpack and the uuid module) and know the solution.

I was trying to do this by building a single version of the package, but I don't think that is possible.
What is possible is building multiple versions, and then hosting the web bundle via unpkg or jsdelivr via an entry in package.json. Those entries can point to the target: 'web' version of the package, while the npm package can point to the target: 'node' version.

Related

Error when Requiring Twilio Voice SDK Javascript

I have included (via npm) the twilio/voice-sdk package (v.2.1.0) into a project. When I include the following code (as shown in many examples):
const Device = require('#twilio/voice-sdk').Device;
I get a console error stating:
"Cannot find module 'events' in '#twilio/audioplayer/es5'". I am trying to import this onto the client side, not server.
I get this whether I use require or import.
As an attempt around this, I have also include the node package #twilio/audioplayer, but to no avail. Kind of stuck as to what is going on here.
I am trying to use this on a Wix (or Velo more specifically) project. Hoping to create a dialer that can both answer and instigate phone calls on a site that already exists on that platform.
I have installed both of the above npm packages into my project, but get he above enumerated error.
Any ideas from the Internet?
Additional Information:
If I add the 'require' on the server side I do not get the same error. I was going to try this and then do an async call to the server to get my Device object. However, the Twilio Device SDK package utilizes the Window object, which of course does not exist on the server side.
The #twilio/audioplayer package uses the "events" module. This module is available in Node.js and when applications are bundled with something like Webpack is polyfilled.
I haven't used Velo, but I assume they are bundling differently in a way that doesn't add polyfills for this. I'd recommend installing the events npm module to your project too. That should provide the EventEmitter that the library is using for the browser environment and stop this error.
I had a similar problem, where I can import Device, but cannot construct it. The problem I had was that the bundler (in my case Vite) doesn't have a polyfill to run some functions inside the #twilio/voice-sdk.
The solution in my case was by installing polyfill on Vite.
Here is how:
First, install these packages:
npm i #esbuild-plugins/node-globals-polyfill #esbuild-plugins/node-modules-polyfill --save-dev
Then add the polyfill config to your vite.config.js. Here is link of the code: https://medium.com/#ftaioli/using-node-js-builtin-modules-with-vite-6194737c2cd2.
Because I use React, I still need to add plugins: [react()] inside the polyfill config. So it becomes something like:
export default defineConfig({
plugins: [react()],
// rest of the polyfill config
})
Now you can do:
import { Device } from "#twilio/voice-sdk";
new Device(token);

Package an npm module so that it can work in the frontend (eg. with create-react-app) `You may need an appropriate loader to handle this file type`

I have written a node module and published it as a node package. It works when I use it in backend applications (pure nodejs, no babel or transpile).
However, when I use this same npm module in the frontend (in my case a 'create-react-app') application, it breaks. Bellow is the exact error:
Module parse failed: Unexpected token (14:2)
You may need an appropriate loader to handle this file type.
The error is referring to my use of the spread operator (...). I would prefer not to have to rewrite the library, and would rather add some kind of transpiler to package my library. I haven't found a clear solution to this, they are all very convoluted.
I have tried using rollupjs, and https://github.com/insin/nwb. Neither sadly seem to be what I'm after.
Run my code:
You can install the library to your create react app using npm i cbs-proxy-client#0.0.3. And then add the line const cbsProxyClient = require('cbs-proxy-client') or import cbsProxyClient from 'cbs-proxy-client' to any of your scripts.
Advice would be appreciated :)
A library used for frontend is expected to package an already transpiled version of the source javascript. To do this, you might want to use rollup as a build process in your library to create a bundle file. You can use babel to transpile your code for desired browser support. Let's say the bundle file is saved in dist/bundle.js. Now you will modify the package.json to load this bundled file as the entry file using main parameter in package.json
If you are building using rollup or webpack, it is easy to miss that the bundled file should be prepared as a library. This means that importing the file using commonjs should be able to export correct variables. A typical webpack build removes such exports because it is supposed to work straight on a browser. This blog is in my bookmarks titled "js library steps" since I was creating my first js library.
Note that you do not need to put your generated file in version control. You can use npm files property in package.json to package your bundled files while ignoring them in git.

The npm http package only provides a package.json, no javascript files

I installed a npm package that had 'http' as a dependency, so I installed that as well. All that was downloaded by npm for 'http' was a package.json file which referenced a non-existent index.js file. Is the index.js indeed missing from package.json or am I doing something wrong?
I'm using systemJS as a library loader.
TL;DR: you can't run server-side modules inside a browser.
From what I understand, you're trying to use server-side JavaScript modules inside of a browser, which isn't going to work. Browser have (very) limited abilities to set up network connection, or read from local file systems.
The http dependency that you're refering to is part of the Node standard library. So for Node apps, running server-side, it's always available.
In your case, you assumed that because require('http') didn't work (in the browser), you needed to install a separate package for that (this package).
But even if that package was working properly (it isn't), it wouldn't have worked inside of a browser because it depends on other modules inside the Node standard library, that also aren't available in a browser.
I don't know if CouchDB has a REST API itself that you would be able to use from the browser, but if not, you're going to have to implement a server-side API that will act as go-between between the browser and CouchDB.
From the browser, to talk to CouchDB, try the PouchDB library (https://pouchdb.com/) and put the URL to your CouchDB in the constructor. It's intended for connecting to a local PouchDB (javascript implementation of CouchDB) but their APIs are identical. Or, try actually using a local PouchDB and then syncing between the two databases.

import ES6 modules in Angular2 served by Express

I would like to use ES6 Modules with Angular2 in an app that is served by Node.js and Express.js. However, when I try to load an Angular2/ES6 app in the browser, the following is printed in the FireFox console:
The stylesheet http://localhost:8080/boot.css was not loaded because its MIME type, "text/html", is not "text/css". localhost:8080
SyntaxError: import declarations may only appear at top level of a module vendor.js:1:0
SyntaxError: import declarations may only appear at top level of a module boot.js:1:0
The problem seems to be the result of something missing from the build of the Angular2 app that is done by the Node.js/Express.js server that serves the Angular2 app.
Specifically, the problem emerged after I deleted the entire public app folder from this GitHub AngularJS 1.x sample app and replaced it with a copy of the entire client app folder from this GitHub Angular2 example app. When I then started the Express.js server with nodemon server.js and typed http : // localhost : 8080 into FireFox, the console printed out the errors shown above.
I would like to get the Angular2 app running in the browser so that I can then manually start stepping through the work of re-creating the Node.js routes and resolving other errors one by one in order to get the Angular2 app to work with the Node.js/Express.js server.
What specific changes need to be made so that these initial errors due to ES6 imports are resolved when this Angular2 app is placed inside the public folder of this Node.js/Express.js instance?
I just check out those two repos, and then do the same thing you mentioned above.
the problem is that the client folder of angular2 is written is ES6 syntax.
I don't think currently we can run this code on the browser without problem and
you can tell from the repo that it uses babel to compile the code
so if you want to use its client code, just make sure you also do the same
compile stuff as it does. I think everything should work
update
What I am trying to say is the angular repo use babel and gulp to help it
transpile the code from ES6 to ES5.
You can run gulp serve under angular2-esnext-starter and it will generate one
new folder called dist my screenshot
copy the client folder under that dist folder to node-todo and remember
rename it to public and you will see everything is ok.
so the hint is copy the gulpfile of angular2-esnext-starter and don't forget
to add more dependencies to your package.json should solve your problem.
my workable node-todo

NPM modules in Grunt based projects

Node has a simple module loading system which uses require() method call to load modules from different locations in the root folder.
E.g.
var qr = require('qr-image');
I am trying to do something similar in grunt but i am unsuccessful with that.
I had added this module to package.json file in the following fashion and then ran npm install at root directory of the project.
"devDependencies": {
.
.
.
"qr-image": "^2.0.0"
},
Now whenever I use require I get the following error on console and my code breaks.
ReferenceError: require is not defined
Please suggest as how to use the npm module in Grunt based project, Thanks.
The require function isn't available in web browsers. Instead it's part of nodejs, which is a server-side language (e.g., something you might run directly from your computer terminal, not in a browser) and used to load dependencies in that language.
In a web browser, I usually just include my dependencies as additional scripts on the page, e.g.,:
<script src="path/to/my/dependency.js"></script>
<script src="path/to/my/code.js"></script>
Some other options are RequireJS or what's listed in this question or as more of a general purpose dependency manager for front-end code: Bower.
Looking closer at your question, it's likely that the "qr-image" npm dependency won't work in client-side code for you (since it was built to run via node in server-side code).
A quick search for QR code client-side code brought up this SO post, which points to the QRCode.js project for client-side QR code generation—I haven't used it, but it looks like a step in the right direction for what you're working on.

Categories

Resources