react-router deploying non-static - node.js

Is it OK to deploy a react-router based webapp to production running under a node.js server? Deploying static files prevents links like server.com/about from working unless index.html is loaded first. One can get around this by using HashRouter but it seems old school to do down that route.
index.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import App from './js/App';
import About from './js/About';
import registerServiceWorker from './registerServiceWorker';
import './index.css';
import { BrowserRouter as Router, Route } from 'react-router-dom';
ReactDOM.render(
<Router>
<App>
<Route path='/about' component={About} />
</App>
</Router>
, document.getElementById('root'));
registerServiceWorker();

you can use nginx fall back any route (eg. server.com/about) to the index.html
for example
location ^~ / {
alias /usr/local/theapp/dist;
try_files $uri $uri/ /index.html;
access_log /var/log/nginx/theapp/acces.web.log;
error_log /var/log/nginx/theapp/error.web.log debug;
}
# assets
location ~ ^/.+\..+$ {
try_files $uri =404;
alias /usr/local/theapp/dist;
error_log /var/log/nginx/theapp/error.web.log debug;
}

Not the prettiest solution but resolving to something like this alongside the nginx try_files $uri $uri/ /index.html; does the trick.
class OnLoadHack extends Component {
componentDidMount() {
const { location, match, history } = this.props;
if(process.env.NODE_ENV !== 'development' && !match.isExact){
history.push(location.pathname + location.search)
}
}
render() {
return null
}
}
ReactDOM.render(
<Router>
<App>
<Route path='/' component={OnLoadHack} />
<Route path='/about' component={About} />
</App>
</Router>
, document.getElementById('root'));
registerServiceWorker();

Related

"main" has not been registered - Expo Project issue with iOS

I am using an expo managed react-native project and it seems to be running fine on android but not iOS. For iOs i get the following error message :
"'main' has not been registered. This can happen if: * Metro (the local dev server) is run from the wrong folder. Check if Metro is running, stop it and restart it in the current project.
A module failed to load due to an error and 'AppRegistry.registerComponent' wasn't called."
I have tried updating my index.js using AppRegistry.registerComponent('main', () => App) from similar posts but to no avail. What am I doing wrong?
index.js
import { registerRootComponent } from "expo";
import App from "./App";
// registerRootComponent calls AppRegistry.registerComponent('main', ()
=> App);
// It also ensures that whether you load the app in the Expo client or in
a native build,
// the environment is set up appropriately
registerRootComponent(App);
App.js
import "react-native-gesture-handler";
import { NavigationContainer } from "#react-navigation/native";
import { createStackNavigator } from "#react-navigation/stack";
import React from "react";
import { StyleSheet } from "react-native";
import { ScreenStack } from "react-native-screens";
import Login from "./Login";
import Join from "./Join";
import Home from "./Home";
import Dashboard from "./Dashboard";
import BorrowMap from "./BorrowMap";
import SpotRequest from "./SpotRequest";
// import { registerRootComponent } from "expo";
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={Home}
options={{ title: "Welcome" }}
/>
<Stack.Screen
name="Login"
component={Login}
options={{ title: "Login" }}
/>
<Stack.Screen
name="Join"
component={Join}
options={{ title: "Register" }}
/>
<Stack.Screen
name="Dashboard"
component={Dashboard}
options={{ title: "Dashboard" }}
/>
<Stack.Screen
name="Spot Request"
component={SpotRequest}
options={{ title: "Spot Request Details" }}
/>
<Stack.Screen
name="Finding Buddy"
component={BorrowMap}
options={{ title: "Finding Buddy" }}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});
export default App;
Folder Structure

Deploying Next Js project in IIS

I had a requirement of server side rendering in my project.So, I have developed it using next js and now i got struct in deployment.
I need to deploy my project in iis and dont know how i can achieve that. I tried a lot no luck. It works fine in development mode but not in production.
I tried next export but this is for static pages deployment and
my project uses dynamic pages.
Any help will be appreciated. Thanks in advance.
Try this youtube link it helped me deploy the nextjs app on IIS. Do not forget that you need NodeJS, URLRewrite and IISNode on your server.
You build your nextjs app and deploy it to the IIS folder on the server. You also need the node_modules folder with all the dependencies including express and node.
I have the same problem as you, but so far I have successfully deployed and solved the routing problem, but the only thing that has not been solved is that I cannot redirect to the "NotFound page" (404.js), Maybe we can find a solution together.
This is the current solution :
folder tree :
node_modules
public
pages
index.js
first.js
two.js
_error.js
next.config.js
package.json
package.lock.json
README.md
package.json :
{
"name": "my-app",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"prod": "next build && next export"
},
"dependencies": {
"next": "9.3.5",
"react": "16.13.1",
"react-dom": "16.13.1",
}
}
next.config.js :
const data = [
{
path: '/first'
},
{
path: '/two'
}
];
module.exports = {
exportTrailingSlash: true,
exportPathMap: async function () {
//you can get route by fetch
const paths = {
'/': { page: '/' }
};
data.forEach((project) => {
paths[`${project.path}`] = {
page: project.path,
};
});
return paths;
}
}
index.js :
import Link from 'next/link'
import React from 'react';
import Head from 'next/head'
export default function Home(props) {
return (
<div className="container">
<Head>
<title>Create Next App</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<h1 className="title">
<Link href="/first">
<a>page first</a>
</Link>
<Link href="/two">
<a>page two</a>
</Link>
</h1>
</div>
)
}
export async function getStaticProps(context) {
return {
props: {}, // will be passed to the page component as props
}
}
first.js :
import Link from 'next/link'
import Head from 'next/head'
export default function FirstPost() {
return (
<>
<Head>
<title>First</title>
</Head>
{"First page"}
<h2>
<Link href="/">
<a>Back to home</a>
</Link>
</h2>
</>
)
}
export async function getStaticProps(context) {
return {
props: {}, // will be passed to the page component as props
}
}
two.js :
import Link from 'next/link'
import Head from 'next/head'
export default function FirstPost() {
return (
<>
<Head>
<title>two </title>
</Head>
{"two page"}
<h2>
<Link href="/">
<a>Back to home</a>
</Link>
</h2>
</>
)
}
export async function getStaticProps(context) {
return {
props: {}, // will be passed to the page component as props
}
}
and then run the scripts "prod", you will have /out folder,
just use it as the root directory of IIS,
now test the route :
Enter URL http://{your IP or domain}/ => you will see index.js
Enter URL http://{your IP or domain}/first => you will see first.js
Enter URL http://{your IP or domain}/whatever => you will get 404 error from IIS, and I need the help here!
update the reply,
Finally, I know how to solve it, add web.config and redirect to the 404 errpr page.
note: <action type="Rewrite" url="404/index.html" /> // You can specify the error page here!
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Static Assets" stopProcessing="true">
<match url="([\S]+[.](html|htm|svg|js|css|png|gif|jpg|jpeg))" />
<action type="Rewrite" url="/{R:1}"/>
</rule>
<rule name="ReactRouter Routes" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="404/index.html" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>

localForage.setDriver is not a function, using react redux session

I just started using react-redux-session. I installed the same using npm and implemented the code in my react app. However there is an error that is coming up, localForage.setDriver is not a function. I even installed the dependencies (localforage) for it, but still the error.
Am I missing some necessary step? Below is my component where I am calling it.
import App from './containers/App';
import Routes from './Routes';
import appReducer from './reducers';
import { Provider, connect } from 'react-redux';
import { createStore } from 'redux';
import { sessionService } from 'redux-react-session';
let store = createStore(appReducer);
const options = { refreshOnCheckAuth: true, redirectPath: '/login', driver:
'LOCALSTORAGE' };
sessionService.initSessionService(store, options);
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<App>
<Routes />
</App>
</BrowserRouter>
</Provider>,
document.getElementById('main')
);
Package Details:
"redux-react-session": "^2.1.0"<br/>
"localforage": "^1.5.2",
"webpack": "^3.5.6",<br/>
"webpack-dev-server": "^2.7.1"
Any advice would be of great help.
Thanks

Setting up nginx with multiple IPs

I have my nginx configuration file under /etc/nginx/sites-available/ with two upstreams say
upstream test1 {
server 1.1.1.1:50;
server 1.1.1.2:50;
}
upstream test2 {
server 2.2.2.1:60;
server 2.2.2.2:60;
}
server {
location / {
proxy_pass http://test1;
}
location / {
proxy_pass http://test2;
}
}
Sending a curl request to <PrimaryIP>:80 works but I want to use <SecondaryIP1>:80 for test1 and <SecondaryIP2>:80 for test2. Is it possible to define this in nginx?
You have to have two server directives to accomplish this task:
upstream test1 {
server 1.1.1.1:50;
server 1.1.1.2:50;
}
upstream test2 {
server 2.2.2.1:60;
server 2.2.2.2:60;
}
server {
listen 80
server_name <SecondartIP1>
location / {
proxy_pass http://test1;
}
}
server {
listen 80
server_name <SecondarIP2>
location / {
proxy_pass http://test2;
}
}

templateUrl does not work

I'm trying to make angular2-material app
It works when I template: ~ but If I use templateUrl: ~, <my-app> contains nothing even Loading... and a Network log Informed me the template successfully loaded 200 GET /app/mainLayout.html
Basically, I followed quick start guide of angular2 docs and these are what I did
installing angular2-materialize by npm
import "angular2-materialize" in main.ts
add System.config in index.html
index.html
<!-- 2. Configure SystemJS -->
<script src="systemjs.config.js"></script>
<script>
System.config({
defaultJSExtensions: true,
packages: {
"materialize-css": {
"main": "dist/js/materialize"
},
"materialize": {
"main": "dist/materialize-directive",
"defaultExtension": "js"
}
},
map: {
"materialize-css": "node-modules/materialize-css",
"materialize": "node_modules/angular2-materialize",
"angular2-materialize": "node_modules/angular2-materialize"
}
});
System.import('app').catch(function(err){ console.error(err); });
</script>
add MaterializeDirective in app.component.ts
app.component.ts
import { Component } from '#angular/core';
import { MaterializeDirective } from 'angular2-materialize';
#Component({
selector: 'my-app',
directives: [MaterializeDirective],
templateUrl: 'app/views/mainLayout.html',
styleUrls: ['/app/css/mainLayout.css']
})
export class AppComponent { }
This is my working dir
|
|-app
| |-css
| | |-mainLayout.css
| |-views
| | |-mainLayout.html
| |
| |-app.component.ts
| |-main.ts
|
|-node_modules
| |-(....)
|-typings
| |-globals
| | |-(...)
| |-index.d.ts
|-package.json
|-systemjs.config.js
|-tsconfig.json
|-typings.json
one more thing. I think --regardless of template: statement-- it seems some path are setted wrong. *.js files are loaded successfully but *.map files are not.
[1] 16.06.21 20:17:15 200 GET /node_modules/rxjs/Subject.js
[1] 16.06.21 20:17:15 404 GET /node_modules/systemjs/dist/Subject.js.map
like this
Try
#Component({
selector: 'my-app',
directives: [MaterializeDirective],
templateUrl: './app/views/mainLayout.html',
styleUrls: ['/app/css/mainLayout.css']
})
The key difference being './app/. This makes Angular look for the "mainLayout.html" in the current root /app/views/.
Although I don't know what happend, I resolved the problem somehow. Few more restarting npm and app/views/mainLayout.html were solution. but the angular2 still find .map in wrong path. Please let me know why it happen if there are someone who have a idea.

Resources