[ ] typescript
Is the bug related to documentation in
Describe the bug
I am using Node 14.5.0 with a default Express.JS installation. I need to leverage the Azure SDK for Node using Imports and have changed the default express require from:
const express = require('express')
to:
import express from 'express';
Express is able to load, but when I add the example SDK for authorization (https://github.com/Azure/azure-sdk-for-js/tree/master/sdk/authorization/arm-authorization) it is throwing the following error:
import { AuthorizationManagementClient, AuthorizationManagementModels, AuthorizationManagementMappers } from "@azure/arm-authorization"; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SyntaxError: The requested module '@azure/arm-authorization' is expected to be of type CommonJS, which does not support named exports. CommonJS modules can be imported by importing the default export. For example: import pkg from '@azure/arm-authorization'; const { AuthorizationManagementClient, AuthorizationManagementModels, AuthorizationManagementMappers } = pkg; at ModuleJob._instantiate (internal/modules/esm/module_job.js:98:21) at async ModuleJob.run (internal/modules/esm/module_job.js:137:5) at async Loader.import (internal/modules/esm/loader.js:162:24)
I have already added "type": "module", to my package.json and installed the modules listed in the Azure SDK page.
My App.JS page is as follows:
import express from 'express';
import * as msRest from "@azure/ms-rest-js";
import * as msRestAzure from "@azure/ms-rest-azure-js";
import * as msRestNodeAuth from "@azure/ms-rest-nodeauth";
import { AuthorizationManagementClient, AuthorizationManagementModels, AuthorizationManagementMappers } from "@azure/arm-authorization";
const subscriptionId = process.env["myguideforsubhere"];
const app = express()
const port = 5000
app.get('/', (req, res) => res.send('Hello World!'))
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
msRestNodeAuth.interactiveLogin().then((creds) => {
const client = new AuthorizationManagementClient(creds, subscriptionId);
client.classicAdministrators.list().then((result) => {
console.log("The result is:");
console.log(result);
});
}).catch((err) => {
console.error(err);
});
My Package.json is as follows:
{
"name": "myproject",
"version": "1.0.0",
"description": "myproject",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Me",
"license": "ISC",
"dependencies": {
"@azure/arm-authorization": "^8.3.2",
"@azure/ms-rest-nodeauth": "^3.0.5",
"express": "^4.17.1"
},
"type": "module"
}
To Reproduce
Steps to reproduce the behavior:
Expected behavior
A clear and concise description of what you expected to happen.
I expected the interactive login to prompt.
Screenshots
If applicable, add screenshots to help explain your problem.
Additional context
Add any other context about the problem here.
Thanks for reporting @kellyjjrusk
@joheredi, Can you take a look at this since this could be a common problem with any generated package?
I just landed here googling the same issue but with express.
You got that error because azure-sdk-for-js doesn't have "type": "module" in it's paackage.json. Which means node treats it as a commonjs module and not es6 module.
It has nothing to do with "type": "module" in your own project as it is scope based.
Solution:
Is it possible to es6 import a commonjs module?
import { method } from 'commonjs-package'; // Errors
import packageMain from 'commonjs-package'; // Works
Thanks for that insight. When I changed it to the following, it was able to get past the error:
import pkg from '@azure/arm-authorization';
const { AuthorizationManagementClient, AuthorizationManagementModels, AuthorizationManagementMappers } = pkg;
However, it now fails on:
msRestNodeAuth.interactiveLogin().then((creds) => {
^
TypeError: msRestNodeAuth.interactiveLogin is not a function
at file:///home/myproject/app.js:30:16
at ModuleJob.run (internal/modules/esm/module_job.js:140:23)
at async Loader.import (internal/modules/esm/loader.js:162:24)
I am wondering if these are related errors due to importing. A bit of a noob question re: TypeScript, but do I need to install TypeScript in my node project as well?
I didn't use typescript before, but quick googling told me to install it using npm i -D typescript
I suggest you to look for some tutorial on it if you are new to typescript.
Thanks. I looked at the same and have taken a few tutorials. I was more wondering if TypeScript is required/a dependency for running the Azure SDK for Node.
@kellyjjrusk Typescript is not a required dependency for the Azure SDK. You should be able to import the libraries as @AndeYashwanth suggested. Looking at your current error, and your initial post it looks like it may be caused by the msRestNodeAuth import. Can you try with the following imports?
import express from 'express';
import armAuthorization from "@azure/arm-authorization";
import msRest from "@azure/ms-rest-js";
import msRestAzure from "@azure/ms-rest-azure-js";
import msRestNodeAuth from "@azure/ms-rest-nodeauth";
Unfortunately we don't support native ESM yet, and that is the reason why named imports don't work with Javascript + Node.
To be able to use named imports, the code would need to be transpiled into cjs using e.g. Babel or Typescript.
The samples in the README.md on this package are written in Typescript, so they won't run in Javascript. I'll send out a PR to update the sample.
Thank you for the detailed response and education on the reasons why. When attempting the straight froms you recommended, the authorization fails after devicelogin:
ReferenceError: AuthorizationManagementClient is not defined
at file:///home/myproject/app.js:35:20
at processTicksAndRejections (internal/process/task_queues.js:93:5)
I got around this by changing this:
import armAuthorization from "@azure/arm-authorization";
to this:
import armAuthorization from "@azure/arm-authorization";
const { AuthorizationManagementClient, AuthorizationManagementModels, AuthorizationManagementMappers } = armAuthorization;
However, after devicelogin, it can't find the subscription despite being declared as a constant. If I add my sub ID directly into the msRestNodeAuth.interactiveLogin() call it works, but not as setup with the const which is supposed to pass in the value (and does in the older version for Node Auth):
Error: 'subscriptionId' cannot be null.
at AuthorizationManagementClientContext [as constructor] (/home/myproject/node_modules/@azure/arm-authorization/dist/arm-authorization.js:2587:23)
at new AuthorizationManagementClient (/home/myproject/node_modules/@azure/arm-authorization/dist/arm-authorization.js:2632:32)
at file:///home/myproject//app.js:12:18
at processTicksAndRejections (internal/process/task_queues.js:93:5)
Here is my app.js. Hope this helps:
import express from 'express';
import msRest from "@azure/ms-rest-js";
import msRestAzure from "@azure/ms-rest-azure-js";
import msRestNodeAuth from "@azure/ms-rest-nodeauth";
import armAuthorization from "@azure/arm-authorization";
const { AuthorizationManagementClient, AuthorizationManagementModels, AuthorizationManagementMappers } = armAuthorization;
const subscriptionId = process.env["mysubguidadded"];
const app = express()
const port = 5000
msRestNodeAuth.interactiveLogin().then((creds) => {
const client = new AuthorizationManagementClient(creds, subscriptionId);
client.classicAdministrators.list().then((result) => {
console.log("The result is:");
console.log(result);
});
}).catch((err) => {
console.error(err);
});
app.get('/', (req, res) => res.send('Hello World!'))
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
process.env["mysubguidadded"]; is trying to find mysubguidadded in your environment variables. There are 2 options to have it working
1) in your console set the environment variable
windows
> SET myguideforsubhere=testId
> echo %myguideforsubhere%
# output testId
linux/mac
$ export myguideforsubhere=testId
$ echo $myguideforsubhere
# output testId
After setting the variable const subscriptionId = process.env["mysubguidadded"]; should be able to grab it
2) Using a package such as dotenv https://www.npmjs.com/package/dotenv. Allows you to easily save and access your values in a .env file
Let me know if this works!
That makes complete sense. Appreciate all the sharing and opening a PR for the documentation updates. I am closing this as the needs are met.
Unfortunately we don't support native ESM yet
If it helps, I've just published a sample package written in TypeScript, with dual exports: native ESM, and CommonJS. By using conditional exports, the code can be name-imported from TypeScript as well, avoiding the The requested module '...' is expected to be of type CommonJS, which does not support named exports error.
The package is local-iso-dt, and this is the diff that adds supports for conditional exports.
Most helpful comment
I just landed here googling the same issue but with express.
You got that error because
azure-sdk-for-jsdoesn't have"type": "module"in it's paackage.json. Which means node treats it as a commonjs module and not es6 module.It has nothing to do with
"type": "module"in your own project as it is scope based.Solution:
Is it possible to es6 import a commonjs module?