I'm trying to serve a front end with Koa (v2). Eventually, I want to use React. But for now, I'm simply trying to serve a simple html file.
app/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
server.js
import 'babel-polyfill';
import koa from 'koa';
import koaRouter from 'koa-router';
import serve from 'koa-static';
import mount from 'koa-mount';
const app = new koa();
const router = new router({ prefix: '/koa' });
// This route works
router.get('/', async (ctx) => {
ctx.body = 'Hello from Koa!';
});
app.use(router.routes());
const front = new koa();
// This route doesn't work.
front.use(serve(__dirname + '/app'));
// However, this will work, so then, I'm not using koa-serve correctly?
// front.use(async (ctx) => {
// ctx.body = "Mount this.";
// });
app.use(mount('/', front));
app.listen(3000);
So how do I serve the front-end?
I've used a similar code and it worked for me, strange, almost like your example, just that I'm not using async
const koa = require('koa');
const koaRouter = require('koa-router');
const mount = require('koa-mount');
const serve = require('koa-static');
const app = new koa();
const router = new koaRouter({ prefix: '/koa' });
router.get('/', function *() {
this.body = 'Hello from Koa!';
});
app.use(router.routes());
const front = new koa();
front.use(serve(__dirname + '/app'));
app.use(mount('/', front));
app.listen(3000);
Try using koa-sendfile, just to test it out. I've got other example below
Note that I'm using koa-route, not koa-router like in your example
And also, there's a folder called "app" that contains the "index.html"
'use strict';
const koa = require('koa');
const router = require('koa-route');
const mount = require('koa-mount');
const sendfile = require('koa-sendfile');
const serve = require('koa-static');
const app = koa();
const ui = koa();
const api = koa();
// API Mount
function *apiCall() {
this.body='response from api';
}
api.use(router.get('/', apiCall));
// UI Mount
// you have 2 ways:
// // 1. Using koa-sendfile
// function *serveIndex() {
// this.body='response from ui';
// yield sendfile(this, __dirname + '/app/index.html');
// if (!this.status) this.throw(404);
// }
// ui.use(serveIndex);
// 2. Using koa-static
ui.use(serve('app'));
app.use(mount('/api', api));
app.use(mount('/', ui));
app.listen(3000);
Related
I will explain the problems in more detail.
I'm trying to do a really simple little practice. Through a link, the ID of an Instagram post is passed as a parameter.
After this, '? __ a = 1' is added to the URL for subsequent data processing once the JSON object has been obtained.
On localhost this works fine and I get the JSON object. But once deployed as a function in Firebase, although it accepts the request without errors, it does not return a JSON object. Instead it returns HTML content, like this:
"<!DOCTYPE html>\n<html lang=\"en\" class=\"no-js not-logged-in client-root\">\n <head>\n <meta charset=\"utf-8\">\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n\n <title>\nLogin • Instagram\n</title>\n\n
....
Does anyone know what is causing this problem?
...
Localhost:
Deployed like a Firebase Function:
I briefly attach the code of my application.
index.js
const functions = require('firebase-functions');
const server = require("./src/server");
const d = functions
.runWith({
memory: "2GB",
timeoutSeconds: 120
})
.https
.onRequest(server);
module.exports = {d};
server/index.js
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
const app = express();
app
.use(cors({origin: true}))
.use(bodyParser.json())
.use(bodyParser.urlencoded({extended: false}))
.use("/", require("./route"))
.get('*', (_, res) =>
res.status(404)
.json({success: false, data: "Endpoint not found"}));
module.exports = app;
server/route.js
const router = require("express").Router();
const controller = require("./controller");
router.get("/:url", controller.getImageVideo);
module.exports = router;
server/controller.js
'use strict'
const axios = require('axios');
async function getImageVideo(req, res) {
const URL_id = req.params.url;
const URL = 'https://www.instagram.com/p/' + URL_id + '?__a=1';
const metadata = await axios.get(URL);
const test = metadata.data;
return res
.json({
test
});
}
module.exports = {
getAllLanguages,
getImageVideo
}
I'm not getting expected results by including files in Nodejs. Here is my code:
Service Route File
const express = require('express');
const router = express.Router();
const path = require('path');
const config = require('../config');
const serviceAdapter = require('./serviceAdapter');
module.exports = (preRequestPath, serviceBaseUrl) => {
console.log("On server start", preRequestPath)
router.post('/*', (req, res) => {
console.log("On request", preRequestPath)
const axiosHttp = serviceAdapter(serviceBaseUrl);
axiosHttp.post(preRequestPath+req.path, req.body).then(resp => {
res.send(resp.data)
}).catch(err => {
res.status(404).sendFile(path.join(__dirname + '/../404.html'));
});
});
return router;
}
Main Server File
const express = require('express');
const userApiService = require('./routes/userService');
const userAdminService = require('./routes/userService');
app.use('/api/user_service/', userApiService("/api", config.userServiceUrl) );
app.use('/admin/user_service/', userAdminService("/admin", config.userServiceUrl) );
var server = app.listen(3000, function(){
console.log('Server listening on port 3000');
});
module.exports = server;
Expecting Console Result:
On server start /api
On server start /admin
On request /api (when hitting http://baseurl.com/api/<anything>)
On request /admin (when hitting http://baseurl.com/admin/<anything>)
But Getting Console Output as:
On server start /api
On server start /admin
On request /api (when hitting http://baseurl.com/api/<anything>)
On request /api (when hitting http://baseurl.com/admin/<anything>)
Both the time, returning /api path.
Can anyone tell me why is it happening and what's the solution?
You're creating only one router in userService.js (the first file). It's created once before the function so you really only end up with one router. The first time you require it the router gets created, but the second time you require it Node knows it was already loaded and it's not re-initialized. You should be creating a different router for each case like this:
const express = require('express');
// const router = express.Router(); <-- don't do it here
const path = require('path');
const config = require('../config');
const serviceAdapter = require('./serviceAdapter');
module.exports = (preRequestPath, serviceBaseUrl) => {
const router = express.Router(); // <--- create a new router for each case
console.log("On server start", preRequestPath)
router.post('/*', (req, res) => {
console.log("On request", preRequestPath)
const axiosHttp = serviceAdapter(serviceBaseUrl);
axiosHttp.post(preRequestPath+req.path, req.body).then(resp => {
res.send(resp.data)
}).catch(err => {
res.status(404).sendFile(path.join(__dirname + '/../404.html'));
});
});
return router;
}
Also in your main server file you only need to require it once. It's just a function to create the service so you don't need 2 different variables holding that function. So you can initialize both using the one function like this:
// const userApiService = require('./routes/userService');
// const userAdminService = require('./routes/userService');
const service = require('./routes/userService');
app.use('/api/user_service/', service("/api", config.userServiceUrl) );
app.use('/admin/user_service/', service("/admin", config.userServiceUrl) );
I am trying to add a method
loadSiteSettings to express module
In app.js
var express = require('express');
var path = require('path');
var mongoose = require('mongoose');
//Set up default monggose connection for mongo db
var mongoDB = 'mongodb+srv://***:*****#cluste******j.mongodb.net/cms?retryWrites=true&w=majority';
mongoose.connect(mongoDB,{useNewUrlParser: true});
//Get the default connection
var db = mongoose.connection;
//Bind connection to error event (to get notification of connection errors)
db.on('error',console.error.bind(console, 'MongoDB connection error:'));///????????
var app = express();
///////////////////////////////////////////////////////////
var indexRouter = require('./routes/index');
app.loadSiteSettings = async function()
{
let setting = await db.collection('settings').findOne();
app.locals.siteSettings = setting;
}
app.loadSiteSettings();
//////////////////////////////////////////////////////
module.exports = app;
Index.Js for router
var express = require('express');
var router = express.Router();
var app = require('../app');
var util = require('util');
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index');
});
///////////////////////////////////////////
router.get('/reloadSettings', function(req,res,next){
app.loadSiteSettings();
})
///////////////////////////////////////
module.exports = router;
so problem lies here, when server start it calls app.loadSiteSettings() in app.js
but when i use route '/reloadSettings' it seems app is undefined in index.js
This is an issue with circular dependencies and module.exports. This answer shows the same problem.
What's happening is app.js is required first and starts processing. The important thing to understand is that a file pauses execution while requiring a new file.
So when app.js requires ./routes/index, it has not finished processing, and has not reached module.exports = app. This means that when your routes file requires app.js, it's requiring it in its current state, which is the default export {}.
Thankfully there's a very simple fix:
// can be imported and tested separately from the app
const loadSiteSettings = function() {
return db.collection('settings').findOne();
}
router.get('/reloadSettings', async function(req,res,next){
let settings = await loadSiteSettings();
req.app.locals.siteSettings = settings
res.send(200); // signal the response is successful
})
This explains the issue in a lot more depth in case you're interested
All:
I am pretty new to React, right now I am trying how to do server side rendering, I use Express.js as my server, so the code is like:
//server.js
var express = require("express");
var ReactDOMServer = require("react-dom/server");
var MyCom = require("./components");
var domstring = ReactDOMServer.renderToString(MyCom);
var app = express();
app.get("/", function(req, res){
res.json({
name: "new com",
dom: domstring
});
});
And
// components.js
var React = require("react");
var MyCom = React.createClass({
render: function(){
return (<h1>Hello, server side react</h1>);
}
});
module.exports = MyCom;
I use babel to transpile the JSX, but when I start server, I do not know why I keep getting error like:
Invariant Violation: renderToString(): You must pass a valid
ReactElement.
Could anyone give some clue why this not work?
Thanks
Your module exports a ReactComponent, and renderToString accepts a ReactElement (i.e. an instantiated ReactComponent).
In order to render it, you want to instantiate it like so:
ReactDOMServer.renderToString(<MyCom />);
Using a factory allows you to have all your components in separate files and instantiate them without using jsx syntax in your server. Very useful for the main wrapper component.
require('babel-core/register')({
presets: ['react']
});
var express = require('express');
var reactDOM = require('react-dom/server');
var react = require('react');
var app = express();
app.get('/', function (req, res) {
var mainFile = require('./app.jsx');
var output = reactDOM.renderToString(react.createFactory(mainFile)({
data: yourInitialData
}));
res.send(output);
});
I have looked through stackoverflow and read about require. However I cannot understand why my require function does not run.
app.js code:
var http = require('http');
var express = require("express");
var app = express();
//Twitter Search -------------------
app.get("/tweet, function(req,res){
var twiter = require('twiter.js');
});
app.listen(3000);
twitter.js code:
console.log("twitter.js ran");
Make sure both app.js and twitter.js in same directory
And add ./ before it. Just use following
var twitter = require('./twitter'); // .js extension is not necessary
Also as alexey mentioned. twiter is not same as twitter :)
Take care of your typos. (I think I'm too lazy to read it carefully)
app.js
var http = require('http');
var express = require("express");
var app = express();
//Twitter Search -------------------
app.get("/tweet", function (req, res) {
var twitter = require('./twitter');
twitter.log();
});
app.listen(3000);
twitter.js should be exposed using module.exports
var twitter = {
log: function () {
console.log('twitter is loaded');
}
};
module.exports = twitter;
This should now print "twitter is loaded" in your console, when you visit localhost:3000/tweet