Trying to host a simple nodejs api server on azure app service, but getting the following error when azure tries to deploy it
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: D:\home\site\wwwroot\server.js
require() of ES modules is not supported.
require() of D:\home\site\wwwroot\server.js from D:\Program Files (x86)\iisnode\interceptor.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename server.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from D:\home\site\wwwroot\package.json.
Checked the azure app service, WEBSITE_NODE_DEFAULT_VERSION is set to ~14, and the installed nodejs version is v14.15.0 in the web app. Don't think this version of node has problem with import export anymore.
The code runs perfectly fine locally with either
node server.js
# or
node --experimental-modules server
Not sure why it is failing in azure
My code is below:
server.js
import express from 'express';
import bodyParser from 'body-parser';
let app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
let port = process.env.PORT || 8080;
let router = express.Router();
// Middleware to use for all requests
router.use(function(req, res, next) {
next();
});
router.get('/', function(req, res) {
res.json({ message: 'Default home page for the api!' });
});
app.use('/api', router);
// START THE SERVER
// =============================================================================
app.listen(port);
console.log(`Server up and running on port ${port}`);
package.json
{
"name": "my_package",
"version": "1.0.0",
"type": "module",
"scripts": {
"start": "node --experimental-modules server",
"test": "mocha"
},
"dependencies": {
"body-parser": "^1.19.0",
"express": "^4.17.1"
}
}
However, if I change the import & export to require, then it will run in azure web app, it seems like perhaps azure iisnode is not compatible with emac6 yet? Anyone knows?
Anyone has any work around of this beside using babel to transpile emac6 down to emac5? As I have having some problem with executing and running the transpiled emac5 code.
Thankz
This can be solved by adding a new file next to your server.js and configuring it as the app service's (or more specifically iisnode's) entry point (see your web.config).
Let's call the new file run.cjs and put only the following line into it:
import("./server.js");
The cjs file extension is important because it tells Node that this file is not a ES module, as it would expect because of "type": "module" in your package.json. This allows other CommonJS files to include our new file - namely iisnode's interceptor.js.
It again imports the server.js which then runs fine as ES module.
Add "type": "module" in package.json file. It work for me.
{
"name": "module-error",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"start": "node --experimental-modules server",
"test": "mocha"
},
"dependencies": {
"body-parser": "^1.19.0",
"express": "^4.17.1"
},
"author": "",
"license": "ISC",
"type": "module"
}
Related
I am trying to transpile an ES6 express app using Parceljs.
Trying to run the parcel dev server using yarn parcel index.js displays that it is running at localhost:1234 but the page is blank. It also generates the following output when trying to run node dist/index.js:
index.js:116
throw error;
^
TypeError: Cannot read properties of undefined (reading 'prototype')
Running yarn parcel index.js --target node does not yield any localhost port for me to test the API with. However, the API now works as I can use node dist/index.js to run the script but now I have to resort to npx nodemon /dist/index.js to have file watching.
Here is the sample code.
index.js
import express from "express";
const app = express();
const port = 5000;
app.get("/", (req, res) => {
res.json({ msg: "Hello!" });
});
app.listen(port, () => {
console.log(`Example app listening on port ${port}`);
});
package.json
...
"dependencies": {
"express": "^4.17.3",
"parcel": "^2.3.2",
"parcel-bundler": "^1.12.5"
}
...
I would greatly appreciate a solution that allows me to use Parceljs to watch for file updates directly, preferably with HMR.
See issue 355: Is parcel meant to work with server-side code insluding HMR?: parcel does not (yet) support hot module reloading in nodejs.
parcel creates a web server and serve your code but express need to be called by itself to be able create a web server and server requests.
You'd better use babel & nodemon instead of parcel
I use command bellow
nodemon --exec babel-node src/index.js
I am starting studying Node.js, so I am using nodemon to reload my page, but it's not working and already tried all Stack solutions aswell.
Look how simple is my code:
package.json
{
"name": "api",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "nodemon server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.16.4"
},
"devDependencies": {
"nodemon": "^1.18.3"
}
}
server.js
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hey');
});
app.listen(3001);
My bash while interacting with res.send() message.
You are using nodemon with the server. It is restarting the server as you make changes to the server.js file. That is, your endpoints are being updated. This will not cause your client to reload. As you are simply navigating to the endpoint that you are creating within the browser, you will not see the changes reflected without refreshing.
That isn't to say that there is no benefit to running nodemon in this way. If you were not doing so you would need to also close the node instance (ctrl-c) and then rerun it every time before refreshing the page. Otherwise, you would still be running the old version of your server and still see the same content served.
Eventually you will consume these endpoints using an http client from your client application, this is generally when you take advantage of a hot reloading environment. There are some options here if you want to make express live-reload before then.
As of now, my React app runs on port 3000 via npm start.
I've decided that I want to use MySQL for the web app I'm building via yarn add express mysql.
I made server.js listen in on port 3001.
Whenever I run nodemon server.js and then hit refresh, I'm not seeing test on the front page of my React app (which would indicate that everything works fine).
I can see test if I type localhost: 3001 in my browser but it's completely blank, meaning, I only see test and not the original front page of my web app. It's a whole new different page.
Inside package.json file, I tried to include "proxy":"http://localhost:3001" at the bottom of the file as well as various other places, but it still doesn't work.
How do I make it so that I can see test on the original front page of my web app (port 3000) so I can conclude that everything's working fine and can proceed with integrating MySQL?
Here's my server.js file:
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
app.get('/', (req, res) => {
res.send('test');
});
app.listen(3001, () => {
console.log("listening port 3001");
});
Update
If you don't need to build and try your app in production, meaning you only need to run both of them for development then just use a proxy as suggested in the comments. Run both servers and make requests to your Express API routes on the frontend. You can add a proxy like this in your client's (React part) package.json file.
"proxy": {
"/api/*": {
"target": "http://localhost:3001"
}
}
Then, any request made for /api/* on the frontend goes through your Express server.
For starting both servers at the same time, you can use concurrently. First install it on the server side:
yarn add concurrently
After installing it you add something like this in your scripts part:
"scripts": {
"server": "nodemon index.js",
"client": "npm run start --prefix client",
"dev": "concurrently \"npm run server\" \"npm run client\"",
"prod": "NODE_ENV=production nodemon app.js"
},
I misunderstood your intention at first, this is why I gave an answer like the below one.
This is normal behavior since you haven't configured Express to serve your frontend properly.
First of all, for a React app you don't need any server at all. What you are using right now (on port 3000) is for developing purposes. So, after completing your app you should build it and configure Express to serve it statically.
First, build it:
yarn build
After this step, you will have static files in your client's build directory.
Now, your Express config should be something like this:
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
app.get('/test', (req, res) => {
res.send('test');
});
app.use( express.static( "client/build" ) );
app.get( "*", ( req, res ) =>
res.sendFile( path.resolve( __dirname, "client", "build", "index.html" ) ) );
app.listen(3001, () => {
console.log("listening port 3001");
});
Notice the route change for Express. I changed / with /test. So, when you hit /test you will see what your Express route serves. Other than this route you should see your React app.
Also, don't forget to change those if your setup is different:
client/build
and
path.resolve( __dirname, "client", "build", "index.html" )
This means Express searches a client directory and you React app resides there.
PS: You will only start the Express server, there will be no more server for React since you don't need it to serve with Express.
Also, related part can be enhanced like this:
if ( process.env.NODE_ENV === "production" ) {
app.use( express.static( "client/build" ) );
app.get( "*", ( req, res ) =>
res.sendFile( path.resolve( __dirname, "client", "build", "index.html" ) ) );
}
So, at runtime you can pass an environment variable and Express hits this route only in production.
I am using windows ver 10 home, so I am using "docker toolbox for windows" where my docker client is windows/amd64 and server is linux/amd64.
I have built a very simple nodejs application with three files.
server.js
/**
* Created by farhanx on 7/28/2018.
*/
'use strict';
const express = require('express');
// Constants
const PORT = 5000;
const HOST = 'localhost';
// App
const app = express();
app.get('/', function (req, res) {
res.send('Hello world\n');
});
app.get('/students', function (req, res) {
res.send('student page\n');
});
app.listen(PORT, HOST);
console.log('Running on http://'+HOST+':'+PORT);
and package.json
{
"name": "docker_web_app",
"version": "1.0.0",
"description": "Node.js on Docker",
"author": "First Last <first.last#example.com>",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"dependencies": {
"express": "^4.16.1"
}
}
Docker file
FROM node:8
# Create app directory
WORKDIR /usr/src/app
# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm#5+)
COPY package*.json ./
RUN npm install
# If you are building your code for production
# RUN npm install --only=production
# Bundle app source
COPY . .
EXPOSE 5001
CMD [ "npm", "start" ]
Then I have built my docker image successfully and ran this command
docker run -p 5001:5000 farhan/mynode
since I have mentioned port 5000 for the server inside the nodejs server file and inside the docker file I have exposed the 5001 as a port.
Now it runs fine and shows on the console that the nodejs server is running but whenever I use localhost:5001, it displays page not found. Which means somehow docker container is working fine but is not accessible to the browser.
Exposing a port means you let through request asking for that port. You have to expose the port 5000 and not the 5001.
EXPOSE 5000
Also, you should not set the HOST of your Express app to localhost. If you do this, only localhost (the container) will be able to make request.
Usually, you do not set the host (it defaults to 0.0.0.0 and accepts everything):
app.listen(PORT);
Since you are using toolbox, you have to access app in your browser via http://linux_docker_host_ip:5001.
To know the host ip, go to virtualbox, and see the docker machine's ip address. Normally you will find a network icon on right bottom corner when you click on vm in virtual box. By default the IP is '192.168.99.100'
I have an express server that uses a local json file for a database. I'm using https://github.com/typicode/lowdb for getters and setters.
Currently the server keeps starting and restarting without any problems, but can't access it. Below is my Server.js file:
import express from 'express'
import session from 'express-session'
import bodyParser from 'body-parser'
import promisify from 'es6-promisify'
import cors from 'cors'
import low from 'lowdb'
import fileAsync from 'lowdb/lib/storages/file-async'
import defaultdb from './models/Pages'
import routes from './routes/index.js'
const app = express();
const db = low('./core/db/index.json', { storage: fileAsync })
app.use(cors())
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use('/', routes);
app.set('port', process.env.PORT || 1337);
db.defaults(defaultdb).write().then(() => {
const server = app.listen(app.get('port'), () => {
console.log(`Express running → PORT ${server.address().port}`);
});
});
Anyone have an issue like this before? I think it has something to do with this line:
db.defaults(defaultdb).write().then(() => {
const server = app.listen(app.get('port'), () => {
console.log(`Express running → PORT ${server.address().port}`);
});
});
From the documentation:
nodemon will watch the files in the directory in which nodemon was started, and if any files change, nodemon will automatically restart your node application.
If your db's .JSON file is under the watch of nodemon, and you're constantly writing to it, your server will restart in an infinite loop thus making it inaccessible. Try moving your .JSON file outside the scope of nodemon's watch via moving it outside your directory or via some nodemon configuration (if possible).
I solved this issue from this page.
practically you just have to do
nodemon --ignore 'logs/*'
Update: the link was hijacked and has been removed.
My solution: I've added nodemonConfig in package.json file in order to stop infinite loop/restarting. In package.json:
"nodemonConfig": { "ext": "js", "ignore": ["*.test.ts", "db/*"], "delay": "2" },
"scripts": { "start": "nodemon" }
I was puzzled by a constant stream of restarts. I started with nodemon --verbose to see what was causing the restarts.
This revealed that my package.json file was the culprit. I was running my installation in a Dropbbox folder and had just removed all files from my node_modules folder and done a fresh install. Another computer that shared my Dropbox folder was running at the time, and unknown to me, it was busily updating its node_module files and updating the Dropbox copy of package.json files as it did so.
My solution turned out to be simple, I took a break and waited for Dropbox to finish indexing the node_modules folder. When Dropbox finished synching, nodemon ran without any unexpected restarts.
In my case (which is the same as the OP) just ignoring the database file worked
nodemon --ignore server/db.json server/server.js
You can use this generalized config file.
Name it nodemon.json and put in the root folder of your project.
{
"restartable": "rs",
"ignore": [".git", "node_modules/", "dist/", "coverage/"],
"watch": ["src/"],
"execMap": {
"ts": "node -r ts-node/register"
},
"env": {
"NODE_ENV": "development"
},
"ext": "js,json,ts"
}
I solved this by adding the following code to the package.json file
"nodemonConfig": {
"ext": "js",
"ignore": [
"*.test.ts",
"db/*"
],
"delay": "2"
}
}
Add this in your package.json:
"nodemonConfig": {
"ext": "js",
"ignore": [
"*.test.ts",
"db/*"
],
"delay": "2"
}
I solved this by creating a script in my package.json like this:
scripts": {
"start-continuous": "supervisor server/server.js",
},
This will work if you have supervisor installed in your global scope.
npm install supervisor -g
Now all I do is: npm run start-continuous