I think that I am doing something wrong with my React router. I am a beginner to React/Redux so any help is really appreciated. It could also be how I configured webpack, but my front end is showing nothing, but I am not getting any errors at all. I'm not sure what the problem is, but my server starts, is able to populate mock data, and webpack compiles, so I think the backend works.
I'm so sorry for the wall of code but I really have no idea where I'm going wrong and I am a huge newbie to setup on this. This is definitely the longest post I've ever written so I appreciate anyone taking a look at it.
My client/src/routes:
import React from 'react'
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom'
import HomePage from './components/home/HomePage';
import { Layout } from './components/Layout';
export const App = () => (
<Layout>
<Switch>
<Route exact path="/" component={HomePage} />
</Switch>
</Layout>
);
export default App;
client/src/Homepage.js:
import React from 'react';
import { Link } from 'react-router-dom';
class HomePage extends React.Component {
render() {
return (
<div id="main">
<h1>Hello</h1>
<p>World</p>
</div>
);
}
}
export default HomePage;
client/src/Layout.js:
import React from 'react';
import { Link } from 'react-router-dom';
export const Layout = props => (
<div className="app-container">
<header>
<Link to="/">
</Link>
</header>
<div className="app-content">{props.children}</div>
<footer>
</footer>
</div>
);
export default Layout;
client/src/App.jsx:
import React from 'react';
import { Provider } from 'react-redux';
import configureStore from '../store/Store';
import { syncHistoryWithStore } from 'react-router-redux';
import routes from '../routes';
import { BrowserRouter as Router } from 'react-router-dom'
const store = configureStore();
export default class AppRoutes extends React.Component {
render() {
return (
<Provider store={store}>
<Router routes={routes} />
</Provider>
);
}
}
client/src/index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
import AppRoutes from './startup/App';
ReactDOM.render(
<Router>
<AppRoutes />
</Router>,
document.getElementById('main')
);
server/views/index.ejs:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Buddie!</title>
<link rel="stylesheet" href="/css/style.css">
</head>
<body>
<div id="main"><%- markup -%></div>
<script src="/js/bundle.js"></script>
</body>
</html>
server/app.js:
/* eslint no-console: "off"*/
import path from 'path';
import { Server } from 'http';
import Express from 'express';
import React from 'react';
import { renderToString } from 'react-dom/server';
import { StaticRouter as Router } from 'react-router-dom';
import { App } from '../client/src/startup/App';
const app = new Express();
const server = new Server(app);
const routes = require('../server/routes/index');
// use ejs templates
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// define the folder that will be used for static assets
app.use(Express.static(path.join(__dirname, 'static')));
app.use('/api/v1', routes)
// universal routing and rendering
app.get('*', (req, res) => {
let markup = '';
let status = 200;
if (process.env.UNIVERSAL) {
const context = {};
markup = renderToString(
<Router location={req.url} context={context}>
<App />
</Router>,
);
// context.url will contain the URL to redirect to if a <Redirect> was used
if (context.url) {
return res.redirect(302, context.url);
}
if (context.is404) {
status = 404;
}
}
return res.status(status).render('index', { markup });
});
// start the server
const port = process.env.PORT || 3000;
const env = process.env.NODE_ENV || 'production';
server.listen(port, (err) => {
if (err) {
return console.error(err);
}
return console.info(
`
Server running on http://localhost:${port} [${env}]
Universal rendering: ${process.env.UNIVERSAL ? 'enabled' : 'disabled'}
`);
});
webpack config:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
module.exports = {
entry: './client/src/index.js',
output: {
path: path.join(__dirname, 'server', 'static', 'js'),
filename: 'bundle.js'
},
resolve: {
extensions: ['.js', '.jsx', '.json']
},
devServer: {
historyApiFallback: true
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: [ 'babel-loader' ],
}
]
},
plugins: [
new HtmlWebpackPlugin({
inject: 'body',
filename: 'index.html'
}),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development')
})
]
};
package.json scripts:
"scripts": {
"start": "npm run build:dev && babel-node server/app.js",
"start:dev": "export NODE_ENV=development && npm run build:dev && nodemon --exec babel-node -- src/server.js",
"start:universal": "export UNIVERSAL=true && npm run start",
"start:dev:universal": "export NODE_ENV=development && export UNIVERSAL=true && npm run start:dev",
"build": "NODE_ENV=production webpack -p",
"build:dev": "webpack -d",
"build:dev:watch": "webpack -d --watch"
},
"dependencies": {
"axios": "^0.16.2",
"babel-polyfill": "^6.23.0",
"babel-preset-node6": "^11.0.0",
"babel-preset-react-hmre": "^1.1.1",
"babel-preset-stage-0": "^6.24.1",
"body-parser": "^1.17.2",
"chalk": "^1.1.3",
"classnames": "^2.2.5",
"concurrently": "^3.4.0",
"debug": "^2.6.8",
"ejs": "^2.5.6",
"express": "^4.15.3",
"immutable": "^3.8.1",
"jsx-loader": "^0.13.2",
"morgan": "^1.8.2",
"node-jsx": "^0.13.3",
"nodemon": "^1.11.0",
"normalizr": "^3.2.3",
"pg": "^6.2.4",
"react": "^15.6.1",
"react-addons-test-utils": "15.0.2",
"react-dom": "^15.6.1",
"react-hot-loader": "^3.0.0-beta.7",
"react-redux": "^5.0.5",
"react-router-dom": "^4.1.1",
"react-router-redux": "^4.0.8",
"react-scripts": "^1.0.7",
"react-slick": "^0.14.11",
"redux": "^3.7.0",
"redux-logger": "^3.0.6",
"redux-mock-store": "1.0.2",
"redux-thunk": "^2.2.0",
"sequelize": "^4.1.0",
"sequelize-cli": "^2.7.0",
"webpack": "^3.0.0",
"webpack-dev-server": "^2.4.5",
"yargs": "^8.0.2"
},
"proxy": "http://localhost:8000"
In your src/client/App.js file, I noticed you're importing syncHistoryWithStore from react-router-redux. I'm fairly confident RR4 and the old version of react-router-redux are not compatible with one another. The new version installed with #next does not contain syncHistoryWithStore.
This might be your issue.
Just noticed something in this code block
if (process.env.UNIVERSAL) {
const context = {};
markup = renderToString(
<Router location={req.url} context={context}>
<App />
</Router>,
);
// context.url will contain the URL to redirect to if a <Redirect> was used
if (context.url) {
return res.redirect(302, context.url);
}
if (context.is404) {
status = 404;
}
}
You are assigning an empty object to context, passing an empty context to your<Router />and then checking for context.url and context.is404, which are both going to be undefinedeverytime you check them! Maybe you meant context = {...context} ? Really unsure whether this affects rendering (pretty sure it does not) but it's worth mentioning.
If you are not running this code as universal, then it will never update the markup and it will always be empty hence will not print anything.
One small correction in your code: in index.ejs
remove last '-' in markup tag it should be <%- markup %>
Related
I have deployed my mern app to heroku, but it shows me a 404 page error when I try to navigate to the routes by entering the url. The navbar links work fine and they successfully navigate me to the signin and sign up pages, but when I click the register, login links in the forms. those links are broken and it gives me a Failed to load resource: the server responded with a status of 404 (Not Found) instead.
you can check my app at https://fullstack-restaurant-app97.herokuapp.com/
Im getting the error when Im navigating to https://fullstack-restaurant-app97.herokuapp.com/signin or https://fullstack-restaurant-app97.herokuapp.com/signup routes.
{
"name": "backend",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"build": "cd frontend && npm run build",
"install-frontend": "cd frontend && npm install",
"start": "node ./src/server.js",
"server": "nodemon ./src/server.js",
"frontend": "cd frontend && npm start",
"heroku-postbuild": "NPM_CONFIG_PRODUCTION=false && npm run install-frontend && npm run build"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"bcrypt": "^5.0.0",
"cors": "^2.8.5",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"express-validator": "^6.6.1",
"jsonwebtoken": "^8.5.1",
"mongoose": "^5.10.0",
"multer": "^1.4.2",
"path": "^0.12.7",
"shortid": "^2.2.15"
},
"devDependencies": {
"nodemon": "^2.0.4"
}
}
App.js
import React, { useEffect } from 'react';
import {BrowserRouter as Router, Route, Switch} from 'react-router-dom';
import Signin from './containers/Signin';
import Signup from './containers/Signup';
import Home from './containers/Home';
import './App.css';
import { useDispatch, useSelector } from 'react-redux';
import { isUserLoggedIn } from './actions';
import CssBaseline from '#material-ui/core/CssBaseline';
function App() {
const dispatch = useDispatch();
const auth = useSelector(state => state.auth)
useEffect(() => {
if(!auth.authenticate){
dispatch(isUserLoggedIn())
}
}, [])
return (
<>
<CssBaseline/>
<Router>
<Route exact path="/" component={Home} />
<Route path="/signin" component={Signin} />
<Route path="/signup" component={Signup}/>
</Router>
</>
);
}
export default App;
server.js
const express= require('express');
const app= express();
const mongoose= require('mongoose');
const env= require('dotenv').config();
const PORT= process.env.PORT || 2000;
const adminRoutes= require('./routes/admin/auth');
const restaurantRoutes= require('./routes/restaurant')
const cors= require('cors');
const path= require('path');
mongoose.connect(process.env.MONGODB_URI || `mongodb+srv://${process.env.MONGO_DB_USER}:${process.env.MONGO_DB_PASSWORD}#cluster0.e4r3t.mongodb.net/${process.env.MONGO_DB_DATABASE}?retryWrites=true&w=majority`,
{
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex:true
}).then(() => {
console.log('Database connected');
});
app.use(cors());
app.use('/public', express.static(path.join(__dirname,'uploads')));
app.use(express.json());
app.use('/api', adminRoutes);
app.use('/api', restaurantRoutes);
if(process.env.NODE_ENV=='production'){
app.use(express.static("frontend/build"))
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'frontend', 'build', 'index.html'))
})
}
app.listen(PORT, () => {
console.log(`Server is listening on port ${PORT}`);
})
I have also added the link to my github repo https://github.com/codinghamster12/fullstack-restaurant-webapp
I have tried to fix this for days now and I would really appreciate if someone could look into it.
Thanks!
I cannot directly say this is the reason for happening that. But you can use a simple method to find out the problem. Navigate to the project folder and open cmd from that location. Then, login to your heroku account by using heroku login command. Then type heroku logs -t command it will show up the status of your server and API calls init. If there any error you can see the error message in red color. Then go through it you can definitely come up with a solution by using this method.
I am trying to setup webpack dev server using webpackDevMiddleware, webpackHotMiddleware with express generator and react. I got everything working, but there's a huge delay in the reload.
I will get this message every time in the browser
'GET http://localhost:8080/__webpack_hmr
net::ERR_INCOMPLETE_CHUNKED_ENCODING 200 (OK)'
But 5 to 10 seconds later the browser will reload. In the terminal, these messages are showing
GET /7310e23232f92e879547.hot-update.json 404 6.282 ms - 1573
GET / 304 1.071 ms - -
GET /__webpack_hmr 200 1.767 ms - -
GET /stylesheets/style.css 304 1.306 ms - -
GET /app-bundle.js 200 5.337 ms - 2960039
I think the express server has a delay or stopping from getting the hot-update.json.
I have tried time out and keepAliveTimeout the bin/www file
server.listen(port, () => {
server.timeout = 0
server.keepAliveTimeout = 0
});
package.json
{
"name": "react-webpack-hmr",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node ./bin/www",
"dev": "nodemon ./bin/www --inspect --watch app.js --watch webpack.config.js --watch src",
"build": "webpack --config=webpack.config.js",
"clean": "rimraf public/dist"
},
"dependencies": {
"babel-loader": "^8.0.4",
"cookie-parser": "~1.4.3",
"css-loader": "^2.1.0",
"debug": "~2.6.9",
"ejs": "~2.5.7",
"ejs-loader": "^0.3.1",
"express": "~4.16.0",
"extract-loader": "^3.1.0",
"file-loader": "^3.0.1",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"http-errors": "~1.6.2",
"morgan": "~1.9.0",
"react": "^16.7.0",
"react-dom": "^16.7.0",
"react-hot-loader": "^4.6.3",
"style-loader": "^0.23.1"
},
"devDependencies": {
"#babel/preset-react": "^7.0.0",
"#babel/runtime": "^7.2.0",
"#babel/generator": "^7.2.2",
"#babel/polyfill": "^7.2.5",
"babel-plugin-async-to-promises": "^1.0.5",
"#babel/core": "^7.2.2",
"#babel/plugin-transform-runtime": "^7.2.0",
"#babel/preset-env": "^7.2.3",
"webpack": "^4.28.3",
"webpack-cli": "^3.1.2",
"webpack-dev-middleware": "^3.4.0",
"webpack-dev-server": "^3.1.14",
"webpack-hot-middleware": "^2.24.3"
}
}
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
module.exports = {
entry: {
app: [
'webpack-hot-middleware/client?reload=true',
// 'webpack/hot/only-dev-server',
// 'react-hot-loader/patch',
"#babel/runtime/regenerator",
"./src/app.js"
]
},
mode: 'development',
output: {
filename: "[name]-bundle.js",
path: path.join(__dirname, 'public/dist'),
publicPath: "/"
},
devtool: "cheap-eval-source-map",
devServer: {
contentBase: "dist",
overlay: true,
hot: true
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader'
}
]
},
{
test: /\.html$/,
use: [
{
loader: "html-loader"
}
]
},
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(),
new HtmlWebpackPlugin({
template: './views/index.ejs'
})
]
}
app.js
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
const webpack = require("webpack");
const config = require("./webpack.config");
const compiler = webpack(config);
const webpackDevMiddleware = require('webpack-dev-middleware')(compiler, config.devServer);
const webpackHotMiddleware = require('webpack-hot-middleware')(compiler, config.devServer);
var app = express();
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(webpackDevMiddleware);
app.use(webpackHotMiddleware);
//app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/users', usersRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
React side app.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App.js';
import { AppContainer } from 'react-hot-loader';
function render(Component) {
ReactDOM.render(
<AppContainer>
<Component />
</AppContainer>,
document.getElementById('app')
)
}
render(App);
if (module.hot) {
module.hot.accept('./components/App', () => {
const newApp = require('./components/App').default
render(newApp);
})
}
I expect the browser will reload after is finished compiling the new code without a delay everytime I save my files.
So I fixed it was my package.json
I was watching the react files which it shouldn't
I removed the old code this is the new one
"dev": "nodemon --inspect --watch webpack.config.js --watch app.js",
TLDR; In order to have hot module reload working with Nodemon you need to exclude the client code from watch.
Webpack uses __webpack_hmr to receive events about changes in code. If you edit a file then save it, Nodemon restarts and in this time Webpack HMR loses connection to the event stream, resulting in a miss for getting updated code. This is the reason why you need to exclude client side code from the watch list of Nodemon. Basically client side code refresh is 'managed' by Webpack dev server.
Usually I have a nodemon.json file in my root to let Nodemon know what to watch:
{
"watch": [
"server.js",
"src/server",
"config"
]
}
I'm trying to build an application using typescript , express . but i'm getting this error :
Cannot invoke an expression whose type lacks a call signature. Type 'typeof e' has no compatible call signatures(in app.ts where express() is called )
I'm using webpack here to help with my development.
My Package.json :
"scripts" :{
"build": "webpack"
},
"dependencies": {
"body-parser": "^1.18.3",
"dotenv": "^6.1.0",
"jsonwebtoken": "^8.3.0",
"nodemon": "^1.18.5"
},
"devDependencies": {
"#types/body-parser": "^1.17.0",
"#types/dotenv": "^4.0.3",
"#types/express": "^4.16.0",
"clean-webpack-plugin": "^0.1.19",
"ts-loader": "^5.3.0",
"ts-node": "^7.0.1",
"typescript": "^3.1.6",
"webpack": "^4.24.0",
"webpack-cli": "^3.1.2"
}
my webpack.confg.js :
var path = require("path");
const CleanWebpackPlugin = require("clean-webpack-plugin");
var fs = require("fs");
var nodeModules = {};
fs.readdirSync("node_modules")
.filter(function(x) {
return [".bin"].indexOf(x) === -1;
})
.forEach(function(mod) {
nodeModules[mod] = "commonjs " + mod;
});
module.exports = {
entry: "./src/index.ts",
plugins: [new CleanWebpackPlugin(["./dist"])],
output: {
filename: "index.js",
path: path.resolve(__dirname, "dist")
},
module: {
rules: [
//all files with .ts extention will be handled y ts-loader
{ test: /\.ts$/, loader: "ts-loader" }
]
},
target: "node",
externals: nodeModules
};
my app.ts :
import * as express from "express";
import * as bodyParser from "body-parser";
class App {
public app: express.Application;
constructor() {
this.app = express();
this.config();
}
private config(): void {
//add support for application/json type for data
this.app.use(bodyParser.json());
//support application/x-www-form-urlencoded post data
this.app.use(bodyParser.urlencoded({ extended: false }));
}
}
export default new App().app;
I'm running npm run build and my build fails with the error stated .
tried searching for solution in a few blogs and none have mentioned tanything about this error .I manged to add express.Application as type for app in side app.ts
What am i doing wrong ? Is it because of the configuration of webpack ?
Any help appreciated
You need to import the default export from express instead of the namespace (which is an object with all named exports).
In your app.ts this should be all you need:
// Change these
import express from "express";
import bodyParser from "body-parser";
The difference is:
// Namespace import
import * as express from "express";
const app = express.default();
// Default import
import express from "express";
const app = express();
For me, it worked on changing the import as-
import { express } from "express";
const app = express();
I am not sure why my project is giving me Could not find store error when I try to do normal start. But when I do start-dev, which is devServer it works fine. Probably easier to show you in code.
here is the whole error
Invariant Violation: Could not find "store" in either the context or props of "Connect(Layout)". Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(Layout)".
package.json
"scripts": {
"start": "cross-env NODE_ENV=production node_modules/.bin/babel-node --presets react,es2015 src/server.js",
"start-dev": "npm run start-dev-hmr",
"start-dev-single-page": "node_modules/.bin/http-server src/static",
"start-dev-hmr": "node_modules/.bin/webpack-dev-server --progress --inline --hot --open",
"build": "cross-env NODE_ENV=production node_modules/.bin/webpack -p"
},
"dependencies": {
"babel-cli": "^6.11.4",
"babel-core": "^6.13.2",
"babel-loader": "^6.2.5",
"babel-plugin-react-html-attrs": "^2.0.0",
"babel-preset-es2015": "^6.13.2",
"babel-preset-react": "^6.11.1",
"babel-preset-react-hmre": "^1.1.1",
"cross-env": "^3.1.4",
"css-loader": "^0.27.3",
"ejs": "^2.5.1",
"express": "^4.14.0",
"jquery": "^3.2.0",
"react": "^15.3.1",
"react-dom": "^15.3.1",
"react-redux": "^5.0.3",
"react-router": "^2.8.1",
"redux": "^3.6.0",
"style-loader": "^0.14.1"
},
reducer.js
const action_types = require('./action_types');
import json from 'json!../../lang.json';
const initialState = {
content: json.en // Loads default language content (en) as an initial state
};
const reducer = function (state = initialState, action) {
switch (action.type) {
case action_types.SWITCH_LANGUAGE:
return {
content: json[action.language]
};
default:
return state;
}
};
module.exports = reducer;
AppRouter.js
import React from 'react';
import { Router, browserHistory } from 'react-router';
import routes from '../routes';
import Layout from './Layout';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
const content = require('../Action/reducer');
const store = createStore(content);
export default class AppRoutes extends React.Component {
render() {
return (
<Provider store={store}>
<Router history={browserHistory} routes={routes} onUpdate={() => window.scrollTo(0, 0)}/>
</Provider>
);
}
}
routes.js
import React from 'react'
import { Route, IndexRoute } from 'react-router'
import Layout from './components/Layout';
import IndexPage from './components/IndexPage';
import AthletePage from './components/AthletePage';
import Notfound from './components/Notfound';
import Pricing from './components/Pricing/Pricing'
const routes = (
<Route path="/" component={Layout}>
<IndexRoute component={IndexPage}/>
<Route path="pricing" component={Pricing}/>
<Route path="*" component={Notfound}/>
</Route>
);
export default routes;
Layout.js
'use strict';
import React from 'react';
import { Link } from 'react-router';
// const actions = require('../Action/actions');
import * as actions from '../Action/actions';
import {connect} from 'react-redux';
class Layout extends React.Component {
handleSwitchLang(targetLang) {
this.props.switchLanguage(targetLang);
}
render() {
let switchLanguage = this.props.switchLanguage;
let content = this.props.content;
return (
<div className="app-container">
some ui code
</div>
);
}
}
function mapStateToProps(state) {
return { content: state.content }
}
export default connect(mapStateToProps, actions)(Layout);
Server.js
'use strict';
import path from 'path';
import { Server } from 'http';
import Express from 'express';
import React from 'react';
import { renderToString } from 'react-dom/server';
import { match, RouterContext } from 'react-router';
import routes from './routes';
import NotFoundPage from './components/NotFoundPage';
// initialize the server and configure support for ejs templates
const app = new Express();
const server = new Server(app);
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// define the folder that will be used for static assets
app.use(Express.static(path.join(__dirname, 'static')));
// universal routing and rendering
app.get('*', (req, res) => {
match(
{ routes, location: req.url },
(err, redirectLocation, renderProps) => {
// in case of error display the error message
if (err) {
return res.status(500).send(err.message);
}
// in case of redirect propagate the redirect to the browser
if (redirectLocation) {
return res.redirect(302, redirectLocation.pathname + redirectLocation.search);
}
// generate the React markup for the current route
let markup;
if (renderProps) {
// if the current route matched we have renderProps
markup = renderToString(<RouterContext {...renderProps}/>);
} else {
// otherwise we can render a 404 page
markup = renderToString(<NotFoundPage/>);
res.status(404);
}
// render the index template with the embedded React markup
return res.render('index', { markup });
}
);
});
// start the server
const port = process.env.PORT || 3000;
const env = process.env.NODE_ENV || 'production';
server.listen(port, err => {
if (err) {
return console.error(err);
}
console.info(`Server running on http://localhost:${port} [${env}]`);
});
I'm newbie to Reactjs and webpack. I'm trying to do a sample app using Node and React. I have chosen Webpack as module bundler.
This is my project structue
Project
|--index.html
|--package.json
|--server.js
|--webpack.config.js
|--app/main.js
|--app/routes.js
|--app/components/login.js
Contents of package.json
{
"version": "1.0.0",
"description": "learn",
"main": "server.js",
"dependencies": {
"body-parser": "^1.14.1",
"bootstrap": "^3.3.7",
"express": "^4.14.0",
"react": "^15.3.2",
"react-dom": "^15.3.2",
"react-router": "^2.8.1"
},
"devDependencies": {
"babel-cli": "^6.16.0",
"babel-core": "^6.17.0",
"babel-loader": "^6.2.5",
"babel-preset-es2015": "^6.16.0",
"babel-preset-react": "^6.1.18",
"babel-register": "^6.3.13",
"babelify": "^7.2.0",
"nodemon": "^1.11.0",
"webpack": "^1.13.2"
},
"scripts": {
"watch": "nodemon server.js",
"start": "node server.js"
}
}
Contents of webpack.config.js
module.exports = {
context: __dirname + "/app",
entry: "./main.js",
output: {
filename: "./build/bundle.js"
},
resolve: {
extensions: ['', '.js', '.jsx']
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: "babel",
query: {
presets: ['react', 'es2015']
}
}
]
}
}
server.js
var express = require('express');
var path = require('path');
var React = require('react');
var ReactDOM = require('react-dom');
var Router = require('react-router');
var routes = require('./app/routes');
var app = express();
app.set('port', process.env.PORT || 3000);
app.listen(app.get('port'), function() {
console.log('Express server listening on port ' + app.get('port'));
});
app.get('/',function(req, res) {
res.send('Hello');
});
app.get('/login',function(req, res) {
res.send('Login page using react');
});
main.js
import React from 'react';
import Router from 'react-router';
import ReactDOM from 'react-dom';
import routes from './routes';
ReactDOM.render(<Router>routes</Router>, document.getElementById('app'));
routes.js
import React from 'react';
import {Route} from 'react-router';
import Login from './components/login';
//import Home from './components/Home';
export default (
<Route path="/login" component={Login}>
</Route>
);
login.js
import React from 'react';
import ReactDOM from 'react-dom';
class Login extends React.Component {
render() {
return (
<div className="container">
<div className="row">
<div className="col-sm-5">
<strong>Username</strong>
</div>
<div className="col-sm-5">
<input type='text' className='form-control'/>
</div>
</div>
</div>
)
}
}
export default Login;
When I do "webpack -w" seems to be working fine.
when trying to start node using "npm start", says
/Project/app/routes.js:1
(function (exports, require, module, __filename, __dirname) { import React from 'react'; ^^^^^^
SyntaxError: Unexpected token import
I have no idea about why node is not picking up babel's import? Couldn't find anything on the internet and hence posting this question. I badly need a help.
Thanks in advance.
Your webpack config only transpiles (and bundles) your frontend code. When you type npm start, node.js will execute server.js, which then includes your JSX source. Node does not support ES6 modules yet, so that's why it fails with a syntax error.
You can use the Babel require hook to automatically transpile the code for node. Don't forget to specify the 'es2015' and 'react' presets in the options.