Express server configuration issues, the public directory - javascript

I created two separate separate bundles, one for my server and one for my client. However the client bundle is still not getting downloaded by the browser when someone accesses the root route.
I told Express to treat the public/ folder as a freely available public directory here inside of index.js:
app.use(express.static('public'));
app.get('/', (req, res) => {
const content = renderToString(<Home />);
I also added an HTML snippet with an ES6 template string like so:
import express from 'express';
import React from 'react';
import { renderToString } from 'react-dom/server';
import Home from './client/components/Home';
const app = express();
app.use(express.static('public'));
app.get('/', (req, res) => {
const content = renderToString(<Home />);
const html = `<html><head><body><div>${content}</div><script src="bundle.js"></script></body></head></html>`;
res.send(content);
});
The idea is when a user gets a response from this endpoint they will see the content from the <Home /> component, but also tell the users browser to go back to my server and download the bundle.js file.
The expectation is that I refresh the page and instantly retrieve localhost and make a request for bundle.js file and see the console log I added in the Home.js component:
import React from 'react';
const Home = () => {
return (
<div>
<div>I am an OK home component</div>
<button onClick={() => console.log('Howdy!')}>Press me!</button>
</div>
);
};
export default Home;
I refreshed the browser and did not see the console log nor a bundle.js file in Network tab.
What gives here?

So I created the variable html where I stored the HTML from the template string with the bundle.js file in it, but then I don't use that variable anywhere.
I had to replace res.send(content); with res.send(html);.

Related

Why is the Router() Express function returning undefined?

I'm using TypeScript and Express to create an API that follows the principles of Clean Architecture. I separated each route of my application in a folder, and then I import all of them into an index.ts file, merging each one inside an unique router and exporting the same. My problem is that the importation of this unique file is returning undefined.
I think that is isn't a problem of my code itself, since TypeScript can infer correctly the type of the imported file and doesn't report any error during development. The only error I get just happens when trying to run the code:
TypeError: app.use() requires a middleware function
This is the code snippet that causes the error:
// expressInstance.ts --> Imported by the "server.ts" file, where listening the server happens
import express from "express";
import cors from "cors";
import { router } from ".."; // File with all the routes
const expressInstance = express();
expressInstance.use(express.urlencoded({extended: false}));
expressInstance.use(express.json());
expressInstance.use(cors());
expressInstance.use(router); // Line where the error appears
export {
expressInstance
};
And this is the code of the imported router file:
// index.ts
import { Router } from "express";
import { userRouter } from "./user.routes";
import { postRouter } from "./post.routes";
const router = Router();
router.use("/user", userRouter);
router.use("/post", postRouter);
export {
router
};
I read in another question that the undefined return used to happen at Express version 3, but I use the 4.17.13 version, so I think this isn't the cause of the problem. In fact, I have no idea what could be. I tried to see the router content by using console.log(router) in the index.ts file (before being imported by expressInstance.ts), but it didn't work, because the code wasn't even executed.
Try adding a path to your .use()
e.g:
expressInstance.use('/users', router); // in the case you wanted the router to be for users

Nodejs how can I add another main app.js and use both of them to make my code clean?

Hello I'm using nodejs and express framework and I wrote all my serverside code into my app.js file but it's little bit complicated for me cause cause I have almost 250 line code and I want to implement authentication now so I want to create another app.js to write my code only for auth so other code will not confuse me how can I do that????
UPDATED
as you se above I have 2 post requests from my app.js I asking that how I will get thoso request in my auth.js file cause as I understand exports import for static js field I want to take request and save that information my database and I want to that in my auth.js file
Here are a simplified structure for your project derived from my project at this link.
routes.js:
Create a file named route.js where you define all the routes for your application. In this case the routes will be only the register and the login routes that will be handled by the UserController module.
import { Router } from 'express';
import UserController from './UserController';
const router = Router();
router.post(
'/register',
UserController.register
);
router.post(
'/login',
UserController.login
);
export default router;
UserController.js:
This file/class that handle all the operations for the creation and login of an user
As you can see all the methods has no route url because they are called directly from our route.js file. We are dividing and structuring your application!
export default class UserController {
public static register(req, res) {
// Register operation
}
public static login(req, res) {
// Login operation
}
}
app.js
The entry point and where you are configuring your express application.
import express from 'express';
import routes from './routes';
const app = express();
// configure app ...
// Here we attach our routes url to the express app
app.use('/', routes)
Hope it helps :)
depending on your setup you can divide your files in per example:
app.js
authentication.js
and then either require or import functions from the authentication.js file into app.js like this:
import express from "express";
or this:
const express = require("express");
functions inside the authentication file should be exported like this:
//needs to be imported as this: import {authenticate} from "authenticate";
export function authenticate(){};
//needs to be imported as this: import authenticate from "authenticate";
function authenticate(){};
export default authenticate;
or this:
// needs to be imported as this: const authenticate = require("authenticate");
module.exports = function authenticate(){};
See this guide on enabling ES6 imports as shown above. this has the preference for it can save on memory when importing.

Is it possible to use application level middleware in express router?

I've been playing around with setting up a basic atlassian-connect-express (ACE) application, and have modified the starter code provided by the ACE package to be suitable for serverless deployment. One of the problems I faced after doing this was that routing is now divided into stages, e.g. /dev, /prod. I did a bit of research and found that a way to deal with this would be to use an express Router and mount it to the appropriate endpoint for the stage being deployed to. The problem I then faced is that the authentication middleware provided by ACE seems to be application level and then can't be used by each router.
Typically the routes were added to the express app like this:
import ace from 'atlassian-connect-express';
import express from 'express';
import routes from './routes';
const app = express();
const addon = ace(app);
app.use(addon.middleware());
routes(app, addon);
and in ./routes/index.js
export default function routes(app, addon) {
// Redirect root path to /atlassian-connect.json,
// which will be served by atlassian-connect-express.
app.get('/', (req, res) => {
res.redirect('/atlassian-connect.json');
});
// This is an example route used by "generalPages" module (see atlassian-connect.json).
// Verify that the incoming request is authenticated with Atlassian Connect.
app.get('/hello-world', addon.authenticate(), (req, res) => {
// Rendering a template is easy; the render method takes two params:
// name of template and a json object to pass the context in.
res.render('hello-world', {
title: 'Atlassian Connect'
});
});
// Add additional route handlers here...
}
I've changed ./routes/index.js to work as a router object and export that, however this leaves me unable to use the addon.authenticate() middleware
import ace from 'atlassian-connect-express';
import express from 'express';
import routes from './routes';
const app = express();
const addon = ace(app);
app.use('/dev', require('./routes'));
and in ./routes/index.js
const express = require('express');
const router = express.Router();
// Redirect root path to /atlassian-connect.json,
// which will be served by atlassian-connect-express.
router.get('/', (req, res) => {
res.redirect('/atlassian-connect.json');
});
// This is an example route used by "generalPages" module (see atlassian-connect.json).
// Verify that the incoming request is authenticated with Atlassian Connect.
router.get('/hello-world', addon.authenticate(), (req, res) => {
// Rendering a template is easy; the render method takes two params:
// name of template and a json object to pass the context in.
res.render('hello-world', {
title: 'Atlassian Connect'
});
});
module.exports = router;
Obviously having no knowledge of addon, the router cannot use that authentication middleware.
Is it possible to pass that middleware through to the router when attaching it to the application? If not, is there another way I can handle URL prefixes without using a router?

React and Dynamic Routes including Filename and Extension

I am new to React and trying to put a CMS driven application together as kind of a POC. I am majorly stuck on how to get a full URL (including filename and ext) into a dynamic route in a React application. For example if I call this
http://localhost:8080/en/us/fly/index
The dynamic route picks it up. But if I call this
http://localhost:8080/en/us/fly/index.html
I get the following error. Cannot GET /en/us/fly/index.html
It is a requirement that I handle all URLs through my route even if they have a file extension & filename. My routes.jsx is as follows:
import React from 'react';
import {
Switch, Route
} from 'react-router-dom';
// Pages
import Page from "./pages/Page";
class Routes extends React.Component {
render() {
return (
<Switch>
<Route path="/:page" component={Page} />
</Switch>
)
}
}
export default Routes;
and my server.js is as follows:
const path = require('path')
const express = require('express');
const app = express();
const port = process.env.PORT || 8080;
// get an instance of router
const router = express.Router();
// serve static assets normally
router.use(express.static(__dirname + '/dist'))
router.get('*', function (request, response){
response.sendFile(path.resolve(__dirname, 'dist', 'index.html'))
})
// apply the routes to our application
app.use('/', router);
app.listen(port);
console.log('Site available on port ' + port);
How can I get all URLs to pass through my dynamic route? Is this even possible? I need to know if there are limitations in React that prevent this vs how it would work in a traditional ASP.Net MVC application where I can do this kind of dynamic routing.
Any help or advice on this will be very much appreciated as I am very stuck with this and don't fully understand the React world enough to find the solution.
Thanks in advance,
You can use *.* in your route. It matches with file extensions as below
<Route path="*.*" component={YOUR_COMPONENT}/> // matches /hello.jpg and /hello.html
Then you can access the props in your component as
// CMS name: sample.html
this.props.params.splat[0] // For name of prop without extension. It Will give 'sample'
this.props.params.splat[1] // For extension itself. It will give 'html'

Express.js app entry point

It appears some route middleware is running before index.js, which is crashing my application because the order of execution prevents me from loading my dotenv file on time.
I would like to load my dotenv file before everything in order to make sure that all modules that require it will have access to it.
However, while debugging this issue, I noticed that a console.log at the top of the app entry point still doesn't log first.
Folder structure:
src
------index.js
middleware
------auth.js
routes
------auth.route.js
------index.js
.env
Code that logs first middleware/auth.js:
import { Strategy as JwtStrategy, ExtractJwt } from 'passport-jwt'
module.exports = function() {
console.log('this prints first with undefined', process.env.JWT_SECRET) <-------
which gets called in auth.route.js
import auth from '../middleware/auth'
const userRouter = express.Router()
userRouter.get('/dashboard', auth().authenticate(), function(req, res) {
res.send('Authenticated, user id is: ' + req.user.id)
})
index.js file:
console.log("this prints second"); <---------
(...)
import routes from './routes'
import express from 'express'
import auth from './middleware/auth'
require('dotenv').config({ silent: process.env.NODE_ENV === 'production' })
const app = express();
(...)
app.use('/api', routes);
It's not clear from the code fragments in your question where the problem, because I think you've omitted the place where you import the auth.route.js module.
The answer that follows assumes that you actually import auth.route.js in the index.js file, probably before importing middleware/auth (which isn't actually used in the code fragment you posted). So, based on that assumption, here's what's probably happening:
The thing to keep in mind is that code in a module is executed when it is imported. This doesn't affect middleware/auth at first, since all it does is declare a function. But it does affect auth.route.js - look at what that module does:
It imports the auth function from middleware/auth module, which calls the userRouter.get() function. One of the arguments to that function is a call to the auth() function.
If you're importing auth.route.js in your code (and I suspect you are), then that's where the auth function is getting called prematurely.
Now, how to fix this? It's actually pretty easy: the auth.route.js file should export a function which is called to initialize the routes when you're ready, like this:
auth.route.js
import auth from '../middleware/auth'
const userRouter = express.Router()
export default () => {
userRouter.get('/dashboard', auth().authenticate(), function(req, res) {
res.send('Authenticated, user id is: ' + req.user.id)
})
return userRouter;
}
And when you're ready to initialize the routes (ie. when everything else is set up).
import getRouter from './modules/auth.route.js';
app.use('/api', getRouter());

Categories

Resources