UPDATE:
I tried adding a publicPath option to my webpack.config.js
under output
, the value being /static/
. I also changed my script tag from <script src="/bundle.js"></script>
to <script src="/static/bundle.js"></script>
. No luck, which is strange because when I take a look at this example redux app, I can reproduce the error I'm getting by deleting their publicPath
option from the webpack.config.js
.
I'm in the process of trying to render some html server-side with node/express. The app uses react and redux. I ran 'npm run dev' to start the local server, but upon navigating to it in chrome I found this error in the console:
bundle.js:2 Uncaught SyntaxError: Unexpected token <
Upon further inspection it seems that my bundle.js contains nothing but the compiled html from the server. I'm still trying to wrap my head around server side rendering with node, redux, and most of all webpack, so I'm having difficulty seeing how this could be the case. I'm looking at my IDE and it tells me bundle.js contains tons of compiled js.
package.json
{
"name": "serif.nu",
"version": "1.0.0",
"description": "Simple. Fast. Visual. Course Planning for Northwestern University.",
"main": "index.jsx",
"scripts": {
"webpack-watch": "webpack -w",
"express-server": "node ./server/index.js",
"dev": "concurrently --kill-others \"npm run webpack-watch\" \"npm run express-server\"",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/Joonpark13/serif.nu.git"
},
"author": "Joon Park",
"license": "ISC",
"bugs": {
"url": "https://github.com/Joonpark13/serif.nu/issues"
},
"homepage": "https://github.com/Joonpark13/serif.nu#readme",
"devDependencies": {
"babel-watch": "^2.0.3",
"concurrently": "^3.1.0",
"webpack": "^1.13.3"
},
"dependencies": {
"babel-core": "^6.18.2",
"babel-loader": "^6.2.7",
"babel-plugin-transform-object-rest-spread": "^6.16.0",
"babel-polyfill": "^6.16.0",
"babel-preset-es2015": "^6.18.0",
"babel-preset-react": "^6.16.0",
"babel-register": "^6.18.0",
"es6-promise": "^4.0.5",
"express": "^4.14.0",
"isomorphic-fetch": "^2.2.1",
"material-ui": "^0.16.1",
"react": "^15.3.2",
"react-bootstrap": "^0.30.6",
"react-dom": "^15.3.2",
"react-redux": "^4.4.6",
"react-tap-event-plugin": "^1.0.0",
"redux": "^3.6.0",
"redux-thunk": "^2.1.0",
"request": "^2.79.0",
"request-json": "^0.6.1"
},
"babel": {
"presets": [
"es2015",
"react"
],
"plugins": [
"transform-object-rest-spread"
]
}
}
webpack.config.js
const path = require('path');
module.exports = {
entry: path.join(__dirname, 'app/index.jsx'),
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'dist')
},
module: {
loaders: [
{
test: /\.jsx$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}
]
}
};
index.js
require('babel-register');
require('./server');
server.js
import express from 'express';
import React from 'react';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import { renderToString } from 'react-dom/server';
import reducer from '../app/reducers';
import App from '../app/components/App';
const app = express();
function renderFullPage(html, preloadedState) {
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Serif</title>
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.0.1/fullcalendar.min.css">
<link rel="stylesheet" href="materialFullCalendar.css">
<link rel="apple-touch-icon" sizes="57x57" href="https://s3.amazonaws.com/serif-assets/apple-touch-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="https://s3.amazonaws.com/serif-assets/apple-touch-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="https://s3.amazonaws.com/serif-assets/apple-touch-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="https://s3.amazonaws.com/serif-assets/apple-touch-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="https://s3.amazonaws.com/serif-assets/apple-touch-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="https://s3.amazonaws.com/serif-assets/apple-touch-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="https://s3.amazonaws.com/serif-assets/apple-touch-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="https://s3.amazonaws.com/serif-assets/apple-touch-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="https://s3.amazonaws.com/serif-assets/apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" href="https://s3.amazonaws.com/serif-assets/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="https://s3.amazonaws.com/serif-assets/favicon-194x194.png" sizes="194x194">
<link rel="icon" type="image/png" href="https://s3.amazonaws.com/serif-assets/favicon-96x96.png" sizes="96x96">
<link rel="icon" type="image/png" href="https://s3.amazonaws.com/serif-assets/android-chrome-192x192.png" sizes="192x192">
<link rel="icon" type="image/png" href="https://s3.amazonaws.com/serif-assets/favicon-16x16.png" sizes="16x16">
<link rel="manifest" href="https://s3.amazonaws.com/serif-assets/manifest.json">
<link rel="mask-icon" href="https://s3.amazonaws.com/serif-assets/safari-pinned-tab.svg" color="#520063">
<link rel="shortcut icon" href="https://s3.amazonaws.com/serif-assets/favicon.ico">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="msapplication-TileImage" content="https://s3.amazonaws.com/serif-assets/mstile-144x144.png">
<meta name="msapplication-config" content="https://s3.amazonaws.com/serif-assets/browserconfig.xml">
<meta name="theme-color" content="#520063">
</head>
<body>
<div id="app">${html}</div>
<script
src="https://code.jquery.com/jquery-3.1.1.min.js"
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
crossorigin="anonymous">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.16.0/moment.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.0.1/fullcalendar.min.js"></script>
<script>
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState)};
</script>
<script src="/bundle.js"></script>
</body>
</html>
`;
}
function handleRender(req, res) {
const store = createStore(reducer);
const html = renderToString(
<Provider store={store}>
<App />
</Provider>
);
const preloadedState = store.getState();
res.send(renderFullPage(html, preloadedState));
}
app.use(handleRender);
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Running on port ${port}`);
});
index.jsx
import 'babel-polyfill'; // http://redux.js.org/docs/advanced/AsyncActions.html#note-on-fetch
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store';
import App from './components/App.jsx';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('app')
);
store.js
import { createStore, compose, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
import reducer from './reducers';
const preloadedState = window.__PRELOADED_STATE__;
const store = createStore(
reducer,
preloadedState,
compose(
applyMiddleware(thunkMiddleware),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)
);
export default store;
App.jsx
import injectTapEventPlugin from 'react-tap-event-plugin'; // Needed for onTouchTap
import React from 'react';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import { grey500, white, fullBlack } from 'material-ui/styles/colors';
import { fade } from 'material-ui/utils/colorManipulator';
import colors from '../colors';
import NavBar from './NavBar.jsx';
import Serif from './Serif.jsx';
// http://stackoverflow.com/a/34015469/988941
injectTapEventPlugin();
const muiTheme = getMuiTheme({
palette: {
primary1Color: colors.northwesternPurple,
primary2Color: colors.northwesternPurple120,
primary3Color: grey500,
accent1Color: colors.northwesternPurple30,
accent2Color: colors.richBlack10,
accent3Color: colors.richBlack50,
textColor: colors.richBlack80,
alternateTextColor: white,
canvasColor: white,
borderColor: colors.richBlack20,
disabledColor: fade(colors.richBlack80, 0.3),
pickerHeaderColor: colors.northwesternPurple,
clockCircleColor: fade(colors.richBlack80, 0.07),
shadowColor: fullBlack
}
});
export default class App extends React.Component {
render() {
return (
<MuiThemeProvider muiTheme={muiTheme}>
<div> {/* MuiThemeProvider requires stricly one child element */}
<NavBar />
<Serif />
</div>
</MuiThemeProvider>
);
}
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Serif</title>
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.0.1/fullcalendar.min.css">
<link rel="stylesheet" href="materialFullCalendar.css">
<link rel="apple-touch-icon" sizes="57x57" href="https://s3.amazonaws.com/serif-assets/apple-touch-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="https://s3.amazonaws.com/serif-assets/apple-touch-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="https://s3.amazonaws.com/serif-assets/apple-touch-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="https://s3.amazonaws.com/serif-assets/apple-touch-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="https://s3.amazonaws.com/serif-assets/apple-touch-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="https://s3.amazonaws.com/serif-assets/apple-touch-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="https://s3.amazonaws.com/serif-assets/apple-touch-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="https://s3.amazonaws.com/serif-assets/apple-touch-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="https://s3.amazonaws.com/serif-assets/apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" href="https://s3.amazonaws.com/serif-assets/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="https://s3.amazonaws.com/serif-assets/favicon-194x194.png" sizes="194x194">
<link rel="icon" type="image/png" href="https://s3.amazonaws.com/serif-assets/favicon-96x96.png" sizes="96x96">
<link rel="icon" type="image/png" href="https://s3.amazonaws.com/serif-assets/android-chrome-192x192.png" sizes="192x192">
<link rel="icon" type="image/png" href="https://s3.amazonaws.com/serif-assets/favicon-16x16.png" sizes="16x16">
<link rel="manifest" href="https://s3.amazonaws.com/serif-assets/manifest.json">
<link rel="mask-icon" href="https://s3.amazonaws.com/serif-assets/safari-pinned-tab.svg" color="#520063">
<link rel="shortcut icon" href="https://s3.amazonaws.com/serif-assets/favicon.ico">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="msapplication-TileImage" content="https://s3.amazonaws.com/serif-assets/mstile-144x144.png">
<meta name="msapplication-config" content="https://s3.amazonaws.com/serif-assets/browserconfig.xml">
<meta name="theme-color" content="#520063">
</head>
<body>
<div id="app"></div>
<script
src="https://code.jquery.com/jquery-3.1.1.min.js"
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
crossorigin="anonymous">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.16.0/moment.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.0.1/fullcalendar.min.js"></script>
<script src="/bundle.js"></script>
</body>
</html>
bundle.js https://gist.github.com/Joonpark13/2b9c3bb7b8e07e8ee898650c7eeb1b88
Any help would be much appreciated. Thank you!