R3uK
R3uK

Reputation: 14537

React App : Start API server with React server

I'm working on a pretty simple App (my first), but I can't figure out how to get both the API and the react server to start...

I'm using for client routes and I've used on another project so I've started my React project with it to setup the API.

But I was wondering if there was a way to use to handle API routes and return some data...

I've googled and looked around but I can seem to find anything about that (nor confirming nor refuting).

Does anyone have any input about that?
(I know it isn't a proper SO question but I can't seem to find any info to close the nagging wonder)

Upvotes: 4

Views: 1017

Answers (2)

codejockie
codejockie

Reputation: 10864

There's a way to start both API server and react. In your express main file in my case server.js. You'd need to install webpack-dev-middleware and webpack-hot-middleware.

// server.js
import path from 'path';
import express from 'express';
import webpack from 'webpack';
import webpackDevMiddleware from 'webpack-dev-middleware';
import webpackHotMiddleware from 'webpack-hot-middleware';
import config from './webpack.config';

const app = express(),
  DIST_DIR = path.join(__dirname, 'client'),
  HTML_FILE = path.join(DIST_DIR, 'index.html'),
  compiler = webpack(config),
  isDevelopment = process.env.NODE_ENV === 'development';

if (isDevelopment) {
  app.use(webpackDevMiddleware(compiler, {
    publicPath: config.output.publicPath,
  }));

  app.use(webpackHotMiddleware(compiler));
} else {
  app.use(express.static(DIST_DIR));
}

app.get('/', (req, res) => res.sendFile(HTML_FILE));
app.get('*', (req, res) => res.redirect(301, '/'));

app.listen(process.env.PORT || 4200);

Then in your webpack.config.js, you can follow my settings below:

const path = require('path');
const webpack = require('webpack');

process.env.NODE_ENV = process.env.NODE_ENV || 'development';

module.exports = {
  entry: [
    'webpack-hot-middleware/client',
    './app/app.jsx',
  ],
  externals: {
    jquery: 'jQuery',
    'react/addons': 'react',
    'react/lib/ExecutionEnvironment': 'react',
    'react/lib/ReactContext': 'react',
  },
  output: {
    path: path.resolve(__dirname, 'client'),
    filename: 'bundle.js',
    publicPath: '/',
    sourceMapFilename: 'bundle.map',
  },
  devtool: process.env.NODE_ENV === 'production'
    ? undefined : 'cheap-module-eval-source-map',
  resolve: {
    modules: ['node_modules', './app/components'],
    extensions: ['.js', '.jsx'],
  },
  module: {
    rules: [
      {
        test: /(\.js$|\.jsx$)/,
        exclude: /(node_modules|bower_components)/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: ['react', 'es2015', 'stage-0', 'airbnb'],
            },
          },
        ],
      },
      {
        test: /\.scss$/,
        use: ['style-loader', 'css-loader', 'sass-loader'],
      },
      {
        test: /\.(eot|svg|ttf|woff|woff2)(\?v=\d+\.\d+\.\d+)?$/,
        use: {
          loader: 'file-loader',
          options: {
            name: '[name].[ext]'
          }
        }
      }
    ],
  },
  plugins: [
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoEmitOnErrorsPlugin(),
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery',
    }),
    new webpack.optimize.UglifyJsPlugin({
      sourceMap: true,
      minimize: true,
      compressor: {
        warnings: false,
      },
    }),
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify(process.env.NODE_ENV)
      },
    }),
  ],
};

Then in your package.json scripts:

// package.json
"scripts": {
    "build": "webpack",
    "postinstall": "npm run build",
    "start": "babel-node server.js",
    "start:dev": "nodemon -e js --exec babel-node -- ./server.js",
    "test": "karma start"
  }

Now when you start your express server, your API and react will run together.

Upvotes: 1

JJJ
JJJ

Reputation: 3332

I'm working on a pretty simple react App (my first), but I can't figure out how to get both the API and the react server to start...

There is an npm module that I use for my React/Express app called concurrently that I use to start my client and backend servers at the same time.

I installed that globally:

npm install concurrently

In my app's main package.json, I have the scripts setup like this:

"scripts":{
  "start": "concurrently \"npm run server\" \"npm run client\"",
  "server": "node bin/www",
  "client": "node start-client.js"
}

That setup allows me to run npm start and it starts up my server and client scripts.

In start-client.js, I have this:

const args = ["start"];
const opts = { stdio: "inherit", cwd: "client", shell: true };
require("child_process").spawn("npm", args, opts);

start-client.js is located at the root of my app.

My file structure looks like this:

|--bin
|--client
|--routes
|--app.js
|--package.json
|--start-client.js

But I was wondering if there was a way to use react-router to handle API routes and return some data...

To fetch data from the API server, I use the native fetch() method inside my React components.

Since I'm using Express, I will create a route and export it to my app.js file like so:

/* myRoute.js */
var express = require('express')
var router = express.Router()

router.get('/', function(req, res, next) {
  res.send('index', {title: 'Express'})
})

module.exports = router

/* app.js */

var myRoute = require('./routes/myRoute')
var app = express()
//will fetch data from this endpoint
app.use('/myRoute', myRoute)

Now in my React component, I will fetch data from /myRoute like so:

fetch('/myRoute')
  .then(res => JSON.parse(res))
  .then(res => console.log(res))

Upvotes: 1

Related Questions