I'm trying to set up an isomorphic server-side rendering React app using Webpack, but am getting this error when I try turning my React code into a string using renderToString:
Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components).
Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
I stop getting this error when I comment out the line with the renderToString function (of course, the app still doesn't work - I just no longer get an error message).
I've tried passing renderToString <RootApp /> and React.createElement(RoutingContext instead of making a factory, and neither of those has worked. Using React.createElement resulted in the same error, and using <RootApp /> threw an unexpected token < error.
And ideas on what could be going on?
My app looks like:
app.js
"use strict"
require("babel-register");
const Express = require('express');
const BodyParser = require('body-parser');
const Path = require('path');
const Fs = require('fs');
const Url = require('url');
const ReactRouter = require('react-router');
const React = require('react');
const ReactDOMServer = require('react-dom/server');
const app = Express();
app.set('view engine', 'ejs');
app.get('*', (req, res) => {
let RootApp = require('./components/app.jsx');
let rootAppFactory = React.createFactory(RootApp);
let reactHtml = ReactDOMServer.renderToString(rootAppFactory({}));
res.render('index', {reactOutput: reactHtml});
})
if (process.env.NODE_ENV !== 'test') {
let port = process.env.port || 4000;
app.listen(port);
console.log('Listening on port', port);
} else {
module.exports = app;
}
app.jsx
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
class App extends Component {
render() {
return (
<div>
{this.props.children}
</div>
)
}
}
export default App;
index.ejs
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<title>Vjeverica</title>
</head>
<body>
<div id="root">
<%- reactOutput %>
</div>
<script src="bundle.js"></script>
</body>
</html>
Ended up getting this working. The issue was in how I was requiring app.jsx in app.js - because I'm using require instead of import, I needed to change require('./components/app.jsx') to require('./components/app.jsx').default to get the default export.
Related
This question already has answers here:
How to publish a website made by Node.js to Github Pages?
(8 answers)
Closed 11 months ago.
My app.js
const express = require ("express");
const res = require("express/lib/response");
const https = require ("https");
const bodyParser = require ("body-parser");
const app = express();
app.use(bodyParser.urlencoded({extended:true}));
app.get("/",function(request, response){
response.sendFile(__dirname+"/index.html");
})
app.post("/", function(req, res){
console.log(req.body.cityName);
// console.log("POST request received.");
const query=req.body.cityName;
const apiKey="796ea31271937af05a23079696c29758";
const units = "metric";
const url = "https://api.openweathermap.org/data/2.5/weather?q="+query+"&appid="+apiKey+"&units="+units;
https.get(url, function(response){
console.log(res.statusCode);
response.on("data", function(data){
//console.log(data);
const weatherData= JSON.parse(data);
// console.log(weatherData);
// const object = {
// name: "Ann",
// favouriteFood: "Butter Chicken"
// }
// console.log(JSON.stringify(object));
const temp = weatherData.main.temp;
console.log("Temperature : "+temp);
const feelsLike = weatherData.main.feels_like;
console.log("Feels like : "+feelsLike);
const weatherDescription = weatherData.weather[0].description;
console.log("Weather Description : "+weatherDescription);
const icon= weatherData.weather[0].icon;
imageURL = "http://openweathermap.org/img/wn/"+icon+"#2x.png"
// Method 1
//response.send("<h2>The temperature in Montreal, Quebec is "+temp+" degrees Celcius.</h2><br><h2>The weather is currently "+weatherDescription+"</h2><br><h2>The feels like temperature is "+feelsLike+" degrees Celcius. </h2>")
// Method 2
res.set("Content-Type", "text/html");
res.write("<h2>The temperature in "+query+" is "+temp+" degrees Celcius.</h2>")
res.write("<p>The weather is currently "+weatherDescription+"</p>")
res.write("<h4>The feels like temperature is "+feelsLike+" degrees Celcius. </h4>")
res.write("<img src="+imageURL+">");
res.send();
});
});
})
app.listen(3000, function(){
console.log("Server is running on port 3000.");
})
My index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Weather Project</title>
</head>
<body>
<form action="/" method="post">
<label for="city-input">City Name: </label>
<input id="city-input" type="text" name="cityName" />
<button type="submit">Go</button>
</form>
</body>
</html>
When I test this app.js on my local server it shows the expected response, i.e. the temperature of the city that I send in POST request. But when I run the project using my Github pages link it shows the index.html but when I send the city as POST request,I get a 405 error on the next page. I am new so I am not sure what is wrong but my initial thought was that it is something related to the API key? as in the key ID?
Please help.
It seems like github repo doesn't support the post requests. Did you try using the different hosting platform like firebase?
this is my second question here on stack overflow.
I am currently doing a course on udemy on node.js from "0" to "expert", now keep in mind my carrer as a developer focuses on front-end not back-end or even middle-ware in particular, this is just a course that I payed for because I feel it complements very well my carrer and the topic is of high interest to me.
Now with the problem... We started working with pug and handlebars, previously we were working with express.js. Every since I installed pug and translated one of the pages from the webpage we are building on the course from vanilla html to pug the server is throwing the "cannot GET /admin/add-product". Now I understand this error is based on the logic end of everything cause the server clearly states it's not able to obtain the specific route where the "add-product.html" code is located. Where i'm confused is that the code is the same the teacher has, and in the videos this error won't show up, I tried to put a question as a comment on the course's comment section but it hasn't been answered and this is keeping me from continuing with the material. It would be of great value if someone here would look over the code (which I will be posting in this question) and gives me a hand cause at this point i'm completely lost.
Thanks you very much stack overflow community
Project code:
app.js:
const path = require('path');
const http = require('http');
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.set('view engine', 'pug');
app.set('views', 'views');
const adminData = require('./routes/admin');
const userRoutes = require('./routes/user');
app.use(bodyParser.urlencoded({extended: true }));
app.use(express.static(path.join(__dirname, 'public')));
app.use('/admin', adminData.routes);
app.use(userRoutes);
// app.use((res, req, next) => {
// res.status(404).sendFile(path.join(__dirname, 'views', ''));
// });
const server= http.createServer(app);
server.listen(3000);
admin.js:
const path = require('path');
const express = require('express');
const rootDir = require('../util/path');
const router = express.Router();
const products = [];
router.get('/admin', (req, res, next) => {
res.sendFile(path.join(rootDir, 'views', 'add-product.html'));
});
router.post('/admin', (req, res, next) => {
products.push({title: req.body.title})
res.redirect('/');
});
exports.routes = router;
exports.products = products;
user.js:
const path = require('path');
const express = require('express');
const rootDir = require('../util/path');
const adminData = require('./admin');
const router = express.Router();
router.get('/', (req, res, next) => {
const products = adminData.products;
res.render('shop', {prods: products, docTitle: 'Shop'});
});
module.exports = router;
path.js:
const path = require('path');
module.exports = path.dirname(require.main.filename);
add-product.html:
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Add product page</title>
<link rel="stylesheet" href="/css/main.css">
<link rel="stylesheet" href="/css/product.css">
</head>
<body>
<header class="main-header">
<nav class="main-header__nav">
<ul class="main-header__item-list">
<li class="main-header__item"><a class="active" href="/">SHOP PAGE</a></li>
</ul>
</nav>
</header>
<main>
<form class="product-form" action="/admin/add-product" method="POST">
<div class="form-control">
<label for="title">Title</label>
<input type="text" name="title" id="title">
</div>
<button type="submit">ADD PRODUCT</button>
</form>
</main>
</body>
</html>
shop.pug:
<!DOCTYPE html>
html(lang="en")
head
meta(charset="UTF-8")
meta(name="viewport", content="width=device-width, initial-scale=1.0")
meta(http-equiv="X-UA-Compatible", content="ie=edge")
title #{docTitle}
link(rel="Stylesheet", href="/css/main.css")
link(rel="Stylesheet", href="/css/products.css")
body
header.main-header
nav.main-header__nav
ul.main-header__item-list
li.main-header__item
a.active(href="/") Shop
li.main-header__item
a(href="/admin/add-product") Add Product
main
.grid
each product in prods
article.card.product-item
header.card__header
h1.product__title #{product.title}
.card__image
img( src="https://www.vecteezy.com/photo/1224769-open-book-on-dark-background", alt=" a book ")
.card__content
h2.product__price $19.99
p.product__description A ver interesting book about so many even more intersting things!
.card__actions
button.btn Add to Cart
Thanks for your time everyone
Not sure, I guess the path of line 11 and 15 in admin.js should be '/add-product' instead of '/admin'. i.e.
router.get('/add-product', (req, res, next) => {
In your code, the only route under /admin is /admin/admin with method GET or POST. You can try GET /admin/admin and see if it's the expected result. if true, that indicates you wrote a wrong path in line 11 and 15 in admin.js
If you want to GET /admin/add-product, you'll need a route in admin.js which path is /add-product, since all request with a path begins with /admin are handled by adminData.routes at line 18 in app.js
My folder structure is :
APP
-public
main.js
-views
index.html
index.js
I am trying to serve the static file to express server but its not working. The code for this in my index.js file is:
const express = require('express'),
app = express();
app.use(express.static(__dirname+'/public'));
I have also tried using path.join syntax
In my index.html file in the views folder , I am using the src tag as 'main.js'
<script type="text/javascript" src="main.js"></script>
I get the error net::ERR_FILE_NOT_FOUND.
I can also see that path src is referring to is wrong.
It is looking for main.js file in views directory instead of looking in public directory.
I have looked at other answers. I understand the syntax theoretically but am not able to find what I am doing wrong
Please point out the issue in my code. Thanks
Here is a working example:
index.js:
const express = require('express');
const path = require('path');
const app = express();
const port = 3000;
app.use(express.static(__dirname + '/public'));
app.get('/', (req, res) => {
res.sendFile(path.resolve(__dirname, './views/index.html'));
});
app.listen(port, () => console.log(`server is listening on port ${port}`));
./public/main.js:
window.onload = function() {
console.log('onload');
};
./views/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script type="text/javascript" src="main.js"></script>
</head>
<body>
This is template
</body>
</html>
I am new to Nodejs and trying to use weather api.
When I test the link in browser, it gives me accurate answer
http://api.openweathermap.org/data/2.5/weather?q=karachi&appid=dcf486a78f2b8e898c4b1a464a1b31e1
while it keeps throwing error.
const express = require("express")
var logger = require("morgan")
var path = require("path")
var bodyParser = require("body-parser")
let requested = require('request');
var app=express()
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.set("views", path.resolve(__dirname,"views"))
app.set("view engine",'ejs')
app.use(logger("short"))
app.get("/",function(request,response)
{
response.render("homepage")
})
app.post('/', function(request, response) {
var urlOpenWeatherCurrent = 'http://api.openweathermap.org/data/2.5/weather?'
var queryObject = {
APPID: "dcf486a78f2b8e898c4b1a464a1b31e1",
city: request.body.cityName
}
console.log(queryObject)
requested({
url:urlOpenWeatherCurrent,
q: queryObject // In many tutorials they used 'qs' instead of 'q'. I don't know why.
}, function (err, response, body) {
// response.send('You sent the name ' + request.body.cityName + ".");
if(err){
console.log('error:', error);
} else {
console.log('body:', JSON.parse(body));
}
});
});
app.use(function(request,response)
{
response.status(404)
response.send("Error")
})
app.listen(3000,()=>console.log("Working"))
Error
{ APPID: 'dcf486a78f2b8e898c4b1a464a1b31e1', city: 'karachi' }
'Invalid API key. Please see http://openweathermap.org/faq#error401 for more info.'
If I change q to qs in nodejs, then
{ APPID: 'dcf486a78f2b8e898c4b1a464a1b31e1', city: 'karachi' }
body: { cod: '400', message: 'Nothing to geocode' }
Note that changing q to qs in raw html API link also gives
{"cod":"400","message":"Nothing to geocode"}
I believe from the response that I should use qs in nodejs, because at least this time it is not considering API key wrong. But in the API link, we have q and not qs. So how come qs makes sense? Besides, as far as I Understood, it is not properly concatenating the API strings together, resulting in the malfunctioning. But I don't know how to print the entire link in console to validate what I just said.
views/homepage.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form class="pure-form" action="/" method="POST">
<input type="name" placeholder="City name" name="cityName" autofocus required>
<input type="submit" valuue="Go">
</form>
</body>
</html>
embed the "q" and "api key" with open weather url like "http://api.openweathermap.org/data/2.5/weather?q=${city}&units=imperial&appid=${apiKey}"
also Check this link
https://codeburst.io/build-a-weather-website-in-30-minutes-with-node-js-express-openweather-a317f904897b
I'm using EJS as Template engine. Everything looks like working fine, but I have these weak "Unresolved variable or type data" warnings in IntelliJ. How to get rid of these warnings? Is anything wrong with the code?
app.js:
var express = require('express');
var app = express();
var hostname = 'localhost';
var port = 3000;
app.set('view engine', 'ejs');
app.use('/static', express.static('static'));
app.get('/', (req, res) => {
res.sendFile(`${__dirname}/index.html`);
});
app.get('/profile/:id', (req, res) => {
var userData = {
id: req.params.id,
firstName: 'John',
lastName: 'Peterson',
age: 23,
active: true,
interests: ['Design', 'Web', 'Acting']
};
res.render('profile', { data: userData });
});
app.get('*', (req, res) => {
res.sendFile(`${__dirname}/404.html`);
});
app.listen(port);
console.log(`Server running at http://${hostname}:${port}`);
views/profile.ejs:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>My Profile</title>
<link rel="stylesheet" href="../static/style.css">
</head>
<body>
<h2>My Profile Template</h2>
<p>ID: <%=data.id%></p>
<p>Name: <%=data.firstName%> <%=data.lastName%></p>
<p>Age: <%=data.age%> years</p>
<p>Active: <%=data.active%></p>
</body>
</html>
I solved this problem, by adding spaces between %=%.
<p>Name: <%= data.firstName %> <%= data.lastName %></p>
It looks like you need to export the data object somewhere in your code.
Try to add module.exports = { data: {}; } to the end of your app.js file.
To make autocomplete work correctly, you should either export a real object (userData) instead of an empty one, or use TypeScript.