Webpack - Reading from "node:XXX" is not handled by plugins - node.js

I've got a typescript project that I'm building using Webpack. I'm fairly new to web development in general, so forgive me if my terminology isn't always correct.
I'm trying to use the following npm package: https://www.npmjs.com/package/nodewikiaapi
Here are the steps that I followed (I've also done much troubleshooting an tried many webpack configuration changes with no luck):
install the package via npm install --save-dev nodewikiaapi
include it in my TS file like so: import WikiaAPI from 'nodewikiaapi'
try to compile, and I get a few instances of the the following error (or similar, with different variations on "node:XXX"):
Module build failed: UnhandledSchemeError: Reading from "node:zlib" is not handled by plugins (Unhandled scheme).
Webpack supports "data:" and "file:" URIs by default.
You may need an additional plugin to handle "node:" URIs.
at C:\Users\carso\Documents\Programming\TolkienExplorer_Web\node_modules\webpack\lib\NormalModule.js:832:25
at Hook.eval [as callAsync] (eval at create (C:\Users\carso\Documents\Programming\TolkienExplorer_Web\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:6:1)
at Object.processResource (C:\Users\carso\Documents\Programming\TolkienExplorer_Web\node_modules\webpack\lib\NormalModule.js:829:8)
at processResource (C:\Users\carso\Documents\Programming\TolkienExplorer_Web\node_modules\loader-runner\lib\LoaderRunner.js:220:11)
at iteratePitchingLoaders (C:\Users\carso\Documents\Programming\TolkienExplorer_Web\node_modules\loader-runner\lib\LoaderRunner.js:171:10)
at runLoaders (C:\Users\carso\Documents\Programming\TolkienExplorer_Web\node_modules\loader-runner\lib\LoaderRunner.js:398:2)
at NormalModule._doBuild (C:\Users\carso\Documents\Programming\TolkienExplorer_Web\node_modules\webpack\lib\NormalModule.js:819:3)
at NormalModule.build (C:\Users\carso\Documents\Programming\TolkienExplorer_Web\node_modules\webpack\lib\NormalModule.js:963:15)
at C:\Users\carso\Documents\Programming\TolkienExplorer_Web\node_modules\webpack\lib\Compilation.js:1371:12
at NormalModule.needBuild (C:\Users\carso\Documents\Programming\TolkienExplorer_Web\node_modules\webpack\lib\NormalModule.js:1253:32)
# ./node_modules/node-fetch/src/index.js 11:0-29 297:11-28 298:17-34 303:22-39 325:24-42 331:24-45 354:22-49
# ./node_modules/nodewikiaapi/src/main.js 3:0-30 201:29-34
# ./static/src/index.ts 4:0-36 39:24-32
I've tried many things, including installing the node-polyfill-webpack-plugin and then including the following in my webpack.config.js:
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
module.exports = {
// Other rules...
plugins: [
new NodePolyfillPlugin()
]
};
It's very possible that I've been missing some key detail though.
Do I need to change my import statement? import WikiaAPI from 'nodewikiaapi'
Do I need to add some sort external to my webpack config?
Do I need to include the node plugin in webpack differently?
Something else altogether?

Related

Node JS (cpanel) Error: I'm getting an error [ERR_REQUIRE_ESM]: Must use import to load ES Module

So, I've spent quite a few hours today trying to put my nodeJS app that's fully using ESM (modules), and I've deployed it via cPanel on a server that's using Node v. 14.20.1. I'm constantly getting an error:
App 1153856 output: internal/modules/cjs/loader.js:948
App 1153856 output: throw new ERR_REQUIRE_ESM(filename);
App 1153856 output: ^
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /<serverlocation>/app.js
App 1153856 output: at new NodeError (internal/errors.js:322:7)
App 1153856 output: at Module.load (internal/modules/cjs/loader.js:948:11)
App 1153856 output: at Function.Module._load (internal/modules/cjs/loader.js:790:12)
App 1153856 output: at Module.require (internal/modules/cjs/loader.js:974:19)
App 1153856 output: at Module.require (/opt/cpanel/ea-ruby27/root/usr/share/passenger/helper-scripts/node-loader.js:80:25)
All files are written as modules, I don't have one "require()" anywhere.
Since the Node started fully supporting JS modules from v14 on, I'm taking a wild guess that the hosting server I'm using (and their Passenger for NodeJS) is using a loader that's using "require()" when calling my app.js file.
I've tried multiple solutions, I've even switched my app.js file to a CommonJS type, but then it required me to switch all other files to CJS as well, which would be too much hassle.
Has anyone managed to find a proper solution to this issue?
For anyone trying to solve this issue, this is how I solved it:
1- Create a loader script: Not necessarily in the same folder as the main app.js file of your app, but that's where I created it. Call it something like loader.cjs. The extension being .cjs is important if you have "type": "module" in your package.json.
As you might've guessed, this will be the new main of your app. Since the passenger's loaders have an issue with ES modules, just let it load a commonjs file instead.
2- Dynamic import of app.js: Did you know that you can still load ES modules in commonjs files? You just need a little extra bit to do so.
Apparently, ES modules are loaded asynchronously, and this doesn't work well with synchronous commonjs files. That's why you got the issue in the first place, right?
Therefore, the solution is: dynamic imports. Just like async functions, treat the imports of ES modules as promises. I don't really like using .then(), so I opted with await:
async function loadApp() {
await import("/path/to/app.js");
}
loadApp();
3- Rename your app.js's extension: I don't exactly know why this is necessary, but I got error along the lines of "couldn't find /path/to/app.mjs" and so I changed it to so. Then it worked. You can keep the name of the file as "app.js" in the path in the previous point, and the import will sstill correctly look for "app.mjs";
There might be more efficient ways to do this, but that's what my 2 bits of brain could come up with. Hopefully it helps others as well.

Importing JSX with ESM Dynamic Imports in Node.js

Summary of problem
I'm exclusively using ESM in my Node.js project and trying to find a way to dynamically import JSX.
I'm making a custom static site generator for my website and want to render React components to markup with renderToStaticMarkup(), but to achieve this, I first need to successfully import the components to then run this method.
Does anyone know a way to dynamically import JSX in ESM Node.js?
I.e., to make await import("./jsxComponent.js") work?
A few things I've tried
Approach 1: Direct attempt
When I dynamically import the .js file containing the component, I receive the error message: SyntaxError: Unexpected token '<'. Seems import() cannot parse JSX out of the box.
If I change the file extension of the .js file to .jsx, I unsurprisingly receive the error message Unknown file extension ".jsx".
Approach 2: Babeling
Back in the CommonJS heyday of Node.js, I'd use #babel/register, #babel/preset-env, and #babel/preset-react in a separate file with its last line invoking require() on another .js file that, inside itself, would then require() the component. I'm not entirely clued up on how each Babel preset or plugin works, but this did the trick back then allowing me to require() components to then render them to markup. Unfortunately, this doesn't work when using ESM-only packages in an ESM-only project because the moment I use #babel/register my ESM-only packages complain and break.
I've tried using #babel/core to transform the file before it's invoked inside import(). I've done this by using the transformFileSync method, but this created the error message: Error [ERR_MODULE_NOT_FOUND]: Cannot find package '"use strict". Inside the options object of transformFileSync I used babel-plugin-dynamic-import-node as a plugin and #babel/register, #babel/preset-env, and #babel/preset-react as presets.
I've tried also using #babel/core's transformSync method by passing in the JSX code directly (rather than just the file path of the JSX-containing file), and this created the error message: Error: ENOENT: no such file or directory, open 'import Header from "./src/components/header.js"; (note: there IS a file at ./src/components/header.js - it is one of the components being imported inside another component.)
Approach 3: Require
Other approaches online recommend using require() instead of import(), but as I said, this is an ESM-only project using ESM-only packages and so the error message I receive when trying this is require is not defined, as one would expect.
Code examples
Approach 1: Direct attempt
const module = await import("./jsxComponent.js")
Approach 2: Babeling
const module = await import(
babelCore.transformFileSync("./jsxComponent.js", {
presets: [
"#babel/preset-env",
[
"#babel/preset-react",
{
runtime: "automatic",
},
],
],
plugins: ["dynamic-import-node"],
}).code
);
(Let me know if you want me to post any more code examples from my tests with Babel).
Approach 3: Require
const module = require("./jsxComponent.js")
I was able to import JSX in my ESM-only project by:
Installing #node-loader/babel (see GitHub repo)
Installing #babel/core and #babel/preset-react
Creating babel.config.js in my root directory with the following setup:
export default {
presets: [
[
"#babel/preset-react",
{
runtime: "automatic",
},
],
],
};
Then running my node build script with the node loader set as an experimental loader: node --experimental-loader #node-loader/babel ./lib/build.js
I was then able to successfully use const component = await import("./jsxComponent.js") in my node build scripts and pass the component to reactDOMServer's renderToStaticMarkup(component()) method by invoking it as a function.

Express application crashes when it is built with webpack

I am trying to use graphql-upload in a typescript express app (graphql api) built with webpack. When I run with ts-node my app works fine. But when I compile with webpack and then run I get a weird error when I try to upload a file.
My setup
Typescript app
Apollo server / Typegraphql
Build with webpack
My Code
(stripped down to the essentials)
https://github.com/ziggy6792/graphql-file-uploads
My Problem
When I run with ts-node yarn start:ts:node then run yarn test an image gets uploaded no problem
But then I build with webpack yarn start then run yarn test I get the following error
/Users/sive/Documents/workspace/graphql-file-uploads/dist/index.js:56105
if (!isObject(operations) && !Array.isArray(operations))
^
TypeError: isObject is not a function
at Busboy.<anonymous> (/Users/sive/Documents/workspace/graphql-file-uploads/dist/index.js:56105:18)
at Busboy.emit (node:events:378:20)
at Busboy.module.exports../node_modules/busboy/lib/main.js.Busboy.emit (/Users/sive/Documents/workspace/graphql-file-uploads/dist/index.js:32204:33)
at PartStream.onEnd (/Users/sive/Documents/workspace/graphql-file-uploads/dist/index.js:32528:15)
at PartStream.emit (node:events:390:22)
at Dicer.onPart (/Users/sive/Documents/workspace/graphql-file-uploads/dist/index.js:32386:13)
at Dicer.emit (node:events:378:20)
at Dicer.module.exports../node_modules/dicer/lib/Dicer.js.Dicer.emit (/Users/sive/Documents/workspace/graphql-file-uploads/dist/index.js:45439:35)
at Dicer.module.exports../node_modules/dicer/lib/Dicer.js.Dicer._oninfo (/Users/sive/Documents/workspace/graphql-file-uploads/dist/index.js:45540:12)
at SBMH.<anonymous> (/Users/sive/Documents/workspace/graphql-file-uploads/dist/index.js:45486:10)
[nodemon] app crashed - waiting for file changes before starting...
My Attempts to solve
I am not sure if this actually a problem with graphql-upload or webpack or something else. I also noticed that my issue looks similar to this issue, but I didn't really understand if there were any fixes to that issue and if indeed it is the same issue I am facing.
I tried to upgrade webpack (branch upgraded-packages) but this made the problem worse as I get this issue when I start the server
TypeError: Cannot read property 'graphql' of undefined
at getPeerDependencyGraphQLRequirement (/Users/sive/Documents/workspace/graphql-file-uploads/dist/index.js:104216:44)
at Object.ensureInstalledCorrectGraphQLPackage (/Users/sive/Documents/workspace/graphql-file-uploads/dist/index.js:104221:32)
at Function.checkForErrors (/Users/sive/Documents/workspace/graphql-file-uploads/dist/index.js:103346:27)
at Function.generateFromMetadataSync (/Users/sive/Documents/workspace/graphql-file-uploads/dist/index.js:103325:14)
at Function.generateFromMetadata (/Users/sive/Documents/workspace/graphql-file-uploads/dist/index.js:103315:29)
at Object.buildSchema (/Users/sive/Documents/workspace/graphql-file-uploads/dist/index.js:103940:61)
at /Users/sive/Documents/workspace/graphql-file-uploads/dist/index.js:99831:41
at Generator.next (<anonymous>)
at /Users/sive/Documents/workspace/graphql-file-uploads/dist/index.js:99819:71
at new Promise (<anonymous>)
Any help would be greatly appreciated.
My best guess at the problem
From reading the linked issue it seems like isObject seems to ship ECMA Script modules with a newer version. Webpack might pick the ES modules version, but this version differs in the sense that the default export is now default and Apollo Server would have to import it as such or call isObject.default. In this changelog they say it might be breaking for users using bundlers.
Your two options now:
You could use yarn force the dependency to a previous version of isobject:
{
...
"resolutions": {
"graphql-file-uploads/isobject": "3.0.1"
}
}
Or you could simply not bundle your app and use TypeScript for building instead. You lose the benefits of bundling, but you are using an environment that is much more common for running node apps. Furthermore you will use TypeScript as a compiler just like ts-node unifying your development and production tooling.
You can compile using TypeScript like this:
yarn tsc 'src/**/*.ts'
In your TSConfig you should configure the output so that it also emits files to /dist.

node module googleapis causes issues

I wanted to start using Google Authentication in my nodejs webapp am using the googleapis package.
The moment I require this package after installing it, I immediately get the following error:
protocol sync?8d88:2 Uncaught Error: Cannot find module './framer'
at webpackEmptyContext (eval at ./node_modules/http2/lib/protocol sync recursive (app.js:1053), <anonymous>:2:10)
at Array.map (<anonymous>)
at eval (index.js?1fa7:46)
at Object../node_modules/http2/lib/protocol/index.js (chunk-vendors.js:7788)
at __webpack_require__ (app.js:854)
at fn (app.js:151)
at Object.eval (http.js?4679:136)
at eval (http.js:1264)
at Object../node_modules/http2/lib/http.js (chunk-vendors.js:7711)
at __webpack_require__ (app.js:854)
I've looked into the source here:
var modules = ['./framer', './compressor', './flow', './connection', './stream', './endpoint'];
modules.map(require).forEach(function(module) {
for (var name in module.serializers) {
exports.serializers[name] = module.serializers[name];
}
});
And confirmed that those files are present:
I've already tried to reinstall the packages (http2 & googleapis) but no change.
Why would those relative require statements fail? The files are clearly present.
My webapp is a client-server app using vue. Also note that this is my first little project using node so if you need any additional information on this issue from me just let me know.
Thanks in advance for the help.
I also faced this issue while trying to make googleapis lib work in React app. Reason is googleapis is recommended for server-side web apps.
For React/Client side web apps, I made it work following this documentation.
https://developers.google.com/identity/protocols/oauth2/javascript-implicit-flow#js-client-library

Sails.js/Condolidate/Twig Error

I'm getting the following error when I request a view in Sails that is using Twig.js:
error: Sending 500 ("Server Error") response:
TypeError: engine is not a function
at /usr/lib/node_modules/sails/node_modules/consolidate/lib/consolidate.js:479:61
at /usr/lib/node_modules/sails/node_modules/consolidate/lib/consolidate.js:143:5
at Promise._execute (/usr/lib/node_modules/sails/node_modules/bluebird/js/release/debuggability.js:300:9)
at Promise._resolveFromExecutor (/usr/lib/node_modules/sails/node_modules/bluebird/js/release/promise.js:483:18)
at new Promise (/usr/lib/node_modules/sails/node_modules/bluebird/js/release/promise.js:79:10)
at promisify (/usr/lib/node_modules/sails/node_modules/consolidate/lib/consolidate.js:136:10)
at Function.exports.twig.render (/usr/lib/node_modules/sails/node_modules/consolidate/lib/consolidate.js:473:10)
at /usr/lib/node_modules/sails/node_modules/consolidate/lib/consolidate.js:164:27
at /usr/lib/node_modules/sails/node_modules/consolidate/lib/consolidate.js:98:5
at tryToString (fs.js:456:3)
at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:443:12)
I've tried to fix this many different ways, but I'm still getting the error. I understand Sails should allow me to use anything supported by Consolidate.js, but it just isn't working.
I have:
cleared the NPM cache
installed Twig.js (v1.10.4) using NPM, and it's in my package.json
Removed and reinstalled twig
set the engine to 'twig' in config/views.js
This is a fresh Sails project without any other customizations or additions.
I'm a little new to node and sails, any help is appreciated!
Looks like there's a bug with the Sails v0.12.x handling of Twig. The easiest workaround is to install Consolidate yourself as a dependency of your project:
npm install --save consolidate
and then in your config/views.js do:
engine: {
ext: 'twig',
fn: require('consolidate').twig
}

Resources