I'm new to node. I was using express-handlebars as my view-engine, but now I've added React and I understood that I no longer require handlebars. The problem that I'm having is that in order to get to the index.html page, without handlebars, I had to use
app.use(express.static('./public'));
Everything gets rendered from react, but what if I want to do some other things when the user goes to the index page like
app.get("/",function(req,res){
console.log("connected");
});
If I add the get request after exporting the static files, the console.log never gets called. If I use it before, it does get called, but I can see the page loading forever. How should I structure the application now that I'm using react and I don t have a view engine anymore?
In your specific case, if you don't want to render anything to the user, you should turn your function into a middleware :
app.get("/",function(req,res, next){
console.log("connected");
next();
});
and put it before the app.use(express.static('./public'));
However, if you want to do actual logic with return values and such, I would suggest that you setup some kind of API that you request using Ajax from the client.
You can check my repository
https://github.com/kennethmervin01/react-node-production
it's a boilerplate to serve react app in node.js/express
then check my code inside app.js
You just need to copy the production build of your react app inside the react folder
app.use(express.static(path.join(__dirname, "../react")));
app.get("/*", (req, res) => {
res.sendFile(path.join(__dirname, "../react", "index.html"));
});
Related
I have an app.js node main file where I define my api path as the following
app.get('/api/users', UserController.get);
Below in the same file I have the following
app.use(express.static(path.resolve(__dirname, "./front/build")));
app.get("*", function (request, response) {
response.sendFile(path.resolve(__dirname, "./front/build", "index.html"));
});
The index.html successfully serves React App.
If I open my heroku app somewhere at my-app.herokuapp.com it will open the React app which is intended but the Problem is my-app.herokuapp.com/api/users also serves index.html file instead of JSON that the endpoint is supposed to return.
I tried
I replaced endpoint route definition to come before the "" definition (didn't suffice)
EVEN more, I removed redirection to index.html but heroku still opens the index.html page with any type of request (the "" redirection still works). So, it might have cached something?
Is it about cache (how to clean?) or any other suggestions?
You should create routes and work in a proper flow for each functionality,
For Example:
//app.js
app.use("/api/user",userRoutes);
//UserRoutes
router.post("/signup",UserController.signup);
//UserController
exports.signup = async (req,res,next) => {
//Signup function to add a new user when the user provides required info
}
In this way, you code will be easily accessible and much efficient
When using express, the expectation is that you'll serve a public directory.
const app = express();
app.use('/', express.static('./public/'));
Is there a way I could serve a generated file instead? For my application, it would be much more convenient if I could build the index.html directly, then serve that 'file' directly from memory, without having to save it just to then serve it via 'use'.
the expectation is that you'll serve a public directory
I don't think that is the expectation at all. Many applications just use routes instead making a REST micro service.
There are two ways you can do what you want to do.
Use a templating engine with NodeJS and just res.render() the template. Check this out for more information, even though the article is using .pug you can use these ones as well. Popular ones are ejs, handlebars
app.get('/', function (req, res) {
res.render('index', { title: 'Hey', message: 'Hello there!' })
})
Or you can write everything inside res.send() for example:
app.get('/', function (req, res) {
//set the appropriate HTTP header
res.setHeader('Content-Type', 'text/html');
//send multiple responses to the client
res.send('<h1>This is the response</h1>');
});
Ok, so I'm just starting to learn Vue.js, and man, it's so hard to do things that are very simple when just using EJS for example. I'm close to abandon Vue for my current project, since I just don't know how to pass res.locals.something from Express server to Vue frontend. By the way, it's Passport.js thing - when authenticated, user should be redirected, but I have to pass the info whether user has logged in or not to Vue (res.locals.isLogged = req.isAuthenticated();), and that seems impossible with my current (close to 0) Vue.js skills... The only solution I found was using ajax (axios was my choice) request on the client side, targeting /login/facebook route on the server, and then I could pass the response from Express to Vue, but it cannot work because of the damned CORS issue. So, I cannot use ajax to retrieve the data from Express, and Express and Vue are not natively connected like Express and EJS or Pug for example.
In short - does anyone know of a simple way to pass Express variable to Vue, not including Vue SSR, Express-vue module etc.?
P.S. I'm not using Webpack or anything similar (so, no .vue files etc.) - just a simple index.html file with Vue loaded from CDN.
Ok, one thing that crossed my mind as dirty workaround was using .ejs instead of .html extension, so I could pass the variable to ejs, but I thought it won't work. What I did was just renaming my index.html to index.ejs, passing res.locals.isLogged to ejs template and both Vue and ejs rendered parts of the app are working together, somehow...
So, this is the dirty (sort of) solution...
The question has already been answered but I'm not familiar with .ejs and couldn't follow the solution. For those like me, what I did was :
Sent the data using res.locals or res.render('file.pug', data)
Set the data received as a html data attribute to a tag ( ex : p(id="myParagraph" data-myData= data)
Set the state of the Vuex store using
mounted : function () {
this.$store.state.myData = document.getElementById("myParagraph").getAttribute("data-myData");
}
The same can be used to set the data property of the vue root instance.
From here on you can use the data whenever needed and still retain reactivity.
You're on the right track using res.locals. To get access to the variable in the JS that's in the view, you have to wrap the value in a string: console.log('#{isLogged}'). See example below
app.js
const express = require('express')
const app = express()
app.set('view engine', 'pug')
app.use((req, res, next) => {
res.locals.isLogged = false
next()
})
app.get('/', (req, res) => {
res.render('index')
})
app.listen(3000, () => {
console.log('listening on 3000')
})
views/index.pug
doctype html
html
head
title= title
body
h1= text
script.
console.log('#{isLogged}') // false
Trying to understand how to implement AngularJS in a node.js express app. After setting up express, I need 2 things: routing and a template engine, so normally I would need to do as follows to set the app to use Jade templating engine:
app.register('.html', require('jade'));
...and then I would set routes probably like this:
app.get('/', function(req, res) {
res.render('index', function(err, html){
// ...
});
});
But if I want to use AngularJS for templating, do I still need Jade? And I read about how in AngularJS routes must be configured, does this mean the above way of declaring routes with app.get() would no longer be needed when using AngularJS?
If you don't need to add anything extra to your Angular layout prior to rendering the page for the client (i.e. in some cases you could add a window.user object in the Jade template for authentication when using PassportJS), you can completely ditch Jade altogether and let the Express static middleware render your index.html:
app.use(express.static(path.join(__dirname, 'public')));
Obviously, the files in public/ are all your Angular files, including the index.html. Be sure to require the path module too for path normalization, this isn't required though.
Afterwards, Angular will take care of the rest. This means that all your routes are defined inside the Angular app, and not in the Express routes.
I'm using Express, which loads AngularJS from a static directory. Normally, I will request http://localhost/, in which Express serves me my index.html and all of the correct Angular files, etc. In my Angular app, I have these routes setup, which replace the content in an ng-view:
$routeProvider.when('/', {
templateUrl: '/partials/main.html',
controller: MainCtrl,
});
$routeProvider.when('/project/:projectId', {
templateUrl: '/partials/project.html',
controller: ProjectCtrl,
});
$locationProvider.html5Mode(true);
On my main page, I have a link to <a href="/project/{{project.id}}">, which will successfully load the template and direct me to http://localhost/project/3 or whatever ID I have specified. The problem is when I try to direct my browser to http://localhost/project/3 or refresh the page, the request is going to the Express/Node server, which returns Cannot GET /project/3.
How do I setup my Express routes to accommodate for this? I'm guessing it will require the use of $location in Angular (although I'd prefer to avoid the ugly ?searches and #hashes they use), but I'm clueless about how to go about setting up the Express routes to handle this.
Thanks.
with express 4, you probably want to catch all requests and redirect to angularjs index.html page.
app.use(app.router); doesn't exist anymore and res.sendfile is deprecated, use res.sendFilewith an uppercase F.
app.post('/projects/', projectController.createProject);
app.get('/projects/:id', projectController.getProject);
app.get('*', function (req, res) {
res.sendFile('/public/index.html');
});
put all your API routes before the route for every path app.get('*', function (req, res){...})
I would create a catch-all handler that runs after your regular routes that sends the necessary data.
app = express();
// your normal configuration like `app.use(express.bodyParser());` here
// ...
app.use(app.router);
app.use(function(req, res) {
// Use res.sendfile, as it streams instead of reading the file into memory.
res.sendfile(__dirname + '/public/index.html');
});
app.router is the middleware that runs all of your Express routes (like app.get and app.post); normally, Express puts this at the very end of the middleware chain automatically, but you can also add it to the chain explicitly, like we did here.
Then, if the URL isn't handled by app.router, the last middleware will send the Angular HTML view down to the client. This will happen for any URL that isn't handled by the other middleware, so your Angular app will have to handle invalid routes correctly.
I guess I should have clarified that I wasn't interested in using a template engine, but having Angular pull all of the HTML partials on it's own, Node is functioning completely as a static server here (but it won't be for the JSON API. Brian Ford shows how to do it using Jade here: http://briantford.com/blog/angular-express.html
My app is a single-page app, so I created an Express route for each possible URL pattern, and each of them does the same thing.
fs.readFile(__dirname + '/public/index.html', 'utf8', function(err, content) {
res.send(content);
});
I was assuming I would have to pass some request variables to Angular, but it looks like Angular takes care of it automatically.