I state that I am a beginner with this type of development, so if there are some stupid errors I apologize in advance. I created an Express.js server to use as base for my service, here the settings and the code:
{
"name": "nodejstrial",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "nodemon src/index.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"#kafkajs/confluent-schema-registry": "^3.3.0",
"body-parser": "^1.20.1",
"ejs-mate": "^4.0.0",
"events": "^3.3.0",
"express": "^4.18.2",
"kafka-node": "^5.0.0",
"kafkajs": "^2.2.2",
"morgan": "^1.10.0",
"node-fetch": "^3.3.0",
"socket.io": "^4.5.3",
"tiny-json-http": "^7.4.2"
},
"devDependencies": {
"nodemon": "^2.0.20"
}
}
const express = require('express');
const engine = require('ejs-mate');
const path = require('path');
const {consumeMessage}= require('./consumer')
const port = 3000;
// Initializiation
const app = express();
//Settings
app.engine('ejs',engine);
app.set('view engine','ejs');
app.set('views',path.join(__dirname,'views'));
app.set('src',__dirname);
app.use(express.json())
//Routes
app.use(require('./routes/'));
// static-files
app.use(express.static(path.join(__dirname,'static')))
// Starting server
app.listen(port,() =>{
console.log('APP started at http://localhost:'+port);
consumeMessage()
})
The directory structure is the following:
.
├── src
│ ├── routes
│ │ └── index.js
│ ├ static
│ │ ├── css
│ │ ├── favicon.ico
│ │ ├── images
│ │ └── js
│ │ └── main.js
│ └── views
│ │ └── index.ejs
│ │
│ └── consumer.js
│ └── index.js
Practically the program listen to a Kafka broker using KafkaJS, when a message arrive it will generate a server-sent event that should trigger the creation of a marker in the map.
This is the code of the consumer.js:
const { Kafka } = require('kafkajs')
const router =require('./routes/index')
const fetchP = import('node-fetch').then(mod => mod.default)
const fetch = (...args) => fetchP.then(fn => fn(...args))
var bodyParser = require('body-parser')
var jsonParser = bodyParser.json()
var url_marker = 'http://localhost:3000/topic/bleLocalization'
const username = ''
const password = ''
const brokers = ['BROKER_LINK']
const clientId = 'mapConsumer'
const groupId = 'mapApplication'
const topic = 'bleLocalization'
let body={data:'start'};
const sasl = username && password ? { username, password, mechanism: 'plain' } : null
const ssl = !!sasl
const kafka = new Kafka({ clientId, brokers /*ssl sasl*/ })
const consumer = kafka.consumer({groupId:groupId })
router.get('/topic/bleLocalization',jsonParser, function (req,res){
console.log(body)
res.set({
'Cache-Control': 'no-cache',
'Content-Type': 'text/event-stream',
'Connection': 'keep-alive'
});
res.flushHeaders();
res.write('data: '+body+'\n\n');
})
const consumeMessage = async () => {
await consumer.disconnect();
await consumer.connect()
await consumer.subscribe({topic:topic,fromBeginning: true})
await consumer.run({
eachMessage: async ({ topic, partition, message }) => {
console.log('received message')
try {
body = JSON.stringify(JSON.parse(message.value))
try{
const response = await fetch(url_marker, {
method: 'get',
headers: { 'Cache-Control': 'no-cache',
'Content-Type': 'text/event-stream',
'Connection': 'keep-alive'}
});
}catch (e) {
console.log(e)
}
} catch (e) {
await console.error('unable to handle incoming message', e);
}
},
})
// await consumer.disconnect()
}
module.exports.consumeMessage = consumeMessage
To do this in the consumer at the begin I initialize a variable
let body={data:'start'};
That everytime a message arrives it is overwrited. I think that there is a better approach but for the moment this workaroud works.
The code till here is able to generate events, the problem arise in the interaction with the static javascript main.js. Each events will bring data that I will use to print proper stuffs on leaflet map
const url= 'http://localhost:3000/topic/bleLocalization';
var source1 = new EventSource(url);
//Attach a listener to the responses triggered by the source
source1.onmessage= function(e) {
console.log("MESSAGE")
//Snippet of code launched each time an event arrive
// MSG FORMAT [{'floor':int,'x':int,'y':int,'id':String},...]
let array = JSON.parse(e.data);
// DO STUFF WITH ARRAY
};
For sake of completeness I put also the code of the index.ejs
<html>
<head>
<meta charset="utf-8">
<!-- LEAFLET -->
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.9.3/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet#1.9.3/dist/leaflet.js"></script>
<!-- END LEAFLET -->
<link rel="apple-touch-icon" sizes="57x57" href="/favicon.ico/apple-icon-57x57.png">
<meta name="theme-color" content="#ffffff">
<title>Live Map</title>
<!-- <link rel ="stylesheet" href="/css/main.css" -->
</head>
<body>
<h1>Live Map</h1>
<!-- LEAFLET -->
<script src="https://unpkg.com/leaflet#1.9.3/dist/leaflet.js">
</script>
<div id="map-template" class="leaflet-container leaflet-touch leaflet-fade-anim leaflet-grab leaflet-touch-drag leaflet-touch-zoom __web-inspector-hide-shortcut__"
style = "width:1700px; height:750px;"></div>
<script src="/socket.io/socket.io.js"></script>
<script type="module" src="/js/geoFences.js"></script>
<script type="module" src="/js/main.js"></script>
<!-- END LEAFLET -->
</body>
</html>
EDIT
The idea is to have similar result tha I have with a Flask server:
WEB_HOST = '0.0.0.0'
PORT = 5000
def get_kafka_client():
return KafkaClient(hosts='BROKER')
app = Flask(__name__)
#app.route('/')
def index():
return(render_template('index.html'))
#Consumer API
#app.route('/topic/<topicname>')
def get_messages(topicname):
client = get_kafka_client()
def events():
for item in client.topics[topicname].get_simple_consumer():
yield 'data:{0}\n\n'.format(item.value.decode())
return Response(events(), mimetype="text/event-stream")
For getting data from KafkaJS, to the response, you should not be using global variables across async functions.
Pass the response object into your consumer. For example,
const consumer = kafka.consumer({ groupId })
router.get('/topic/bleLocalization',jsonParser, async function (req,res) {
res.set({
'Cache-Control': 'no-cache',
'Content-Type': 'text/event-stream',
'Connection': 'keep-alive'
});
res.flushHeaders();
// ideally, you would extract the topic name from the path
await consumeMessage('bleLocalization', res);
})
const consumeMessage = async (topic, res) => {
await consumer.disconnect();
await consumer.connect()
await consumer.subscribe({topic,fromBeginning: true})
await consumer.run({
eachMessage: async ({ topic, partition, message }) => {
console.log('received message');
try {
const body = JSON.parse(message.value);
res.write(JSON.stringify({'data' : body}) + '\n');
Keep in mind that this will run forever (until the consumer disconnects and throws an error)
Then,in the frontend code, at least do console.log(array) in your message listener to actually see the message data (but, it should be an object, not an "array" since you have an object with one key of data). Otherwise, only write body if the data in the topic is a JSON array
Related
I'm building a server-side rendered website with Node. I want to display a green alert box upon successfully updating data in updateSettings.js. Even though the user data (name and email) is updated on Compass correctly, I get a red alert box (error) with undefined as the message. In the browser console, I get a 'bad request' error from bundle.js.
Also, no code seems to run after the Axios PATCH request code
updateSettings.js
/* eslint-disable */
import axios from 'axios';
import { showAlert } from './alerts';
export const updateData = async (name, email) => {
try {
const res = await axios({
method: 'PATCH',
url: 'http://127.0.0.1:3000/api/v1/users/updateMe',
data: {
name,
email,
},
});
if (res.data.status === 'success') {
showAlert('success', 'Data updated successfully!');
}
} catch (err) {
showAlert('error', err.response.data.message);
}
};
Alerts.js
/* eslint-disable */
export const hideAlert = () => {
const el = document.querySelector('.alert');
if (el) el.parentElement.removeChild(el);
};
// type is 'success' or 'error'
export const showAlert = (type, msg) => {
hideAlert();
const markup = `<div class="alert alert--${type}">${msg}</div>`;
document.querySelector('body').insertAdjacentHTML('afterbegin', markup);
window.setTimeout(hideAlert, 5000);
};
Index.js
`
/* eslint-disable */
import '#babel/polyfill';
import { login, logout } from './login';
import { displayMap } from './leaflet';
import { updateData } from './updateSettings';
// DOM ELEMENTS
const leaflet = document.getElementById('map');
const loginForm = document.querySelector('.form--login');
const logOutBtn = document.querySelector('.nav__el--logout');
const updateDataForm = document.querySelector('.form-user-data');
// DELEGATION
if (leaflet) {
const locations = JSON.parse(leaflet.dataset.locations);
displayMap(locations);
}
if (loginForm)
loginForm.addEventListener('submit', (e) => {
e.preventDefault();
const password = document.getElementById('password').value;
const email = document.getElementById('email').value;
login(email, password);
});
if (logOutBtn) logOutBtn.addEventListener('click', logout);
if (updateDataForm)
updateDataForm.addEventListener('submit', (e) => {
e.preventDefault();
const name = document.getElementById('name').value;
const email = document.getElementById('email').value;
updateData(name, email);
});
`
Running the node debugger indicates that process.env.NODE_ENV is undefined but I'm using dotenv for this so it should be working just fine. In any case, the login functionality which is quite similar and uses axios runs just fine.
App.js
const path = require('path');
const express = require('express');
const morgan = require('morgan');
const rateLimit = require('express-rate-limit');
const helmet = require('helmet');
const mongoSanitize = require('express-mongo-sanitize');
const xss = require('xss-clean');
const hpp = require('hpp');
const cookieParser = require('cookie-parser');
// eslint-disable-next-line node/no-deprecated-api
const exp = require('constants');
const AppError = require('./utilities/appError');
const globalErrorHandler = require('./controllers/errrorController');
const tourRouter = require('./routes/tourRoutes');
const userRouter = require('./routes/userRoutes');
const reviewRouter = require('./routes/reviewRoutes');
const viewRouter = require('./routes/viewRoutes');
const app = express(); //express is a function which upon calling will add a bunch of methods to the app variable
app.set('view engine', 'pug');
app.set('views', path.join(__dirname, 'views'));
// 1.GLOBAL MIDDLEWARES
// Serving static files
// app.use(express.static(`${__dirname}/public`));
app.use(express.static(path.join(__dirname, 'public')));
// Set Security HTTP headers
app.use(helmet());
// Development logging
console.log(process.env.NODE_ENV);
if (process.env.NODE_ENV === 'development') {
// the readinng of the process only needs to happen once, and the process is the same no matter which file we're in
app.use(morgan('dev'));
}
// Limit requests from same API
const limiter = rateLimit({
max: 100,
windowMs: 60 * 60 * 1000,
message: 'Too many requests from this IP, please try again in an hour',
});
app.use('/api', limiter);
// Body parser: reading data from body into req.body
app.use(express.json({ limit: '10kb' })); //'express.json' here is middleware
app.use(express.urlencoded({ extended: true, limit: '10kb' }));
app.use(cookieParser());
// Data sanitization against NoSQL query injection
app.use(mongoSanitize());
// Data sanitization agains XSS
app.use(xss());
// Prevent parameter pollution
app.use(
hpp({
whitelist: [
'duration',
'ratingsAverage',
'ratingsQuantity',
'maxGroupSize',
'difficulty',
'price',
],
})
);
// Test middleware
app.use((req, res, next) => {
// we have access to the requestTime property; assuming we want to display the time of the request
req.requestTime = new Date().toISOString();
next();
console.log(req.cookies);
});
// 3. ROUTES: this is where we mount our routers
// these 3 routers are actually middlewares that we mount upon the paths
app.use('/', viewRouter); //mounted right on the root URL
app.use('/api/v1/tours', tourRouter); //we've created a sub-app with this
app.use('/api/v1/users', userRouter);
app.use('/api/v1/reviews', reviewRouter);
// this router is essentially a sub-app for each resource
// the request goes into middleware and when it hits the above line of code, it will match the url, and thus the tourRouter middleware function will run
app.all('*', (req, res, next) => {
next(new AppError(`Cant find ${req.originalUrl} on this server!`, 404));
});
app.use(globalErrorHandler);
module.exports = app;
/updateMe
exports.updateMe = catchAsync(async (req, res, next) => {
// 1) Create error if user POSTs password data
if (req.body.password || req.body.passwordConfirm) {
return next(
new AppError(
'This route is not for password updates. Please use /updateMyPassword',
400
)
);
}
// 2) Filter out unwanted field names that are not allowed to be updated
const filteredBody = filterObj(req.body, 'name', 'email');
// 3) Update user document
const updatedUser = await User.findByIdAndUpdate(req.user.id, filteredBody, {
new: true,
runValidators: true,
});
res.status(400).json({
status: 'success',
data: {
user: updatedUser,
},
});
});
package.json
"scripts": {
"start": "nodemon server.js",
"start:prod": "NODE_ENV=production nodemon server.js",
"debugger": "ndb server.js",
"watch:js": "parcel watch ./public/js/index.js --out-dir ./public/js --out-file bundle.js",
"build:js": "parcel watch ./public/js/index.js --out-dir ./public/js --out-file bundle.js"
},
"author": "Dave Odipo",
"license": "ISC",
"dependencies": {
"#babel/polyfill": "^7.12.1",
"axios": "^1.1.3",
"b": "^2.0.1",
"babel": "file:../../../../../../../../polyfill",
"bcryptjs": "^2.4.3",
"cookie-parser": "^1.4.6",
"dotenv": "^16.0.2",
"express": "^4.18.1",
"express-mongo-sanitize": "^2.2.0",
"express-rate-limit": "^6.6.0",
"helmet": "3.16",
"hpp": "^0.2.3",
"jsonwebtoken": "^8.5.1",
"mongoose": "^5.13.15",
"morgan": "^1.10.0",
"nodemailer": "^6.8.0",
"pug": "^3.0.2",
"slugify": "^1.6.5",
"validator": "^13.7.0",
"xss-clean": "^0.1.1"
},
"optionalDependencies": {
"win-node-env": "^0.6.1"
},
"devDependencies": {
"eslint": "^8.23.1",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsx-a11y": "^6.6.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.31.8",
"parcel-bundler": "^1.12.3",
"prettier": "^2.7.1"
},
"engines": {
"node": ">=8.0.0"
}
}
Please help
Try changing res.status(400).json({ to res.status(200).json({
I am attempting to import files from a directory from within a loop to dynamically generate routes. As you can see in my (Working from index file (my initial code), I attempted to use (import.meta.url) because I wanted this to be a sync operation. The error I got was as follow:
First Error:
[ERROR] 11:51:22 ⨯ Unable to compile TypeScript:
src/routes/index.ts(26,33): error TS1343: The 'import.meta'
meta-property is only allowed when the '--module' option is 'es2020',
'es2022', 'esnext', 'system', 'node12', or 'nodenext'.
This is what I tried.
After Google searches I tried the code in the (One of the things I tried) section below. I ran into this error which is strange to me since I am actually using the dynamic import.
[ERROR] 11:52:20 Error: require() of ES Module
/app/src/routes/module-streams.js from /app/src/routes/index.ts not
supported. Instead change the require of module-streams.js in
/app/src/routes/index.ts to a dynamic import() which is available in
all CommonJS modules.
Honestly even if I got the second approach I tried working, I am not thrilled about having to deal with promises. I want to import the function of each of the many routes, invoke it and create the routes during startup. This is a mock server and I am attempting to reduce the boilerplate code for adding new JSON. The funny thing is I was able to get my first approach working in another place in the app importing JSON. The code is almost identical and I get no complaint.
Really all I want to do is dynamically get the files and invoke the functions synchronously if possible. I never imaged this would be so problematic. It certainly was not with require.
package.json
{
"name": "mock-server",
"version": "1.0.0",
"description": "",
"main": "server.js",
"type": "module",
"scripts": {
"start": "ts-node-dev src/server.ts",
"test": "jest --watchAll --no-cache"
},
"author": "",
"license": "ISC",
"dependencies": {
"#types/express": "^4.17.13",
"#types/mongoose": "^5.11.97",
"express": "^4.17.3",
"mongoose": "^6.3.0",
"typescript": "^4.6.3"
},
"devDependencies": {
"ts-node-dev": "^1.1.8"
}
}
tsconfig
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true
}
}
Dockerfile
FROM node:alpine
WORKDIR /app
COPY package.json .
RUN npm install --only=prod
COPY . .
CMD ["npm", "start"]
One of the route files i am attepting to import
import express from 'express';
import mongoose from "mongoose";
const ModuleStreams = mongoose.model('ModuleStreams', new mongoose.Schema({
moduleName: String,
streamName: String,
status: String,
softwareSourceId: String,
profiles: Array
}, { collection : 'module-streams' }));
export default (services) => {
let router = express.Router();
router.route('/')
.get((req, res, next) => {
ModuleStreams.find({}, function(err, data) {
console.log(data);
res.send(data);
});
});
return router;
};
Working from index file (my initial code)
import fs from 'fs';
import { createRequire } from "module";
export const routes = () => {
const require = createRequire(import.meta.url);
const dir = process.cwd() + '/src/routes';
const paths = fs.readdirSync(dir, { withFileTypes: true })
.filter(item => !item.isDirectory())
.map(item => item.name);
paths.forEach(filePath => {
const fileNameSegments = filePath.split('.');
const routeName = fileNameSegments[0];
if (routeName !== 'index') {
const content = require(`./${filePath}`);
const test = import(`./${filePath}`);
}
});
};
One of the things I tried
import fs from 'fs';
export const routes = () => {
const dir = process.cwd() + '/src/routes';
const paths = fs.readdirSync(dir, { withFileTypes: true })
.filter(item => !item.isDirectory())
.map(item => item.name);
paths.forEach(filePath => {
const fileNameSegments = filePath.split('.');
const routeName = fileNameSegments[0];
if (routeName !== 'index') {
const test = import(`./${filePath}`);
}
});
};
I'm using the Parse server and I'm trying to send an email with an Html file. the problem I'm not really sure how to access the public folder from the cloud code.
This is the error:
ENOENT: no such file or directory, open './public/invoice.html'
The directory:
│ ├── cloud
│ │ ├── functions.js
│ │ ├── main.js
│ ├── public
│ │ ├── invoice.html
fs.readFileSync("../public/invoice.html", "utf8"
And this is my code:
var fs = require('fs');
Parse.Cloud.define("mailSend", function(request, response) {
const apiKey = '4441*****************a47f';
const mailgun = require("mailgun-js");
const DOMAIN = 'user.mailgun.org';
const mg = mailgun({apiKey: apiKey, domain: DOMAIN});
const data = {
from: 'email <email#example.com>',
to: 'email#example.com',
subject: 'Invoice',
html: fs.readFileSync("../public/invoice.html", "utf8") || null
};
mg.messages().send(data, function (error, body) {
console.log(body);
});
});
Try this:
var path = require('path');
var fs = require('fs');
Parse.Cloud.define("mailSend", function(request, response) {
const apiKey = '4441*****************a47f';
const mailgun = require("mailgun-js");
const DOMAIN = 'user.mailgun.org';
const mg = mailgun({apiKey: apiKey, domain: DOMAIN});
const data = {
from: 'email <email#example.com>',
to: 'email#example.com',
subject: 'Invoice',
html: fs.readFileSync(path.join(__dirname, "../public/invoice.html"), "utf8") || null
};
mg.messages().send(data, function (error, body) {
console.log(body);
});
});
Looks similar. Check this and try, Error: ENOENT: no such file or directory, unlink
Thank you all for your answers, This code works fine with me. I used ejs instead of HTML. you can use HTML but you have to add
var fs = require('fs'); insteead of const ejs = require('ejs');
var path = require('path');
const ejs = require('ejs');
const mailgun = require("mailgun-js");
const apiKey = '444**********00a47f';
const DOMAIN = 'user.mailgun.org';
const mg = mailgun({apiKey: apiKey, domain: DOMAIN});
Parse.Cloud.define("SendEmail", function(request, response) {
var orderId = request.params.orderId;
var items = request.params.items;
var details = request.params.details;
var user = request.params.user;
var subject = "Thank You for Your Order #" + orderId;
var orderData = {
user: user,
items: items,
details: details
}
ejs.renderFile(path.join(__dirname, './public/invoice.ejs'), orderData, (err, htmlString) => {
if (err) console.error(err);
let data = {
from: 'app neme <email#gmail.com >',
to: 'email#gmail.com',
subject: subject,
html: htmlString
};
mg.messages().send(data, function (error, body) {
console.log(body);
console.log(prods);
response.success("success send");
});
});
});
This question already has an answer here:
Fetch error when building Next.js static website in production
(1 answer)
Closed 9 months ago.
I have an API route which upon request gets me the data I want when the Project page (component) is loaded as shown below.
http://localhost:3000/api/projects
When I load the page where I request for that data inside getInitialProps() within pages/projects.js it shows data coming through which is what I want as shown below, so far so good.
console logs data coming through from custom express API route I have made
The code for that is here:
pages/projects.js
import React, { Component } from "react";
import Layout from "../components/Layout";
import Siema from "siema";
import Head from "next/head";
import fetch from "isomorphic-unfetch";
export default class extends React.Component {
componentDidMount() {
this.siema = new Siema({
loop: false
});
}
prev = () => {
this.siema.prev();
};
next = () => {
this.siema.next();
};
render() {
return (
<Layout>
<Head>
<title>Jesal Patel | Projects</title>
</Head>
<div className="container">
<section>
<div className="projects">
<div className="siema">
<div>
<img src="(ignore this the img is showing on stackoverflow post.)" />
<div className="overlay">
<div id="overlay_title">Dextero</div>
<div id="overlay_description">
I developed a multi-touch mobile game for stroke patients
to rehabilitate their finger coordination and dexterity.
</div>
<div id="overlay_tech">Java, Android, LibGDX, SQLite</div>
</div>
</div>
</div>
<div />
<button onClick={this.prev}>Prev</button>
<button onClick={this.next}>Next</button>
</div>
</section>
</div>
</Layout>
);
}
static async getInitialProps({ req }) {
//This fetch is the reason why my project won't build
const result = await fetch("http://localhost:3000/api/projects");
const projects = await result.json();
console.log(projects);
return { projects };
}
}
The Problem:
Now the problem begins when I run next-build and the following error throws during it: EDIT: I didn't paste the error properly. NOTE: I run now-buildscript which exports the project and that's my problem, it's what's causing me problems
I:\Next.js\website>npm run now-build
> website#1.0.0 now-build I:\Next.js\website
> next build && next export -o dist
Creating an optimized production build ...
Compiled successfully.
┌ /
├ /_app
├ /_document
├ /_error
├ /contact
└ /projects
> using build directory: I:\Next.js\website\.next
copying "static" directory
copying "static build" directory
> No "exportPathMap" found in "next.config.js". Generating map from "./pages"
launching 11 threads with concurrency of 10 per thread
[====-] 4/5 80% 160/s 0.0s { FetchError: request to http://localhost:3000/api/projects failed, reason: connect ECONNREFUSED 127.0.0.1:3000
at ClientRequest.<anonymous> (I:\Next.js\website\node_modules\node-fetch\lib\index.js:1444:11)
at ClientRequest.emit (events.js:189:13)
at Socket.socketErrorListener (_http_client.js:392:9)
at Socket.emit (events.js:189:13)
at emitErrorNT (internal/streams/destroy.js:82:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:50:3)
at process._tickCallback (internal/process/next_tick.js:63:19)
message:
'request to http://localhost:3000/api/projects failed, reason: connect ECONNREFUSED 127.0.0.1:3000',
type: 'system',
errno: 'ECONNREFUSED',
code: 'ECONNREFUSED' }
{ message:
'request to http://localhost:3000/api/projects failed, reason: connect ECONNREFUSED 127.0.0.1:3000',
type: 'system',
errno: 'ECONNREFUSED',
code: 'ECONNREFUSED' }
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! website#1.0.0 now-build: `next build && next export -o dist`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the website#1.0.0 now-build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\Jesal\AppData\Roaming\npm-cache\_logs\2019-03-19T04_10_45_930Z-debug.log
I understand that it's due to this line const result = await fetch("http://localhost:3000/api/projects");, but I don't know what to do to enable it to build. I am new to MEAN stack. I'm not sure if I have to create that route externally somewhere global for it to work fine? I don't know if that will fix it or if it's something else.
I have used Express and Mongoose with this application and the code for these can be found below along with the package.json and next.config.js files.
server/index.js
const express = require("express");
const next = require("next");
const bodyParser = require("body-parser");
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });
const handle = app.getRequestHandler();
const routes = require("./routes/index.js");
var mongoose = require("mongoose");
const PORT = process.env.PORT || 3000;
const dbName = "MySite";
const MONGO_URL =
"mongodb+srv://admin:<hidden for privacy>#cluster0-5cjs1.mongodb.net/MySite?retryWrites=true";
app
.prepare()
.then(() => {
mongoose.connect(MONGO_URL, { useNewUrlParser: true });
mongoose.Promise = global.Promise;
mongoose.connection.on("open", function() {
console.log("mongodb is connected!!");
});
const db = mongoose.connection;
model = db.modelNames();
db.on("error", console.error.bind(console, "MongoDB connection error:"));
const server = express();
server.use(bodyParser.json());
server.use(bodyParser.urlencoded({ extended: true }));
server.use("/api", routes);
server.use((req, res, next) => {
// Also expose the MongoDB database handle so Next.js can access it.
req.db = db;
next();
});
server.get("*", (req, res) => {
return handle(req, res);
});
server.listen(PORT, () => {
console.log("Server is up and running on port number " + PORT);
});
})
.catch(ex => {
console.error(ex.stack);
process.exit(1);
});
server/routes/index.js
const express = require("express");
const router = express.Router();
const project_controller = require("../controllers/project_controller");
router.get("/projects", project_controller.projects_list);
module.exports = router;
server/models/project_schema.js
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var ProjectSchema = new Schema(
{
name: String,
description: String,
tech: String
},
{ collection: "project" }
);
module.exports = mongoose.model("Project", ProjectSchema);
server/controllers/project_controller.js
const Project = require("../models/project_schema");
exports.test = function(req, res) {
res.send("Greetings from the Test controller!");
};
exports.projects_list = function(req, res) {
var documents = Project.find({}, function(err, docs) {
if (err) throw err;
res.send(docs);
return docs;
});
};
exports.project_create = function(req, res) {
let project = new Project({
name: req.body.name,
description: req.body.description,
tech: req.body.tech
});
project.save(function(err, project) {
if (err) {
console.log("Unsuccessful");
}
console.log("Saved!");
});
};
package.json
{
"name": "website",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "nodemon server/index.js",
"now-build": "next build && next export -o dist",
"build": "next build",
"start": "next start -p 8000"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"#engineerapart/nextscript": "^1.0.2",
"#zeit/next-css": "^1.0.1",
"#zeit/next-typescript": "^1.1.1",
"body-parser": "^1.18.3",
"bootstrap": "^4.3.1",
"co": "^4.6.0",
"cross-env": "^5.2.0",
"express": "^4.16.4",
"file-loader": "^3.0.1",
"isomorphic-unfetch": "^3.0.0",
"jquery": "^3.3.1",
"mongodb": "^3.1.13",
"mongoose": "^5.4.19",
"next": "^8.0.4-canary.10",
"next-compose-plugins": "^2.1.1",
"next-images": "^1.0.4",
"nodemon": "^1.18.10",
"react": "^16.8.3",
"react-dom": "^16.8.3",
"react-slick": "^0.23.2",
"siema": "^1.5.1",
"superagent": "^4.1.0",
"url-loader": "^1.1.2"
}
}
next.config.js
const withCSS = require("#zeit/next-css");
const withImages = require("next-images");
const withPlugins = require("next-compose-plugins");
module.exports = {
crossOrigin: "anonymous"
};
module.exports = withPlugins([withImages, withCSS]);
module.exports = withImages();
// module.exports = withCSS();
module.exports = {
target: "serverless"
};
module.exports = withCSS({
webpack: function(config) {
config.module.rules.push({
test: /\.(eot|woff|woff2|ttf|svg|png|jpg|gif)$/,
use: {
loader: "url-loader",
options: {
limit: 100000,
name: "[name].[ext]"
}
}
});
return config;
}
});
UPDATE: This is an update to Prabhakar Pandey's response, to let you guys know, I always killed the server when running the now-buildcommand, Also, to be very clear as I mentioned before on my first edit of this post, that it's the 2nd part of that command which is failing with error, which is next export -o distnot next build, that works fine! Also, I'm on Windows OS not Mac OS.
This happens because you want to run an application on a port which is already being used.
you can check the application running on a port with these commands:
For macOS El Capitan and newer (or if your netstat doesn't support -p), use lsof
sudo lsof -i tcp:3000
For Centos 7 use
netstat -vanp --tcp | grep 3000
Also if wnat to kill any process you can use
kill -9 `PID`
when port is empty you try your application by rebuilding it should work
So I connect to my database when the server is started. Then when my site is being loaded in the entry js file, I require the file that has functions I can call to run some query. My bundler tries to build the file containing the database functions and everything crashes. I think the root of the problem is that my databasemanger.js file is being built(even though it shouldn't) but I don't know how to resolve the issue.
server.js
'use strict';
const express = require('express');
const app = express();
const path = require("path");
var Vue = require('vue');
var database = require('./databasemanager');
// Create connection to database
var DIST_DIR = path.join(__dirname, "dist"), PORT = 3000;
app.use(express.static(DIST_DIR));
app.get("*", function (req, res) {
res.sendFile(path.join(DIST_DIR, "index.html"));
});
// var connection = new Connection(config);
database.connect();
app.listen(3000);
here is my databasemanger.js
var Connection = require('tedious').Connection;
var Request = require('tedious').Request;
var ableToRun = false;
var config =
{
userName: '.....', // update me
password: '....!', // update me
server: '......', // update me
options:
{
database: '.....' //update me
, encrypt: true
}
};
var connection;
function connect() {
connection = new Connection(config);
// Attempt to connect and execute queries if connection goes through
connection.on('connect', function (err) {
if (err) {
console.log(err);
return false;
}
else {
ableToRun = true;
queryDatabase();
return true;
}
}
);
};
function queryDatabase() {
// Read all rows from table
request = new Request(
"SELECT * FROM STUDENT",
function (err, rowCount, rows) {
if (err) {
console.log(err);
}
console.log("rowCount::" + rowCount);
console.log(rows)
// process.exit();
}
);
request.on('row', function (columns) {
columns.forEach(function (column) {
console.log("%s\t%s", column.metadata.colName, column.value);
});
});
connection.execSql(request);
};
function unionQuery() {
// Read all rows from table
request = new Request(
"SELECT * FROM STUDENT",
function (err, rowCount, rows) {
if (err) {
console.log(err);
}
console.log("rowCount::" + rowCount);
console.log(rows)
// process.exit();
}
);
request.on('row', function (columns) {
columns.forEach(function (column) {
console.log("%s\t%s", column.metadata.colName, column.value);
});
});
connection.execSql(request);
};
module.exports = {
connect: connect,
unionQuery: unionQuery
}
mywebpack.config is setup like this::
var path = require("path");
var DIST_DIR = path.join(__dirname, "dist"),
CLIENT_DIR = path.join(__dirname, "src");
module.exports = {
context: CLIENT_DIR,
entry: "./index",
output: {
path: DIST_DIR,
filename: "bundle.js"
},
resolve: {
extensions: ['', '.js']
}
};
In my index.js file I have this line
let databasemanager = require ('../databasemanager');
which seems to be causing the issue. I need this here because I want to run the commands here.
Part of the error on the console I get is::
> webpack && npm start
Hash: 7cfb6092af955d7afa54
Version: webpack 2.1.0-beta.22
Time: 1458ms
Asset Size Chunks Chunk Names
index.html 1.69 kB [emitted]
bundle.js 1.17 MB 0 [emitted] main
[144] ../databasemanager.js 5.78 kB {0} [built]
[322] ./index.js 555 bytes {0} [built]
+ 321 hidden modules
ERROR in ../~/tedious/lib/connector.js
Module not found: Error: Can't resolve 'net' in '/Users/nishantrimal/Desktop/DataBase/WebsistePresent/node_modules/tedious/lib'
# ../~/tedious/lib/connector.js 17:10-24
# ../~/tedious/lib/connection.js
# ../~/tedious/lib/tedious.js
# ../databasemanager.js
# ./index.js
ERROR in ../~/tedious/lib/connector.js
Module not found: Error: Can't resolve 'dns' in '/Users/nishantrimal/Desktop/DataBase/WebsistePresent/node_modules/tedious/lib'
# ../~/tedious/lib/connector.js 18:10-24
# ../~/tedious/lib/connection.js
# ../~/tedious/lib/tedious.js
# ../databasemanager.js
# ./index.js
Lastly, my pacakage.json is setup like this
{
"name": "WebsistePresent",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js",
"dev": "webpack && npm start"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"async": "^2.6.0",
"express": "^4.16.2",
"lodash": "^4.17.4",
"tedious": "^2.1.1",
"uniq": "^1.0.1",
"vue": "^2.5.6"
},
"devDependencies": {
"eslint": "^4.11.0",
"file-loader": "^1.1.5",
"webpack": "^2.1.0-beta.22",
"webpack-node-externals": "^1.6.0"
}
}
Any help would be greatly appreciated!!