react-router, resolve URL beyond root - node.js

I have a create-react app with react-router-dom. It works quite well if I start from the root (i.e. '/') and then follow links defined in Links. But if I try to load the app not from the root path, it says
Cannot GET /<path>
As I understand, this should be set on the server-side (I am working on regular localhost:9000). Or not? Anyway, how to achieve this practically?
Notice, this is not relevant to the base path resolving problem, described here: Can I set a base route in react-router
UPDATED:
I suppose, there should be a solution similar to using .htaccess. But I still cannot figure out how to apply it to create-react-app. Or, maybe, it is possible to set an appropriate option in webpack.config.js?
Update 2. Repo is here: https://github.com/srgg6701/react-mini

Since all your routes are handled by a router, which normally sits in the '/' (index) path, you would need to fallback to your index so that the router knows where to redirect. This can be done by setting the paths on your server side, but I've found this package to be particularly helpful in these matters.
Webpack
If you are using webpack-dev-server, you should know that it serves the following (taken from official docs):
Use webpack with a development server that provides live reloading.
This should be used for development only.
It uses webpack-dev-middleware under the hood, which provides fast
in-memory access to the webpack assets.
...
Either method will start a server instance and begin listening for
connections from localhost on port 8080.
This means that a server will be running listening to localhost. You can either solve this by using the previous approach (server side coding or middleware) or by using the history api fallback option:
"scripts": {
"start": "webpack-dev-server --history-api-fallback --config webpack.dev.config.js",
"build": "webpack"
},
Have a look at the official documentation of webpack for more info on all of its components.

Related

How to use CAS authentication with angular2 webpack starter typescript?

I am using the following:
https://github.com/gdi2290/angular-starter
I start the application with npm start that uses webpack dev server. My issue is I want to add CAS authentication, but have no idea where what goes. This is the library I am trying to use:
https://github.com/TencentWSRD/connect-cas2
All the examples appear to use express, though I am not sure if I can use this with the webpack-dev-server as is with the starter I am using? If so, how do I use it? Or do I need a different CAS library that is compatible with the npm start?
Webpack is more of a build tool with minimal server capability. It can serve static content making it perfect for updating content on the fly and put together simple websites with basic routing and client side side logic.
If you want anything even a little more complex you will need a server side technology. So the connect-cas2 will require you to use node.js and express. The documentation shows you exactly how to set it up.
I don't know anything about connect-cas2 but I know passport for authentication, but they wouldn't be terribly different. I would follow the quick start and if you have any issues then edit your question with the code that you are having issues with or have trouble understanding.
I have been digging around and you might be able to proxy the authentication if you already have a CAS server setup somewhere. I would try the following:
// the proxy option is part of the devServer in your webpack.config.js
devServer: {
contentBase: 'public',
// setup a proxy
proxy: {
// just replace the /cas/validate endpoint to the endpoint in your
// website that will trigger the api call
'/cas/validate': 'https://url-to-your-cas-server.com'
}
},

Webpack somehow bypasses Express routing completely

I am starting from this excellent tutorial: https://www.fullstackreact.com/articles/using-create-react-app-with-a-server/ and trying to extend it by adding a new page to serve through a new route. However after hours of mucking around I am realizing that somehow create-react-app is doing some weird magic (as mentioned in their docs here):
`create-react-app` configures a Webpack development server to run on `localhost:3000`.
This development server will bundle all static assets located under `client/src/`.
All requests to `localhost:3000` will serve `client/index.html` which will include Webpack's `bundle.js`.
The key quote is "All requests to localhost:3000 will serve client/index.html". I have no idea how this happens. So even though i mess around with routes/index.js:
app.route('/')
.get(function (req, res) {
res.sendFile(bipath.join(__dirname, '../public', 'THISCANBEANYRANDOMFILENAME.html'))
});
it doesnt matter because webpack is somehow directing localhost:3000 to index.html anyway. where and how is it doing this? Bottom line I am trying to modify my routes to serve a new html file and am running into all sorts of filepath issues (yes, even when i use require('path') or sendFile(...,{root: __dirname}).)
So what exactly is going on here and can you give me any hints to help me out?
Edit: this could be from babel as well as webpack - i'm not exactly clear where babel hands off and where webpack starts.
I haven't played around with create-react-app, but it seems like instead of using the default npm start, you could create your own server file and run that.
This looks like a good example.
https://medium.com/#patriciolpezjuri/using-create-react-app-with-react-router-express-js-8fa658bf892d#.6y4rrl61q
Alternatively, if you're looking to have routes used as an api, you could proxy them to a different port like shown in the tutorial you linked.

Webpack for back-end?

I was just wondering, I started using Webpack for a new project and so far it's working fine. I almost would say I like it better than Grunt, which I used before. But now I'm quite confused how and or I should use it with my Express back-end?
See, I'm creating one app with a front-end (ReactJS) and a back-end (ExpressJS). The app will be published on Heroku. Now it seems like I should use Webpack with ExpressJS as well to get the app up and running with one single command (front-end and back-end).
But the guy who wrote this blogpost http://jlongster.com/Backend-Apps-with-Webpack--Part-I seems to use Webpack for bundling all back-end js files together, which is in my opinion really not necessary. Why should I bundle my back-end files? I think I just want to run the back-end, watch my back-end files for changes and use the rest of Webpack's power just for the front-end.
How do you guys bundle the front-end but at the same time run the back-end nodejs part? Or is there any good reason to bundle back-end files with Webpack?
Why to use webpack on node backend
If we are talking about react and node app you can build isomorphic react app. And if you are using import ES6 Modules in react app on client side it's ok - they are bundled by webpack on the client side.
But the problem is on server when you are using the same react modules since node doesn't support ES6 Modules. You can use require('babel/register'); in node server side but it transipile code in runtime - it's not effective. The most common way to solve this problem is pack backend by webpack (you don't need all code to be transpile by webpack - only problematic, like react stuff in this example).
The same goes with JSX.
Bundling frontend and backend at the same time
Your webpack config can have to configs in array: one for frontend and second for backend:
webpack.config.js
const common = {
module: {
loaders: [ /* common loaders */ ]
},
plugins: [ /* common plugins */ ],
resolve: {
extensions: ['', '.js', '.jsx'] // common extensions
}
// other plugins, postcss config etc. common for frontend and backend
};
const frontend = {
entry: [
'frontend.js'
],
output: {
filename: 'frontend-output.js'
}
// other loaders, plugins etc. specific for frontend
};
const backend = {
entry: [
'backend.js'
],
output: {
filename: 'backend-output.js'
},
target: 'node',
externals: // specify for example node_modules to be not bundled
// other loaders, plugins etc. specific for backend
};
module.exports = [
Object.assign({} , common, frontend),
Object.assign({} , common, backend)
];
If you start this config with webpack --watch it will in parallel build your two files. When you edit frontend specific code only frontend-output.js will be generated, the same is for backend-output.js. The best part is when you edit isomorphic react part - webpack will build both files at once.
You can find in this tutorial explanation when to use webpack for node (in chapter 4).
This is my second update to this answer, which is beyond outdated by now.
If you need full a stack web framework in 2023, I'd recommend nextjs (which is built on top of react). No need to go around setting up anything, it just works out of the box, and is full stack.
On the other hand, if you need to compile your nodejs project written in typescript (which you should use as much as you can for js projects), I would use tsup-node.
You don't need to be a genius to imagine that in 3-5 years I'll come back to this and say this is really outdated, welcome to javascript.
This answer is outdated by now since node now has better support for ES modules
There's only a couple of aspects I can redeem the need to use webpack for backend code.
ES modules (import)
import has only experimental support in node (at least since node 8 up to 15). But you don't need to use webpack for them work in node.
Just use esm which is very lightweight and has no build step.
Linting
Just use eslint, no need to use webpack.
Hot reloading/restart
You can use nodemon for this. It's not hot reloading but I think it's way easier to deal with.
I wished I could refer to a more lightweight project than nodemon, but it does do the trick.
The blog post you shared (which is dated by now) uses webpack for having hot reloading. I think that's an overkill, opens a can of worms because now you have to deal with webpack config issues and hot reloading can also lead to unexpected behaviour.
The benefits we get from using tools like webpack on the frontend don't really translate to backend.
The other reasons why we bundle files in frontend is so browsers can download them in an optimal way, in optimal chunks, with cache busting, minified. There's no need for any of these in the backend.
Old (and terrible, but maybe useful) answer
You can use webpack-node-externals, from the readme:
npm install webpack-node-externals --save-dev
In your webpack.config.js:
var nodeExternals = require('webpack-node-externals');
module.exports = {
...
target: 'node', // in order to ignore built-in modules like path, fs, etc.
externals: [nodeExternals()], // in order to ignore all modules in node_modules folder
...
};
to use Webpack for bundling all back-end js files together, which is in my opinion really not necessary.
I think you are absolutely right. It's not necessary at all. I've been researching on this topic for a while. I've asked lots of questions on this topic, and up to this day, I haven't found yet a single "real" reason for one to use webpack on a Node.js back-end.
I'm not saying you can't or shouldn't set up a webpack-dev-server to develop your back-end code locally. But you definitely don't need to bundle your backend code on your build process.
webpack bundles are meant for the browser. Take a look at its official docs: Why webpack?. Historically, browsers never had a built-in module system, that's the reason why you need webpack. It basically implements a module system on the browser. On the other hand, Node.js has a built-it module system out of the box.
And I do re-use all of my front-end code for SSR on my server. The very same front-end files are run on my server as-is without any bundling (they are just transpiled, but the folder structured and number of files is the same). Of course I bundle it to run on the browser, but that's all.
To run on your Node.js server, simply transpile it with babel, without webpack.
Just use ["#babel/preset-env", { targets: { node: "12" }}], on your babel config. Choose the Node version of your backend environment.
backend
dist_app // BABEL TRANSPILED CODE FROM frontend/src
dist_service // BABEL TRANSPILED CODE FROM backend/src
src
index.tsx
frontend
src
App.tsx
public // WEBPACK BUNDLED CODE FROM frontend/src
You can perfectly render your frontend code on the server, by doing:
backend/src/index.tsx
import { renderToString } from "react-dom/server";
import App from "../dist_app/App";
const html = renderToString(<App/>);
This would be considered isomorphic, I guess.
If you use path aliases on your code, you should use babel-plugin-module-resolver.

Express app doesn't find node_modules folder to load scripts from

I'm rather new to how webservers behave in general, so I have a few questions I hope someone can help me with.
It would also be nice if anyone could point me to an article or some documentation about the following topics.
Basically I'm trying to develop a webapp using Angular2, Expressjs and obviously node.js.
I have already successfully developed some basic Angular2 apps without a backend attached to it, which worked fine.
However, now I'm trying to send the index.html file (which contains a tag referring to an Angular component) to the browser from my server.
app.get('/test', function(req, res) {
res.sendfile('index.html');
});
You can find the html here: http://pastebin.com/utMHk8Pe
However, even though the node_modules package is on the same hierarchic level as both server.js and index.html, going to localhost:8080/test gives me a 404 for the node_modules script files in my html header.
Q1: Why doesn't my server find the node_modules folder?
Now, when I run my index.html file through following link, http://localhost:54720/testapp/index.html, everything works just fine.
Somehow it finds the node_modules at port 54720 but not 8080 (which is the port I made the express app listen on).
Q2: Why can't my server find the node_modules folder at the port I make it listen on?
As I've already said, I'm really new to node.js and webservers in general.
I'd be very grateful for any help!
Even linking me to an article which could be helpful would help me tons, since I can't really find anything since I don't know what to Google for.
You need to define a static folder to enable this. Something like this:
var express = require('express');
var app = express();
(...)
app.use('/static', express.static('public'));
This way, you will be able to serve the static files you need for Angular2, the ones that are present under the node_modules (angular2, systemjs and rxjs).
See this documentation for more details: http://expressjs.com/en/starter/static-files.html.
Hope it helps you,
Thierry

Can I use webpack on the client side without nodejs server?

I am trying to build a web app where I want to store all html, js and css files on amazon s3, and communicate with a restful server through api.
I am trying to achieve lazy loading and maybe routing with react router. It seems that webpack has this feature code splitting that would work similarly as lazy loading.
However, all of the tutorial and examples I found involves webpack-dev-server, which is a small node express server. Is there anyway I could generate bundle at build time and upload everything to amazon s3 and achieve something similar to Angular's ocLazyLoading?
It's definitely possible to create a static bundle js file, which you can use in your production code that does not include webpack-dev-server.
See this example as a reference (note: I am the owner of this repo). webpack.prod.config.js does create a production ready bundle file using webpack via node.js which itself does not require node.js anymore. Because of that you can simply serve it as a simple static file (which is done in the live example).
The key difference is how the entry points are written in the dev- and production environments. For development webpack-dev-server is being used
module.exports = {
entry: [
'webpack-dev-server/client?http://localhost:3000',
'webpack/hot/only-dev-server',
'./src/index'
],
// ...
}
In the production environment you skip the webpack-dev-server and the hot reloading part
module.exports = {
entry: [
'./src/index'
],
// ...
}
If you want to split your code into more than one bundle, you might want to have a look at how to define multiple entry points and link the files accordingly.

Resources