Git Product home page Git Product logo

Comments (17)

dvdzkwsk avatar dvdzkwsk commented on April 20, 2024

Hey, really sorry but I'll be away on vacation for the next 2 days. I'll take a look when I get back in case you haven't found any answers by then. Do you have a sample project that demonstrates this problem?

Anyways, good luck until then!

from react-redux-starter-kit.

HriBB avatar HriBB commented on April 20, 2024

So I finally figured out the problem. As @bitinn suggested in his reply, we should not build the server node-fetch/node-fetch#41 (comment). It makes sense.

So I reconfigured my server to use the ./src/server instead of the built ./dist/server in render-route middleware. Then I also reconfigured webpack to only use a single client config. The error went away, because now I'm not building the server app anymore.

BTW what are the reasons for building the server app?

from react-redux-starter-kit.

dvdzkwsk avatar dvdzkwsk commented on April 20, 2024

Interesting. So, not to be pedantic but I'm not bundling the server, I'm bundling the client application twice - once for client distribution, and once for server consumption. The reasoning for the latter bundle is that I want to be able to import styles and other non-js assets within the client application (which is a major feature of webpack), but those sorts of imports don't work in a non-webpack environment (i.e. the Koa server). Compiling this separate bundle allows the server to simply ignore those assets.

From what I've seen, a lot of universal boilerplates simply avoid this issue by restricting you to js-only imports. This means you can directly import all your client source code freely without a build step, so long as you have some sort of JSX transformer like Babel. There's no real problem with this approach, but unless I'm missing something you're giving up a lot of what Webpack has to offer. Perhaps it's just a matter of a difference in approach: I just want basic server rendering, they want fully isomorphic/universal applications.

I'm still not convinced this is unsolvable in this starter kit, but until I get a minute to toy with it myself I guess I'll have to defer to the issue you referenced: node-fetch/node-fetch#41 (comment). Anyways, glad you fixed the issue!

from react-redux-starter-kit.

HriBB avatar HriBB commented on April 20, 2024

Hmm now I understand. When I started thinking about how to implement styles it became clear to me, that in a non-webpack environment style imports wont work. ATM I am using normal sass loader in development. For production I have a different config with ExtractTextPlugin and I simply disable loading of .css and .scss files on server

require('babel/register')({
  stage: 0
});

require.extensions['.css'] = function() {return null}
require.extensions['.scss'] = function() {return null}

require('./index');

And then there's this https://github.com/halt-hammerzeit/webpack-isomorphic-tools ...

I'm still a bit confused as to what is the best way to setup webpack dev server. Do you run it together with koa server or standalone? Do you use server rendering in development? If not, how do you load your initial data into redux store? I want to be able to run koa server together with webpack-dev-server in the background for hot reloading. I already had a working env, but when I started implementing styles it all fell apart :P

Aaaanyway ... I will probably switch back to bundling the client app for server :) I knew that there must have been a good reason why you did this ... and now I know.

from react-redux-starter-kit.

dvdzkwsk avatar dvdzkwsk commented on April 20, 2024

Exactly, and at this point I'm wondering if the easiest solution is to just deprecate support for non-JS assets. If you want styles, you may just have to hop on the bandwagon of inline styles (either that or just build them separately). In fact, I started a discussion for this very topic here: #61.

Anyways, as you've discovered, the current architecture (needing to precompile the app) means that it's essentially pointless to run the Koa server and webpack-dev-server in tandem, which isn't awesome. I did recently add a (very basic) ability to inject initial state in from the server (see #57), but even still you're not able to refresh changes to the React application on the fly, which leads to a less-than-stellar developer experience.

What are your thoughts on this? If you just drop css support you save yourself a lot of headache and can do exactly what you're asking: namely run the Koa and webpack-dev-server together. You do lose a few other things in the process (aliases, dynamic asset insertion with HtmlWebpackPlugin, for example), but perhaps the tradeoff is worth it.

from react-redux-starter-kit.

HriBB avatar HriBB commented on April 20, 2024

I agree with https://byjoeybaker.com/react-inline-styles ... inline styles are "not there yet".
Need to do some research, but in the end I would like to have 1 scss file per component + global styles, overrides and vendors. All hot reloadable with webpack dev server and development server rendering :)

from react-redux-starter-kit.

jimpick avatar jimpick commented on April 20, 2024

I hit this too. Webpack is a bit mysterious to me. Perhaps there's a way to move the isomorphic-fetch method into the koa side of things so webpack doesn't touch it?

I'm also struggling with how to package a server side API that I'd like to have live in the same tree, and eventually bundle it with the server. But I'd like to use the API when developing the client side as well.

from react-redux-starter-kit.

HriBB avatar HriBB commented on April 20, 2024

The problem with isomorphic-fecth is that it throws an error when you try to bundle it for node with webpack. But that could easily be fixed.

Main problem is the webpack setup and workflow. For my "dream setup", my main requirement is that in development I can use webpack-dev-server with hot reload in combination with an existing server (koa in my case). I want to be able to render the application on the server and use hot reload on the client. My current setup allows me to do everything but the server rendering in dev mode. So I just need to figure out how to tell koa server to use webpack-dev-server hot reload in development. Preferably without any gulp or grunt.

In this example webpack-dev-server is started from the express server, but only in development. Then all requests to bundle are proxied from the express to dev-server. Maybe we can use proxy for a perfect setup?

Also I see that there are two ways to run the server: inline or iframe, but the docs are very basic. If only there was some good example for this ...

Back to the drawing board ... :)

from react-redux-starter-kit.

dvdzkwsk avatar dvdzkwsk commented on April 20, 2024

@HriBB if you want the iframe mode, just append /webpack-dev-server/ to the URL. not sure how this works with React Router though, as I haven't tested it yet.

It's fairly trivial to get the Koa app to serve assets from the webpack-dev-server (I should get around to this...) but the problem is that the bundle that the server consumes to render the application can't be hot reloaded (at least to my knowledge), so after the first hot reload your server + client application get out of sync. Maybe take a look at webpack-hot-middleware and see how that fits in to things.

from react-redux-starter-kit.

crazile avatar crazile commented on April 20, 2024

I ran into the same issue with isomorphic-fetch. The steps below seem to fix it:

1. Install json-loader

npm install --save-dev json-loader

2. Add the following to the start of the preLoaders array in /build/webpack/server.js

{
  test: /\.json$/,
  loader: 'json-loader'
}

Then npm run compile should work. Hope this helps.

Edit: This only gets isomorphic-fetch to compile with webpack, but you'll still get the warning about an expression in a require statement.

from react-redux-starter-kit.

dvdzkwsk avatar dvdzkwsk commented on April 20, 2024

Thanks @crazile. Should I just add this in as a default loader so nobody else runs into this?

from react-redux-starter-kit.

crazile avatar crazile commented on April 20, 2024

Hi @davezuko, it looks like being able to require('file.json') was added in node 0.5.x so it could turn up in some universal/isomorphic libraries. I don't think there's any harm in adding support for it in the default loaders.

from react-redux-starter-kit.

dvdzkwsk avatar dvdzkwsk commented on April 20, 2024

Ok cool, I'll add it then. Curious about why you added it as a preLoader rather than a regular loader, however. Any particular reason?

from react-redux-starter-kit.

crazile avatar crazile commented on April 20, 2024

Honestly, I thought it might need to run before the other loaders, so that was the first place I tried. I just tested it now in with the regular loaders and it works fine there as well.

I realise now I didn't actually solve HriBB's issue. We both had the same problem with isomorphic-fetch, fixed it the same way by adding json-loader (turns out there's no difference between loader: 'json' and loader: 'json-loader' one is just shorthand for the other.) Then ran into the next warning about expressions in a require statement. This was caused intentionally by a dependency of isomorphic-fetch trying to discourage browserfying the library (presumably because it contains large json files.) That warning is what this issue was originally about and which my answer doesn't fix.

That said, adding json-loader to the stater kit will still help anyone who runs into issues with require json.

from react-redux-starter-kit.

HriBB avatar HriBB commented on April 20, 2024

I am thinking about using two separate servers, koa for api server and express for serving react app. The reason for using express for react app is to be able to use webpack-hot-middleware which lets you use hot reloading with your existing server. Then you can pre-render your app on server and use hot reloading on client in development. What do you think about this approach? It's basically more code and more setup, but for me it makes sense. I really like koa and how I can keep flat code structure with generators. Other option is to create webpack-hot-koa-middleware :)

from react-redux-starter-kit.

HriBB avatar HriBB commented on April 20, 2024

So I did exactly as I said above. For now it works perfectly and I hope I don't find any big problems with this setup. Good by webpack dev server :) Here is my setup if you are interested. It's not yet perfect, still need to improve the fetchInitialData() logic, but other than that I'm pretty happy.

server/index.js

import 'babel-core/polyfill';

import { readFileSync } from 'fs';
import { resolve } from 'path';

import Express from 'express';
import serve from 'serve-static';
import favicon from 'serve-favicon';

import React from 'react';
import ReactDOMServer from 'react-dom/server';

import { Provider } from 'react-redux';
import { ReduxRouter } from 'redux-router';
import { reduxReactRouter, match } from 'redux-router/server';
import createHistory from 'history/lib/createMemoryHistory';

import configureStore from '../client/stores';
import routes from '../client/routes';

import {
  fetchTypes,
  fetchLocationsByType,
  fetchLocationBySlug
} from '../client/actions';

// Server config
const host = 'localhost';
const port = 3000;

// Create express app
const app = new Express();

// Attach hot middleware in development
if (__DEV__) {
  console.log('==> Using webpack-hot-middleware');
  // Step 1: Create & configure a webpack compiler
  const webpack = require('webpack');
  const webpackConfig = require('../webpack/dev.config');
  const compiler = webpack(webpackConfig);

  // Step 2: Attach the dev middleware to the compiler & the server
  app.use(require("webpack-dev-middleware")(compiler, {
    noInfo: true,
    publicPath: webpackConfig.output.publicPath
  }));

  // Step 3: Attach the hot middleware to the compiler & the server
  app.use(require("webpack-hot-middleware")(compiler, {
    log: console.log,
    path: '/__webpack_hmr',
    heartbeat: 10 * 1000
  }));
}

// Serve favicon
app.use(favicon(resolve(__dirname, '..', 'static', 'favicon.ico')));

// Serve app
app.use('/app.js', (req, res) => {
  res.sendFile(resolve(__dirname, '..', 'dist', 'client', 'app.js'));
});

// Serve styles
app.use('/styles.css', (req, res) => {
  res.sendFile(resolve(__dirname, '..', 'dist', 'client', 'styles.css'));
});

// Prepare template for router middleware
const template = readFileSync(resolve(__dirname, '..', 'dist', 'client', 'index.html'), 'utf-8')
  .replace('<div id="cb"></div>', '<div id="cb">${content}</div><script>window.__INITIAL_STATE__ = ${data};</script>');

// Render react app
app.use((req, res) => {
  console.info('==> Render react application:', req.url);

  // Do the redux magic
  const history = createHistory();
  const router = reduxReactRouter({ history, routes });
  const store = configureStore(router);

  // Run the redux-router
  store.dispatch(match(req.url, (error, redirectLocation, renderProps) => {
    if (error) {
      console.log(error);
      return res.status(500).end('Internal server error');
    }
    if (redirectLocation) {
      return res.status(301).redirect(redirectLocation.pathname);
    }
    if (!renderProps) {
      return res.status(404).end('Not found'); // TODO: render 404 on client?
    }

    function renderReactApp() {
      // Render react app to string
      const content = ReactDOMServer.renderToString(
        <div className="app">
          <Provider store={store}>
            <ReduxRouter {...renderProps}/>
          </Provider>
        </div>
      );
      // Get initial application state from redux store
      const initialState = store.getState();
      // Inject content and initial state into html
      const html = template.replace('${content}', content).replace('${data}', JSON.stringify(initialState));
      // Return final version back to middleware
      return html;
    }

    function fetchInitialData() {
      const path = renderProps.location.pathname;
      if (path === '/') {
        return store.dispatch(fetchTypes());
      } else if (path.indexOf('/type') === 0) {
        return store.dispatch(fetchLocationsByType(renderProps.params.type));
      } else if (path.indexOf('/location') === 0) {
        return store.dispatch(fetchLocationBySlug(renderProps.params.location));
      } else {
        return Promise.resolve(true);
      }
    }

    fetchInitialData()
      .then(renderReactApp)
      .then(html => res.end(html))
      .catch(err => res.end(err.message));

  }));

});

app.listen(port, (err) => {
  if (err) {
    console.error(err);
  }
  console.log('==> Express server running on http://' + host + ': ' + port + '/');
});

server/start.js

// Babel require hook
require('babel/register')({
  stage: 0
});

// Disable styles on server
// TODO: check if this is still needed with webpack-hot-middleware
require.extensions['.css'] = function() {return null}
require.extensions['.scss'] = function() {return null}

// Global application config
global.__DEV__    = process.env.NODE_ENV !== 'production';
global.__PROD__   = process.env.NODE_ENV === 'production';
global.__CLIENT__ = false;
global.__SERVER__ = true;

// Load server
require('./index');

from react-redux-starter-kit.

dvdzkwsk avatar dvdzkwsk commented on April 20, 2024

Closing this since this repo no longer comes with a server. I should probably find a good place to stick this post though since it might be helpful for others.

from react-redux-starter-kit.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.