I have deployed a React app to Heroku. It works fine and all, but whenever I refresh a page that it's not the index ('/'), I keep getting an error: Cannot GET /project/post1.
I have no idea why this is happenning. I configured my express server to serve my static files on all routes, but its not working.
My file structure looks something like this:
-dist
- bundle.js
- index.html
-server.js
This is my server.js file:
var express = require('express');
var path = require('path');
var app = express();
var isProduction = process.env.NODE_ENV === 'production';
var port = isProduction ? process.env.PORT : 3000;
var publicPath = path.resolve(__dirname, './dist');
app.use(express.static(publicPath));
app.get('*', function(request, response) {
response.sendFile(path.join(publicPath))
});
// And run the server
app.listen(port, function () {
console.log('Server running on port ' + port);
});
This is my webpack.prod.config file:
var webpack = require('webpack');
module.exports = {
entry: {
main: './src/index.js'
},
resolve: {
extensions: ['', '.js', '.jsx']
},
output: {
path: __dirname + '/dist',
publicPath: '/dist/',
filename: 'bundle.js'
},
module: {
loaders: [{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'react-hot!babel'
},
{
test: /\.scss$/,
loader: 'style!css!sass'
}]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': '"production"'
}
})
]
};
I call my bundle.js file in the index.html like this:
<body>
<div id="app"></div>
<script src="/bundle.js"></script>
</body>
Your routing happens on the client, not the server. Express doesn't know what it should do on a GET request on /project/post1.
So we send all requests to the client, where you have react-router running. We can do that by configuring a fallback in the server.js file, for example like this:
import fallback from 'express-history-api-fallback';
import express from 'express';
import http from 'http';
// Set up express
const app = express();
const server = http.createServer(app);
const root = `${__dirname}`;
// History Fallback for express
app.use(express.static(root));
app.use(fallback('index.html', { root }));
// Listen
server.listen(8080, '0.0.0.0');
Related
For the life of me, I can't seem to get hot reloading to work. Does anyone have any ideas? What I do get in the console is "[HMR] connected", but when i make a change to a react component, the entire page refreshes.
I understand that I should something along the lines of:
[HMR] bundle rebuilding
[HMR] bundle rebuilt in 5269ms
.....
But I don't see any of this.
Here are my configs:
server.js
var path = require('path')
var webpack = require('webpack')
var express = require('express')
var config = require('./webpack.config')
var app = express()
var compiler = webpack(config)
app.use(
require('webpack-dev-middleware')(compiler, {
publicPath: config.output.publicPath
})
)
app.use(require('webpack-hot-middleware')(compiler, {
heartbeat: 10 * 1000
}))
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname, 'index.html'))
})
const PORT = 8080
app.listen(PORT, function(err) {
if (err) {
return console.error(err)
}
console.log(`Listening at http://localhost:${PORT}/`)
})
webpack.config.js
const path = require('path')
const webpack = require('webpack')
module.exports = {
mode: 'development',
entry: [
'react-hot-loader/patch',
'webpack-hot-middleware/client?path=http://localhost:8080/__webpack_hmr',
'babel-polyfill',
'./src/index.js'
],
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: '/dist/',
filename: 'bundle.js'
},
target: 'electron-main',
plugins: [ new webpack.HotModuleReplacementPlugin(), new webpack.ExternalsPlugin('commonjs', ['electron']) ],
module: {
rules: [
{
test: /\.(js|jsx)$/, // include .js files
exclude: /node_modules/, // exclude any and all files in the node_modules folder
loader: require.resolve('babel-loader'),
include: path.join(__dirname, 'src')
},
{
test: /\.css$/,
use: [{loader: 'style-loader'}, {loader: 'css-loader'}]
}
]
},
externals: ['electron', 'fs']
}
src/index.js
import React from 'react'
import ReactDOM from "react-dom"
import {AppContainer} from 'react-hot-loader'
import App from './app'
const renderApp = Component => {
ReactDOM.render(
<AppContainer>
<App />
</AppContainer>,
document.getElementById("root")
)
}
renderApp(App)
if (module.hot) {
module.hot.accept('./app.js', () => {
const nextRootContainer = require('./app').default
renderApp(nextRootContainer)
})
}
.babelrc
{
"presets": ["#babel/preset-env", "#babel/preset-react", "#babel/preset-flow"],
"plugins": [
["transform-class-properties", { "loose": true }],
"react-hot-loader/babel"
]
}
any suggestions welcome!!
i am trying render my React code on express server below is the code for that
const express =require('express');
const react =require('react');
const renderToString =require('react-dom/server').renderToString;
const HelloWorld=require('./client/components/Home');
const app = express();
app.get('/', (req, res) => {
const content=renderToString(<HelloWorld/>);
res.send(content);
});
app.listen(3000, () => {
console.log('Listening on prot 3000');
});
webpack.server.js
const path = require('path');
module.exports = {
// Inform webpack that we're building a bundle
// for nodeJS, rather than for the browser
target: 'node',
// Tell webpack the root file of our
// server application
entry: './src/index.js',
// Tell webpack where to put the output file
// that is generated
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build'),
},
module:{
rules:[
{
test:/\.js?$/,
loader:'babel-loader',
exclude:/node_modules/,
options:{
presets:[
'react',
'stage-0',//asyc purpose,
['env',{targets:{browsers:['last 2 versions']}}]
]
}
}
]
}
};
package.json
"dev:build:server": "webpack --config webpack.server.js"
when i run my application using node build\bundle.js i am getting react is not defined even i am importing react in index.js
Changing
const react=require('react');
to
const React=require('react');
solved my problem
i need help, with this error "webpack express Uncaught SyntaxError: Unexpected token <" can u tell me what i doing wrong ? webpack and express server not reported eny erorrs..
file struture:
app
package.json
server.js
webpack.config.js
-public
--index.html
--bundle.js
-node_modules
-src
--config.js
--index.js
--about
---about.html
--todos
---todos.html
webpack.config.js
var webpack = require('webpack');
var path = require('path');
module.exports = {
devtool: 'inline-source-map',
entry: ['./src'],
output: {
path: path.join(__dirname, 'public'),
filename: 'bundle.js'
},
resolve: {
modulesDirectories: ['node_modules', 'src'],
extension: ['', '.js']
},
module: {
loaders: [{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['es2015']
}},
{ test: /\.html$/,
loader: 'raw'}
]
},
devServer: {
hot: true,
proxy: {
'*': 'http://localhost:3000'
}
}
};
index.js
import angular from 'angular';
import appModule from 'config';
angular.bootstrap(document, [appModule.name]);
index.html
<html>
<head>
<title>MEAN ToDo App</title>
<base href="/">
</head>
<body>
<div ui-view></div>
<script src="bundle.js"></script>
</body>
</html>
config.js
import angular from 'angular';
import uiRouter from 'angular-ui-router';
const app = angular.module('app', [uiRouter]);
app.config(($stateProvider, $urlRouterProvider, $locationProvider) => {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('todos', {
url: '/',
template: require('todos/todos.html'),
})
.state('about', {
url: '/about',
template: require('about/about.html')
});
$locationProvider.html5Mode(true);
});
export default app;
server.js
var express = require('express');
var app = express();
var path = require('path');
var PORT = process.env.PORT || 3000;
app.all('/*', function(req, res) {
res.sendFile(path.join(__dirname, 'public/index.html'));
});
app.listen(PORT, function() {
console.log('Server running on ' + PORT);
});
The problem is in the node code:
app.all('/*', function(req, res) {
res.sendFile(path.join(__dirname, 'public/index.html'));
});
All routes are returning index.html. Try removing the *.
Your express server is misconfigured – it always returns index.html.
Try this instead:
app.use(express.static('/'));
app.listen(3000, function() {
console.log('listening');
});
Or use http-server from npm.
Just started redux, get stuck on a weird situation, webpack shows no error, but in the html, the component did not get rendered. The file structure:
dist
bundle.js
node_modules
src
index.js
.babelrc
index.html
package.json
server.js
webpack.config.js
index.html
<html>
<head>
<title>jie blog</title>
<meta charset="utf-8">
</head>
<body>
<div id="root"></div>
</body>
<script src="dist/bundle.js">
</script>
</html>
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import { Router, Route, Redirect, browserHistory } from 'react-router'
import { syncHistoryWithStore } from 'react-router-redux'
class App extends React.Component{
render(){
return(
<div>
hello world
</div>
)
}
}
ReactDOM.render(
<App/>,
document.getElementById('root')
)
server.js
var http = require('http')
var express = require('express')
var httpProxy = require('http-proxy')
var fs = require('fs')
var babelrc = fs.readFileSync('./.babelrc')
var config = JSON.parse(babelrc)
require('babel-core/register')(config)
var proxy = httpProxy.createProxyServer({})
var app = express()
app.use(require('morgan')('short'))
// webpack
var webpack = require('webpack')
var config = require('./webpack.config')
var compiler = webpack(config)
app.use(require('webpack-dev-middleware')(compiler, {
noInfo: true,
publicPath: config.output.publicPath
}))
app.use(require('webpack-hot-middleware')(compiler))
app.all(/^\/api\/(.*)/, function api(req, res){
proxy.web(req, res, {
target: 'http://localhost:5000'
})
})
app.get(/.*/, function root(req, res){
res.sendFile(__dirname + '/index.html')
})
const server = http.createServer(app)
server.listen(process.env.PORT || 3000, function(){
const address = server.address()
console.log('listening on %j', address)
})
webpack.config.js
const webpack = require('webpack')
const path = require('path')
module.exports = {
devtool: 'source-map',
entry: [
'webpack-hot-middleware/client',
path.resolve(__dirname, 'src/index.js')
],
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/static/'
},
resolve: {
extensions: ['', '.jsx', '.js', '.json', '.scss']
},
module: {
loaders: [
{
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react']
}
}
]
}
}
output html
<body>
<div id="root"></div>
<script src="dist/bundle.js">
</script>
</body>
It looks it's not an issue with ReactDOM but instead a configuration problem.
In server.js
...
app.use(require('webpack-dev-middleware')(compiler, {
noInfo: true,
publicPath: config.output.publicPath // <--- /static/
}))
...
publicPath specifies the public URL address of your bundle.js when referenced in a browser. So /static/bundle.js as you set in your webpack.config.js. Ok fine !
So Index.html need to request for /static/bundle.js. and NOT dist/bundle.js
...
<script src="static/bundle.js"></script>
...
Check output.publicPath configurations for webpack for more informations
As index.html requested for your bundle at /dist and webpack-dev-middleware handle requests at /static, an index.html file was returned instead of a your bundle.js
app.get(/.*/, function root(req, res){
res.sendFile(__dirname + '/index.html')
})
It's why you got Uncaught SyntaxError: Unexpected token < bundler.js:1.
The problem is that Babel is transpiling only .jsx files:
test: /\.jsx?$/,
while your file with JSX has a .js extension (index.js)
I'm trying to setup hot module reloading in a react/typescript (with TSX) environment. I have used the react/redux real-world example as a model in getting things going, and this is what I have so far:
server.js
var webpack = require('webpack')
var webpackDevMiddleware = require('webpack-dev-middleware')
var webpackHotMiddleware = require('webpack-hot-middleware')
var config = require('./webpack.config')
var app = new (require('express'))()
var port = 3000
var compiler = webpack(config)
app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath }))
app.use(webpackHotMiddleware(compiler))
app.use(function(req, res) {
res.sendFile(__dirname + '/index.html')
})
app.listen(port, function(error) {
if (error) {
console.error(error)
} else {
console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port)
}
})
webpack.config.js
var path = require('path')
var webpack = require('webpack')
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
devtool: 'cheap-module-eval-source-map',
entry: [
'webpack-hot-middleware/client',
path.resolve('./src/index.tsx'),
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js'
},
plugins: [
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({ template: './index.html' })
],
module: {
loaders: [
{ test: /\.tsx?$/, loader: 'ts-loader' }
]
},
resolve: {
extensions: ['', '.ts', '.tsx', '.js', '.json']
},
}
index.tsx
import * as React from 'react';
import { render } from 'react-dom';
import Root from './containers/root';
render(
<Root />,
document.getElementById('root')
);
containers/root.tsx
import * as React from 'react';
export default class Root extends React.Component<void, void> {
render(): JSX.Element {
return (
<p>boom pow</p>
);
}
}
Changing <p>boom pow</p> to <p>boom boom pow</p> in the root element kicks off this in the javascript console in the browser:
[HMR] bundle rebuilding
client.js?3ac5:126 [HMR] bundle rebuilt in 557ms
process-update.js?e13e:27 [HMR] Checking for updates on the server...
process-update.js?e13e:81 [HMR] The following modules couldn't be hot updated: (Full reload needed)
This is usually because the modules which have changed (and their parents) do not know how to hot reload themselves. See http://webpack.github.io/docs/hot-module-replacement-with-webpack.html for more details.
process-update.js?e13e:89 [HMR] - ./src/containers/root.tsx
process-update.js?e13e:89 [HMR] - ./src/index.tsx
I've stepped through these steps as best I can tell, but am still having no luck.
What am I missing?
The problem, as mentioned by commenters, was missing in my loader - I'm not sure if this had anything to do with it, but I also switched to using babel after typescript - and having typescript compile to ES6. New config below:
var path = require('path')
var webpack = require('webpack')
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
devtool: 'cheap-module-eval-source-map',
entry: [
'webpack-hot-middleware/client',
path.resolve('./src/index.ts'),
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js'
},
plugins: [
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({ template: path.resolve('./src/index.html') })
],
module: {
loaders: [
{ test: /\.tsx?$/,
loaders: [
'react-hot',
'babel?presets[]=es2015',
'ts-loader'
]
},
{ test: /\.json$/,
loader: 'json'
}
]
},
resolve: {
extensions: ['', '.ts', '.tsx', '.js', '.json']
},
}
if someone still struggles with this see the readme: https://github.com/webpack-contrib/webpack-hot-middleware/blob/master/README.md
This module is only concerned with the mechanisms to connect a browser client to a webpack server & receive updates. It will subscribe to changes from the server and execute those changes using webpack's HMR API. Actually making your application capable of using hot reloading to make seamless changes is out of scope, and usually handled by another library.
webpack-hot-middleware doesn't handle hot reload, you'd need to use react-hot-loader for example