I am trying to get server side rendering set up in a Vue application. I have imported the server side renderer bundle and I believe included everything necessary for it to work, however, when refreshing my webpage I am getting the error Cannot read property 'renderToString' of undefined from my server.js file.
I've tried to debug but it appears as though my bundle never gets set to anything and so is always undefined.
dev-server.js
const webpack = require('webpack')
const clientConfig = require('./webpack.client.config')
const serverConfig = require('./webpack.server.config')
const MFS = require('memory-fs')
const path = require("path")
module.exports = function setupDevServer (app, onUpdate) {
clientConfig.entry.app = [
'webpack-hot-middleware/client',
clientConfig.entry.app
]
clientConfig.plugins.push(
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin()
)
const clientCompiler = webpack(clientConfig)
app.use(
require('webpack-dev-middleware')(clientCompiler, {
stats: {
colors: true
}
})
)
app.use(require('webpack-hot-middleware')(clientCompiler))
const serverCompiler = webpack(serverConfig)
const mfs = new MFS()
const outputPath = path.join(serverConfig.output.path, 'server/main.js')
serverCompiler.outputFileSystem = mfs
serverCompiler.watch({}, () => {
onUpdate(mfs.readFileSync(outputPath, 'utf-8'))
})
}
server.js
const express = require("express");
const app = express();
const fs = require("fs");
const path = require("path");
const { createBundleRenderer } = require('vue-server-renderer');
let renderer;
const indexHTML = (() => {
return fs.readFileSync(path.resolve(__dirname, "./index.html"), "utf-8");
})();
app.use("/dist", express.static(path.resolve(__dirname, "./dist")));
require("./build/dev-server")(app, bundle => {
renderer = createBundleRenderer(bundle)
});
app.get("*", (req, res) => {
renderer.renderToString({ url: req.url }, (err, html) => {
if (err) {
return res.status(500).send('Server Error')
}
html = indexHTML.replace('{{ APP }}', html)
res.write(html);
res.end();
})
});
const port = process.eventNames.PORT || 3000;
app.listen(port, () => {
console.log(`server started at http://localhost:${port}`);
});
Related
I'm trying to create a Note taker app, but when click on save any information, is coming a TypeError: Cannot read properties of undefined (reading 'push')
Below the code for Note.js
const path = require('path');
const fs = require('fs');
const uniqid = require('uniqid');
let noteList = [];
function findById(id, noteList) {
return noteList.filter(note => note.id === id)[0];
}
function addNewNote(body, noteList) {
let newNote = body;
newNote.id = uniqid();
noteList.push(newNote);
fs.writeFileSync(
path.join(__dirname, '../db/db.json'),
JSON.stringify({db: noteList}, null, 2)
);
return newNote;
}
function removeNote (id, noteList) {
const removeThisNote = findById(id, noteList);
for (let i = 0; i<noteList.length; i++){
if (noteList[i].id === removeThisNote.id) {
noteList.splice(i, 1);
fs.writeFileSync(
path.join(__dirname, '../db/db.json'),
JSON.stringify({db: noteList}, null, 2)
);
}
};
}
module.exports = {
findById,
addNewNote,
removeNote
};
api index.js
const router = require('express').Router();
const {db} = require('../db/db.json');
const { addNewNote, removeNote} = require('../lib/note.js');
router.get('/notes', (req, res) => {
let results = db;
res.json(results);
})
router.post('/notes', (req, res) => {
const newNote = addNewNote(req.body, db);
res.json(newNote);
})
router.delete('/notes/:id', (req, res) => {
removeNote(req.params.id, db);
res.json(req.body);
})
module.exports = router;
Server.js
const express = require(`express`);
const apiRoutes = require('./routes/apiRoutes.js');
const path = require('path');
// const htmlRoutes = require('./routes/htmlRoutes.js');
const PORT = process.env.PORT || 3001;
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use('/api', apiRoutes)
// app.use('/', htmlRoutes)
app.use(express.static(`public`));
//Routes
app.get(`/notes`, (req, res) => {
console.log(`Note page requested`);
res.sendFile(path.join(__dirname, `public/notes.html`));
});
app.get(`/`, (req, res) => {
console.log(`Home page requested`);
res.sendFile(path.join(__dirname, `public/index.html`));
});
app.listen(PORT, () =>
console.log(`App listening at http://localhost:${PORT}`)
);
Can anyone help with this ?
I want to deploy this using Heroku but when testing save any info, error comes up.
push() is an Array method. Therefore, the error shows that some variable is not array but undefined.
The addNewNote function contains a variable called noteList and the error says it is not an array.
So, the argument you pass to this function is not an array.
I suggest you check the db variable you import from db.json and see if this is an array because this is the variable you pass as an argument in addNewNote.
my code is:
//Imports
const express = require('express');
const app = express();
const fs = require("fs");
const multer = require('multer');
const { createWorker } = require("tesseract.js");
const worker = createWorker();
//Storage
const storage = multer.diskStorage({
destination: (req,file,cb) => {
cb(null, "./uploads");
},
filename: (req,file,cb) => {
cb(null, file.originalname);
}
});
const upload = multer({storage: storage}).single("avatar");
app.set('view engine', 'ejs');
//route
app.get('/',(req,res)=>{
res.render('index');
});
app.post('/upload',(req,res) => {
upload(req,res, err => {
fs.readFile(`./uploads/${req.file.originalname}`,(err,data) => {
if(err) return console.log('This is your error',err);
worker
.recognize(data, "eng", {tessjs_create_pdf: '1'})
.progress(progress => {
console.log(progress);
})
.then(result => {
res.send(result.text);
})
.finally(() => worker.terminate())
});
});
});
//Start Up our server
const PORT = 5000 || process.env.PORT;
app.listen(PORT, () => console.log(`Hey I am running on port ${PORT}`));
the error I get is this
D:\ML\OCR\app.js:34
.progress(progress => {
^
TypeError: worker.recognize(...).progress is not a function
at D:\ML\OCR\app.js:34:18
I know worker.recognize/.progress is decapitated but can someone please correct this code.
Thank you.
I am trying to create an OCR using tesseract.js . watching this video: https://www.youtube.com/watch?v=a1I3tcALTlc
But I am not able to find a solution.
Change this line
const worker = createWorker();
To
const worker = await createWorker();
I think the issue is that the code is out of date.
Try this
async function getTextFromImage() {
await worker.load()
await worker.loadLanguage('eng')
await worker.initialize('eng')
const { data: { text } } = await worker.recognize(data);
res.send(text);
console.log(text);
await worker.terminate()
}
getTextFromImage();
I was actually following a nodejs course on Udemy and suddenly down the course, the code started breaking and giving some errors. I then tried copying the instructor's code, but still, the problem was the same.
I also followed this answer on StackOverflow itself but the problem remains the same.
I am attaching all the js files below and also the error message from the terminal below:
Error message from the terminal
This is what the file structure looks like
Now the js files:
app.js file:
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const adminRoutes = require('./routes/admin');
const shopRoutes = require('./routes/shop');
const errorController = require('./controllers/error');
const app = express();
app.set('view engine', 'ejs');
app.set('views', 'views');
app.use(bodyParser.urlencoded({extended:false}));
app.use(express.static(path.join(__dirname, 'public')));
app.use('/admin', adminRoutes);
app.use(shopRoutes);
app.use(errorController.get404Page);
app.listen(3000);
controllers/error.js file:
exports.get404 = (req, res, next) => {
res.status(404).render('404', { pageTitle: 'Page Not Found' });
};
controllers/products.js file
const Product = require('../models/product');
exports.getAddProduct = (req, res, next) => {
res.render('add-product', {
pageTitle: 'Add Product',
path: '/admin/add-product',
formsCSS: true,
productCSS: true,
activeAddProduct: true
});
};
exports.postAddProduct = (req, res, next) => {
const product = new Product(req.body.title);
product.save();
res.redirect('/');
};
exports.getProducts = (req, res, next) => {
Product.fetchAll(products => {
res.render('shop', {
prods: products,
pageTitle: 'Shop',
path: '/',
hasProducts: products.length > 0,
activeShop: true,
productCSS: true
});
});
};
models/product.js file :
const fs = require('fs');
const path = require('path');
const p = path.join(
path.dirname(process.main.filename),
'data',
'products.json'
);
const getProductsFromFile = cb => {
fs.readFile(p, (err, fileContent) => {
if (err) {
cb([]);
} else {
cb(JSON.parse(fileContent));
}
});
};
module.exports = class Product {
constructor(t) {
this.title = t;
}
save() {
getProductsFromFile(products => {
products.push(this);
fs.writeFile(p, JSON.stringify(products), err => {
console.log(err);
});
});
}
static fetchAll(cb) {
getProductsFromFile(cb);
}
};
routes/admin.js file:
const path = require('path');
const express = require('express');
const productsController = require('../controllers/products');
const router = express.Router();
// /admin/add-product => GET
router.get('/add-product', productsController.getAddProduct);
// /admin/add-product => POST
router.post('/add-product', productsController.postAddProduct);
module.exports = router;
routes/shop.js file:
const path = require('path');
const express = require('express');
const productsController = require('../controllers/products');
const router = express.Router();
router.get('/', productsController.getProducts);
module.exports = router;
util/path.js file:
const path = require('path');
module.exports = path.dirname(process.main.filename);
I am new to backend development, nodejs to be specific. Please help me find my mistake.
In many file you have used process.main.filename, but there is no property named process.name for node.js process, so process.main is undefined. As a result reading the property process.main.filename gives the error.
So, to solve your problem:
Replace every process.main.filename with
process.mainModule.filename OR require.main.filename
(there is difference in both, but it will not matter in your app.)
and see if it works. I guess this is a mistake on your part while writing the code.
Tip: Always try to understand the error using terminal output. That way You can solve most of the problems.
I've deployed my app on Heroku and after some tweaking, everything works except when I try to retrieve data from the Mongo database. The console error I get is: Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0.
I have the feeling that it won't go into the get request while that should be the case. (Because it's not logging anything in the console)
Am I missing something in the way routes are handled in production?
Everything in development is working.
I'm very confused at this point, hope someone can help me
Server.js:
const bodyParser = require('body-parser')
const path = require('path');
const express = require('express');
const morgan = require('morgan');
const MongoClient = require('mongodb').MongoClient;
const cors = require('cors')
const compression = require('compression');
const helmet = require('helmet')
const app = express();
const port = process.env.PORT || 5000;
app.use(helmet())
app.use(compression());
if (process.env.NODE_ENV === 'production') {
const publicPath = path.join(__dirname, 'client/build');
const apiPath = path.join(__dirname, 'api');
app.use(express.static(publicPath));
app.use('/overview', express.static(apiPath));
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname + '/client/build/index.html'));
})
}
app.use(cors())
app.use(morgan('tiny'));
app.use(bodyParser.json())
const apiRouter = require('./api/api');
app.use('/overview', apiRouter);
// connect to the db and start the express server
let db;
const url = process.env.MONGODB_URI
MongoClient.connect(url, {useUnifiedTopology: true,useNewUrlParser: true,}, (err, client) => {
if(err) {
return console.log(err);
}
console.log('mongo connected')
db = client.db('kvdlaanmeldingen');
// start the express web server listening on port 5000
app.listen(port, () => console.log(`Listening on port ${port}`));
});
apiRouter, api.js in api/api.js:
const express = require('express');
const apiRouter = express.Router()
const MongoClient = require('mongodb').MongoClient;
const mongodb = require('mongodb');
const url = process.env.MONGODB_URI
console.log('api.js is activated') //this is logged to console, so file can be read.
let db;
MongoClient.connect(url, {useUnifiedTopology: true,useNewUrlParser: true,}, (err, client) => {
db = client.db('kvdlaanmeldingen');
});
let aanmeldingen = [];
// this is where I believe it gets stuck
apiRouter.get('/', (req, res) => {
console.log(db)
db.collection('kvdlaanmeldingen').countDocuments({}, function(err, result) {
console.log(result)
if (err) return console.log(err);
res.send(JSON.stringify(result));
})
});
module.exports = apiRouter;
The get request should be done as soon as this React component is rendered:
import React from 'react';
import './Aanmeldingen.css';
import { Link, Route } from "react-router-dom";
import XPress from './utils/Xpress.js';
import TaakComponent from './TaakComponent';
import { snakeCase } from "snake-case";
class Aanmeldingen extends React.Component {
constructor (props) {
super(props);
this.state = {
dataLoaded: 0,
taken: [// an array of different names that will be loaded as headers],
taakKlik: false,
taakData: null,
taakNaam: null,
}
}
componentDidMount(){
XPress.getTaken().then(data => {
console.log(data)
if (data) {
this.setState({
taakData: data,
dataLoaded: 1,
});
}
});
}
{...}
render(){
return (
<div className="Aanmeldingenpage">
<div className="statistics" onClick={this.aanmeldingen}>
<p className="statistics" id="counterAanmeldingen">{this.state.dataLoaded ? `Aantal aanmeldingen: ${this.state.taakData}` : 'Data aan het laden..'}</p>
</div>
</div>
);
}
}
and Xpress.getTaken is looking like this:
const XPress = {};
const baseUrl = window.location.origin;
XPress.getTaken = () => {
const url = `${baseUrl}/overview`;
return fetch(url, {method: 'GET'}).then(response => {
if (!response.ok) {
return new Promise(resolve => resolve([]));
}
return response.json().then(jsonResponse => {
return jsonResponse
}
)
})
}
The error you posted is often seen when parsing JSON fails. I guess this happens when fetch fails to parse the result in the frontend at this line: return response.json().then(jsonResponse => {.
Instead of returning valid JSON, the backend returns a file that starts with "<" (the unexpected token). Your backend responds with an HTML page instead of JSON.
Issue comes from here most likely:
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname + '/client/build/index.html'));
})
This basically says that all GET requests should serve index.html. That's why the request doesn't go to apiRouter.get('/'), it stops at the first match, which is the code above. It works on localhost because this code path is inside a conditional that checks NODE_ENV for production.
Not sure why you have it in there, but removing it would solve the issue.
Please try adding the heroku postbuild script to your json file in the root directory as same as the existence of the server.js file, that might help, using in react we must add heroku postbiuld so that the build is saved in the server, and that might not produce an issue,
I have node-express app where I have bunch of Routes for login, logout and signup and one Route for checking authorised Route which can be accessed only through providing authToken. I moved the Routes to separate Route file and I got the above error.
This is my Users Routes File:
const express = require('express');
const authenticate = require('./../middleware/authenticate');
const router = express.Router();
const {User} = require('./../models/user');
router.post('/',(req, res) => {
var body = _.pick(req.body,['email','password']);
var user = new User(body);
user.save().then(() => {
return user.generateAuthToken()
}).then((token) => {
res.header('x-auth', token).send(user);
}).catch((e) => {
res.status(400).send(e);
});
});
router.post('/login',(req, res) => {
var body = _.pick(req.body, ['email', 'password']);
User.findByCredentials(body.email, body.password).then((user) => {
return user.generateAuthToken().then((token) => {
res.header('x-auth', token).send(user);
});
}).catch((e) => {
res.status(400).send(e);
});
});
router.delete('/logout',authenticate, (req, res) => {
req.user.removeToken(req.token).then(() => {
res.status(200).send();
},(e) => {
res.status(400).send(e);
}) ;
});
router.get('/me',authenticate, (req,res) => {
res.send(req.user);
});
module.exports = router;
Following is my main server.js file:
const express = require('express');
const _ = require('lodash');
var app = express();
const usersRoutes = require('./routes/users');
app.use(express.json());
app.use('/users', usersRoutes);
var {mongoose} = require('./db/mongoose');
var {User} = require('./models/user');
var {authenticate} = require('./middleware/authenticate');
const port = process.env.PORT || 3000 ;
app.listen(port, () => console.log(`Listening on ${port}...`))
I have a model/Schema(mongoose) file for User so If You feel you need that I am ready to edit my question. Thanks.
The problem is that router.delete is expecting a function on the middleware parameter (like you did in your server.js file with app.use(express.json())) so it can be used like a callback which gets called whenever a request reach your route.
Try changing authenticate to authenticate().
It seems like in your users routes file you are importing the entire module who contains the authenticate function, so when try to access it like a function you'll get an error. You need to import it like you did in your server.js file.
Change the line const authenticate = require('./../middleware/authenticate'); for const {authenticate} = require('./../middleware/authenticate');.