Cannot use import statement outside a module with #pusher/push-notifications-web nodejs - beams - node.js

I am trying to follow this tutorial using nodejs and express: https://pusher.com/docs/beams/reference/web/#npm-yarn
First I did: npm install #pusher/push-notifications-web before adding the code.
But when I add this code in the index.js file:
import * as PusherPushNotifications from "#pusher/push-notifications-web";
const beamsClient = new PusherPushNotifications.Client({
instanceId: "<YOUR_INSTANCE_ID_HERE>",
});
beamsClient.start().then(() => {
// Build something beatiful 🌈
});
I get this error:
SyntaxError: Cannot use import statement outside a module
It's also not very clear to me from the tutorial if the code has to be in the frontend or the backend. I tried both but got the same result.
How can I fix this problem?

The error is caused by the fact that you're trying to use ES module specific features in a regular CommonJS file (the default behavior in Node.js). However, what you're looking at is the Web SDK for Pusher which won't help you achieve your goals.
You need the server SDK for Node.js - https://pusher.com/docs/beams/reference/server-sdk-node/.

Verify that you have the latest version of Node.js installed and you have 2 ways of fixing that
Set "type" field with a value of "module" in package.json. This will ensure that all .js and .mjs files are interpreted as ES modules.
// package.json
{
"type": "module"
}
Use .mjs as file extension instead of .js.

Related

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.

Is there a way to import from this node module with 'import' instead of 'require'?

I'm using this node module 'deep-equal' () and so far the only way I've been able to access the function in it is with var equal = require('deep-equal');, as suggested in the documentation. I usually use import instead of require, and am wondering if it's possible to use import with this module. The main function is exported from the file in this line:
var deepEqual = module.exports = function (actual, expected, opts) {...}
Is it possible to import this function with import, or is it only possible with require?
Thanks!
Yes you actually can.
If you're using nodejs LTS then you'll have to use .mjs extension for the file where you're using import and pass experimental-modules flag while running node process.
// foo.mjs
import equal from 'deep-equal';
node --experimental-modules foo.mjs
As of nodejs 12.3.0 you can simply pass the experimental-modules. From docs
Once enabled, Node.js will treat the following as ES modules when passed to node as the initial input, or when referenced by import statements within ES module code
Also you can specify type as module in your package.json:
// package.json
{
"type": "module"
}
From docs
Files ending with .js or .mjs, or lacking any extension, will be loaded as ES modules when the nearest parent package.json file contains a top-level field "type" with a value of "module"

Angular 6 :: Cannot find name 'require'

My project is created using angular cli [ version - 6.1.3 ].
I installed npm module - is-reachable and used it in my code as -
const isReachable = require('is-reachable');
appDetailsFromJson.forEach(app => {
isReachable(app.server).then(reachable => {
console.log('Hey --> ',reachable);
//=> true
});
However, on running the project it throws the exception - error TS2304: Cannot find name 'require'.
What is the root cause for this & what is the correct way to import a library in angular 6 ?
From the NPM page of isReachable it says (my emphasis):
Works in Node.js and the browser (with browserify).
This means that it is unlikely to work natively in an Angular application as the Angular CLI uses webpack and the standard typescript compiler (rather than browserify) to resolve imports and package dependencies.
In general, imports in Angular are standard ES6-style 'import' statements, e.g.:
import { isReachable } from 'is-reachable';
... or ...
import * as isReachable from 'is-reachable';
If is-reachable itself does not use any further require() statements, this may work, but if it uses require within its own code to bring in its dependencies, you would be in for a lot of difficulty in getting it to work at all - and it would almost certainly be better to find a different way to meet your requirement.

how to use node module with es6 import syntax in typescript

I have a typescript project which has uses one of our node modules which normally runs in our front-end. We are now looking to use this module in node on our server.
The module uses es6 import syntax import { props } from 'module/file'
When I include a ref in typescript using either of the following methods
import { props } from 'module/file';
var props = require('module/file');
I get the following error from typescript
unexpected token 'import'
(function (exports, require, module, __filename, __dirname) { import
It's a big job to re-write the module, and I've tried using babel with babel-plugin-dynamic-import-node, as well as SystemJS.
The problem with these systems is that they are all asynchronous, so I can't import the module in the standard fashion, so I would need to do a whole bunch of re-write when we get to the point that I can use import natively in node.js.
I can't be the first person to have this issue, but I can't seem to find a working solution.
--------------- update with set-up -------------
In response to #DanielKhoroshko's response. The original module I am trying to import is normally packaged by webpack in order to use on the front-end. I am now trying to use this same module both server-side and in the front-end (via webpack on the front-end) without re-writing the imports to use require and without running webpack to bundle the js to use on the server.
To be clear, the original module is written in JS, our service which is trying to use this module is written in typescript and transpiled. When the typescript tries to require the old module which uses import, it is at this point that we are running into the issue.
------------------ some progress ---------------------------
I've made some progress by creating a file in my imported module which uses babel in node.js to transpile the es6 code into commonJS modules.
I've done this via
var babel = require("babel-core")
var store = babel.transformFileSync(__dirname + '/store.js', {
plugins: ["transform-es2015-modules-commonjs"]
});
module.exports = {
store: store.code
}
I can now get the store in my new node.js project. However, the submodules within the store.js file are not included in the export.
So where in my module, it says
import activities from './reducers/activities';
I now get an error
Cannot find module './reducers/activities'
How can I get babel to do a deep traversal to include the sub-directories?
unexpected token 'import' means you are running es-modules code in environment that doesn't support import/export commands. If you are writing you code in TypeScript it's important to transpile it first before building for the browser or use ts-node to run it server-side.
If you are using webpack there are loaders ts-loader and awesome-typescript-loader
What is your setup?
To describe the module you would need to create an activities.d.ts file in the same folder where the js-version (I understood it is called activities.js and containers a reducer) resides with the following (approx.):
import { Reducer } from 'redux';
export const activities: Reducer<any>;
#Daniel Khoroshko was right in many ways, I ended up finding #std/esm which lets you import es6 modules and worked find for fetching the included imports as well.
var babel = require('babel-register')({
presets: ["env"]
});
require = require('#std/esm')(module);
var store = require('ayvri-viewer/src/store');
exports.default = {
store: store
}
I had to run babel to get a consistent build from es6 to node compatible es5

How to use Webpack loaders in a Node app?

Is there a way to use Webpack loaders in a Node app / Run a Node app in a Webpack environment?
For instance I've got a webpack config that has a style-loader. In my Node app I do the following:
import style from 'style.css'
console.log(style.someClass)
I wanna run it like $ node app.js
I've got an idea that might work, based on the Webpack NodeJS API. What if we put the code that we want to be able to use the Webpack environment (with the configured module loaders) into a module:
appModule.js:
import style from 'style.css'
console.log(style.someClass)
And require it with the following:
app.js:
import Webpack from 'webpack'
import MemoryFS from 'memory-fs'
...
webpackConfig.entry = 'appModule.js'
webpackConfig.output = 'appModule-out.js'
let compiler = Webpack(webpackConfig)
let mfs = new MemoryFS()
compiler.outputFileSystem = mfs
compiler.run(function (err, stats) {
require(webpackConfig.output)
})
Probably it won't work because the require looks for the output on the physical FS... Can we require from the memory FS? I have not tried it yet - Any idea?
Webpack loaders aren't transpilers or interpreters, they simple gather assets that are then handled off to something like SASS or a text concatenator; within the confines of Webpacks environment.
Thus it is not possible to reuse them in the way you want, because while you can of course import and call them (they're still just functions + classes), they don't convert CSS to JSON objects (they don't do this) as you have written in your desired example.
It looks like you just need a JS implementation of a css parser - have a look at https://github.com/reworkcss/css
You should be able to create a compilation targeting the node environment which you can ultimately run by simply calling node output.js and this will immediately execute the entry point module.
Be aware, in case that you're using a newer version of Node.js, that Webpack doesn't support the ES2015 module syntax, so you'll have to configure Babel for Node.js as well to transform the modules.

Resources