Open eromoe opened 8 years ago
I think that there is no need for standalone frontend branch. The only "switch" you need to turn off is __SSR__
inside src/server.js
file. Then if you execute npm run build
you will get standalone app without server rendering which might be hosted on any server with any backend (I use it with Rails). For more info (about API communication) see the docs https://github.com/erikras/react-redux-universal-hot-example/blob/master/docs/ApiConfig.md
Hi,
Your request coincides with something I'm trying to get working actually - here's what I've done so far, its quick and dirty and helmet is broken at the moment for it but I don't have the luxury of time.
Added /src/static.js
import 'babel-polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import createStore from './redux/create';
import ApiClient from './helpers/ApiClient';
import {Provider} from 'react-redux';
import { Router, hashHistory } from 'react-router';
import { ReduxAsyncConnect } from 'redux-connect';
import { syncHistoryWithStore } from 'react-router-redux';
import useScroll from 'scroll-behavior/lib/useStandardScroll';
import getRoutes from './routes';
const client = new ApiClient();
const history = useScroll(() => hashHistory)();
const dest = document.getElementById('content');
const store = createStore(history, client);
const syncedHistory = syncHistoryWithStore(history, store);
const component = (
<Router render={(props) =>
<ReduxAsyncConnect {...props} helpers={{client}} filter={item => !item.deferred} />
} history={syncedHistory}>
{getRoutes(store)}
</Router>
);
ReactDOM.render(
<Provider store={store} key="provider">
{component}
</Provider>,
dest
);
Added /src/webpack/static.config.js
require('babel-polyfill');
// Webpack config for creating the production bundle.
var path = require('path');
var webpack = require('webpack');
var CleanPlugin = require('clean-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var strip = require('strip-loader');
var projectRootPath = path.resolve(__dirname, '../');
var assetsPath = path.resolve(projectRootPath, './static/build');
// https://github.com/halt-hammerzeit/webpack-isomorphic-tools
var WebpackIsomorphicToolsPlugin = require('webpack-isomorphic-tools/plugin');
var webpackIsomorphicToolsPlugin = new WebpackIsomorphicToolsPlugin(require('./webpack-isomorphic-tools'));
module.exports = {
context: path.resolve(__dirname, '..'),
entry: {
'main': [
'bootstrap-sass!./src/theme/bootstrap.config.prod.js',
'font-awesome-webpack!./src/theme/font-awesome.config.prod.js',
'./src/static.js'
]
},
output: {
path: assetsPath,
filename: '[name].js',
chunkFilename: '[name].js',
publicPath: '/'
},
module: {
loaders: [
{ test: /\.jsx?$/, exclude: /node_modules/, loaders: [strip.loader('debug'), 'babel']},
{ test: /\.json$/, loader: 'json-loader' },
{ test: /\.less$/, loader: ExtractTextPlugin.extract('style', 'css?modules&importLoaders=2&sourceMap!autoprefixer?browsers=last 2 version!less?outputStyle=expanded&sourceMap=true&sourceMapContents=true') },
{ test: /\.scss$/, loader: ExtractTextPlugin.extract('style', 'css?modules&importLoaders=2&sourceMap!autoprefixer?browsers=last 2 version!sass?outputStyle=expanded&sourceMap=true&sourceMapContents=true') },
{ test: /\.css$/, loader: "style-loader!css-loader" },
{ test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/font-woff" },
{ test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/font-woff" },
{ test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/octet-stream" },
{ test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: "file" },
{ test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=image/svg+xml" },
{ test: webpackIsomorphicToolsPlugin.regular_expression('images'), loader: 'url-loader?limit=10240' }
]
},
progress: true,
resolve: {
modulesDirectories: [
'src',
'node_modules'
],
extensions: ['', '.json', '.js', '.jsx']
},
plugins: [
new CleanPlugin([assetsPath], { root: projectRootPath }),
// css files from the extract-text-plugin loader
new ExtractTextPlugin('[name].css', {allChunks: true}),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
},
__CLIENT__: true,
__SERVER__: false,
__DEVELOPMENT__: false,
__DEVTOOLS__: false
}),
// ignore dev config
new webpack.IgnorePlugin(/\.\/dev/, /\/config$/),
// optimizations
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
webpackIsomorphicToolsPlugin
]
};
Added /index.html
<!doctype html>
<html lang="en-us">
<head>
</title>
<link rel="shortcut icon" href="/favicon.ico"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link href="main.css" media="screen, projection" rel="stylesheet" type="text/css"
charset="UTF-8"/>
</head>
<body>
<div id="content" style="height:100%;min-height:100%;"></div>
<script src="main.js" charset="UTF-8"></script>
</body>
</html>
Edited package.json
"scripts": {
...
"build": "better-npm-run build",
"build-static": "better-npm-run build-static",
...
},
"betterScripts": {
...
"build": {
"command": "webpack --verbose --colors --display-error-details --config webpack/prod.config.js",
"env": {
"NODE_ENV": "production"
}
},
"build-static": {
"command": "webpack --verbose --colors --display-error-details --config webpack/static.config.js",
"env": {
"NODE_ENV": "production"
}
}
...
},
...
}
@eromoe I would like the same feature so I have forked a branch to meet this requirement.Maybe you can check it out: https://github.com/Alexoner/react-redux-universal-hot-example/tree/static
This branch will generate a html file dynamically using webpack isomorphic config when npm run build
.
@jmarceli how do you disable SSR? like this?
__DISABLE_SSR__ = true;
It looks like this option gets renamed since I was using it, but yes, I think that __DISABLE_SSR__ = true
will disable SSR.
I am a python developer, I'd like to use react-redux as frontend, django-rest-framework as backend. But the code embed too much things, hide a lot details, such as ajax, I can't see how client communicate with server. A standalone frontend branch would make it more clear to understand how the frontend moudles cooperate.