1

First off, I'm very new to this Node.js world, so please bear with me for my noobishness. I'm currently getting my hands dirty on Node.js + Express + React + Webpack stack. I managed to run some code in development, but unable to run in production. I got the following error when I try to run node server.js on the terminal.

Nicholass-MacBook-Pro:sevva-backend nicholaslie$ node server.js
/Users/nicholaslie/Documents/Sevva/sevva-backend/server.js:7
import React from 'react'
^^^^^^
SyntaxError: Unexpected token import
    at Object.exports.runInThisContext (vm.js:76:16)
    at Module._compile (module.js:545:28)
    at Object.Module._extensions..js (module.js:582:10)
    at Module.load (module.js:490:32)
    at tryModuleLoad (module.js:449:12)
    at Function.Module._load (module.js:441:3)
    at Module.runMain (module.js:607:10)
    at run (bootstrap_node.js:382:7)
    at startup (bootstrap_node.js:137:9)
    at bootstrap_node.js:497:3

However, in my local machine (development environment), I can run this just fine with npm start.

Nicholass-MacBook-Pro:sevva-backend nicholaslie$ npm start

> sevva-backend@0.0.1 start /Users/nicholaslie/Documents/Sevva/sevva-backend
> if-env NODE_ENV=production && npm run start:prod || npm run start:dev


> sevva-backend@0.0.1 start:dev /Users/nicholaslie/Documents/Sevva/sevva-backend
> webpack-dev-server --progress --profile --colors --inline --content-base public --history-api-fallback

 70% 1/1 build modules http://127.0.0.1:3000/
webpack result is served from /
content is served from /Users/nicholaslie/Documents/Sevva/sevva-backend/public
404s will fallback to /index.html
3076ms build modules      
8ms seal 
6ms optimize 
10ms hashing
30ms create chunk assets
23ms additional chunk assets
57ms optimize chunk assets
77ms optimize assets
20ms emit

When I go to http://localhost:3000, my page loads up as follows.

local development

package.json:

{
  "name": "sevva-backend",
  "version": "0.0.1",
  "private": true,
  "main": "server.js",
  "scripts": {
    "build": "if-env NODE_ENV=production build:prod || build:dev",
    "build:prod": "babel -d ./src ./public/bundle.js -s && webpack --config webpack.production.config.js",
    "build:dev": "webpack",
    "lint": "eslint src",
    "start": "if-env NODE_ENV=production && npm run start:prod || npm run start:dev",
    "start:dev": "webpack-dev-server --progress --profile --colors --inline --content-base public --history-api-fallback",
    "start:prod": "webpack --config webpack.production.config.js && node server.js",
    "test": "NODE_ENV=test mocha --recursive test",
    "test:coverage": "nyc npm test",
    "test:unit": "mocha --recursive test/middleware test/models test/routes",
    "test:integration": "mocha --recursive test/integration"
  },
  "dependencies": {
    "babel": "^6.5.2",
    "babel-cli": "^6.18.0",
    "babel-core": "^6.18.2",
    "babel-eslint": "^7.1.0",
    "babel-loader": "^6.2.7",
    "babel-plugin-css-modules-transform": "^1.1.0",
    "babel-plugin-transform-class-properties": "^6.18.0",
    "babel-plugin-transform-decorators-legacy": "^1.3.4",
    "babel-plugin-transform-es2015-modules-commonjs": "^6.18.0",
    "babel-plugin-transform-runtime": "^6.15.0",
    "babel-preset-es2015": "^6.18.0",
    "babel-preset-react": "^6.16.0",
    "babel-preset-stage-0": "^6.16.0",
    "babel-register": "^6.18.0",
    "babel-runtime": "^6.18.0",
    "body-parser": "^1.13.3",
    "compression": "^1.6.2",
    "cookie-parser": "^1.3.3",
    "css-loader": "^0.25.0",
    "eslint": "^3.9.1",
    "express": "^4.14.0",
    "extract-text-webpack-plugin": "^1.0.1",
    "file-loader": "^0.9.0",
    "firebase": "^3.5.3",
    "glob": "^6.0.4",
    "html-webpack-plugin": "^2.24.1",
    "if-env": "^1.0.0",
    "ignore-styles": "^5.0.1",
    "jade": "^1.11.0",
    "method-override": "^2.3.0",
    "morgan": "^1.6.1",
    "node-sass": "^3.11.2",
    "path": "^0.12.7",
    "postcss-loader": "^1.1.0",
    "react": "^15.3.2",
    "react-dom": "^15.3.2",
    "react-hot-loader": "^3.0.0-beta.6",
    "react-router": "^3.0.0",
    "react-tools": "^0.13.3",
    "react-transform": "0.0.3",
    "sass-loader": "^4.0.2",
    "serve-favicon": "^2.3.0",
    "style-loader": "^0.13.1",
    "url-loader": "^0.5.7",
    "webpack": "^1.13.3",
    "webpack-cleanup-plugin": "^0.4.1",
    "webpack-dev-middleware": "^1.8.4",
    "webpack-dev-server": "^1.16.2",
    "webpack-hot-middleware": "^2.13.1"
  },
  "devDependencies": {
    "babel-cli": "^6.18.0",
    "babel-eslint": "^7.1.0",
    "babel-preset-es2015": "^6.18.0",
    "babel-preset-react": "^6.16.0",
    "chai": "^3.5.0",
    "debug": "^2.2.0",
    "eslint": "^3.9.1",
    "eslint-plugin-react": "^6.6.0",
    "mocha": "^3.0.2",
    "nyc": "^8.1.0",
    "request": "^2.60.0",
    "supertest": "^2.0.0",
    "time-grunt": "^1.2.1"
  },
  "engines": {
    "node": "6.6.0"
  }
}

Mind me for much of the unnecessary dependencies above. I'm very curious as to why webpack-dev-server works perfectly but not with node server.js, as seen in the file above.

Right now I've been scratching my head for hours trying to make sense of this issue. First off, I'm very aware that that ES6 import statements doesn't seem to work with the node command.

So, what I did was I tried to use babel-node instead. However, I can't also get it to work as I expect it to, it returns the following errors.

Nicholass-MacBook-Pro:sevva-backend nicholaslie$ babel-node server.js
/Users/nicholaslie/Documents/Sevva/sevva-backend/node_modules/bootstrap/dist/css/bootstrap.min.css:6
 *//*! normalize.css v4.2.0 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block}audio:not([controls]){display:none;height:0}progress{vertical-align:baseline}[hidden],template{display:none}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}im
SyntaxError: Unexpected token {
    at Object.exports.runInThisContext (vm.js:76:16)
    at Module._compile (module.js:545:28)
    at Module._extensions..js (module.js:582:10)
    at Object.require.extensions.(anonymous function) [as .js] (/Users/nicholaslie/.nvm/versions/node/v7.0.0/lib/node_modules/babel-cli/node_modules/babel-register/lib/node.js:152:7)
    at Module.load (module.js:490:32)
    at tryModuleLoad (module.js:449:12)
    at Function.Module._load (module.js:441:3)
    at Module.require (module.js:500:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (/Users/nicholaslie/Documents/Sevva/sevva-backend/src/app.jsx:1:1)

Somehow, the babel-node also doesn't work as expected, as it fails on transpiling CSS files. My app.jsx file is as follows:

import 'bootstrap/dist/css/bootstrap.min.css'
import styles from './stylesheets/index.scss'
import navlinkStyles from './stylesheets/components/_navlink.scss'
import React from 'react'
import { IndexLink } from 'react-router'
import NavLink from './components/NavLink'
import Home from './components/Home'

export default class App extends React.Component {
  render() {
    return (
      <div>
        {this.props.children || <Home />}
        <h1>It Works!</h1>
        <p>This React project just works including <span className={styles.blueBg}>module</span> local styles.</p>
        <p>Global bootstrap css import works too as you can see on the following button.</p>
        <p><a className="btn btn-primary btn-lg">Enjoy!</a></p>
        <ul role="nav">
          <li><IndexLink to="/" activeClassName={navlinkStyles.navlinkActive}>Home</IndexLink></li>
          <li><NavLink to="/about">About</NavLink></li>
          <li><NavLink to="/repos">Repos</NavLink></li>
        </ul>

        {/* add this */}
        {this.props.children}
      </div>
    )
  }
}

As a side note, I'm aware that babel-node shouldn't be use for production. As it is said in the docs:

Not meant for production use You should not be using babel-node in production. It is unnecessarily heavy, with high memory usage due to the cache being stored in memory. You will also always experience a startup performance penalty as the entire app needs to be compiled on the fly.

My webpack.config.js file:

"use strict";
var webpack = require('webpack');
var path = require('path');
var loaders = require('./webpack.loaders');
var HtmlWebpackPlugin = require('html-webpack-plugin');

const HOST = process.env.HOST || "127.0.0.1";
const PORT = process.env.PORT || "3000";

module.exports = {
    entry: [
        'react-hot-loader/patch',
        './src/index.jsx' // your app's entry point
    ],
    externals: {React: 'react'},
    devtool: process.env.WEBPACK_DEVTOOL || 'cheap-module-source-map',
    output: {
        path: 'public',
        filename: 'bundle.js',
        publicPath: '/'
    },
    resolve: {
        extensions: ['', '.js', '.jsx']
    },
    module: {
        loaders: [{
            // global css
            test: /\.css$/,
            exclude: /[\/\\]src[\/\\]/,
            loaders: [
                'style?sourceMap',
                'css'
            ]
        }, {
            // local scss modules
            test: /\.scss$/,
            exclude: /[\/\\](node_modules|bower_components|public)[\/\\]/,
            loaders: [
                'style?sourceMap',
                'css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
                'postcss',
                'sass'
            ]
        }, {
            // local css modules
            test: /\.css$/,
            exclude: /[\/\\](node_modules|bower_components|public)[\/\\]/,
            loaders: [
                'style?sourceMap',
                'css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]'
            ]
        }, {
            //JS/JSX files
            test: /\.(js|jsx)$/,
            exclude: /node_modules/,
            loaders: ['react-hot-loader/webpack', 'babel?presets[]=es2015,presets[]=stage-0,presets[]=react,plugins[]=transform-runtime']
        }]
    },
    sassLoader: {
        includePaths: [path.resolve(__dirname, "./some-folder")]
    },
    devServer: {
        contentBase: "./public",
        // do not print bundle build stats
        noInfo: true,
        // enable HMR
        hot: true,
        // embed the webpack-dev-server runtime into the bundle
        inline: true,
        // serve index.html in place of 404 responses to allow HTML5 history
        historyApiFallback: true,
        port: PORT,
        host: HOST
    },
    plugins: process.env.NODE_ENV === 'production' ? [
        new webpack.optimize.DedupePlugin(),
        new webpack.optimize.OccurrenceOrderPlugin(),
        new webpack.optimize.UglifyJsPlugin()
    ] : [
            new webpack.NoErrorsPlugin(),
            new webpack.HotModuleReplacementPlugin(),
            new HtmlWebpackPlugin({
                template: './src/index.html'
            }),
        ]
};

My webpack.production.config.js file:

var fs = require('fs')
var webpack = require('webpack');
var path = require('path');
var loaders = require('./webpack.loaders');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var WebpackCleanupPlugin = require('webpack-cleanup-plugin');

module.exports = {
    entry: [
        './src/index.jsx'
    ],
    // keep node_module paths out of the bundle
    externals: fs.readdirSync(path.resolve(__dirname, 'node_modules')).concat([
        'react-dom/server', 'react/addons',
    ]).reduce(function (ext, mod) {
        ext[mod] = 'commonjs ' + mod
        return ext
    }, { React: 'react' }),
    output: {
        path: path.join(__dirname, 'public'),
        filename: 'bundle.js'
    },
    resolve: {
        extensions: ['', '.js', '.jsx']
    },
    module: {
        loaders: [{
            //local css modules
            test: /[\/\\]src[\/\\].*\.css/,
            exclude: /(node_modules|bower_components|public)/,
            loader: ExtractTextPlugin.extract('style', 'css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]')
        }, {
            //local scss modules
            test: /[\/\\]src[\/\\].*\.scss/,
            exclude: /(node_modules|bower_components|public)/,
            loader: ExtractTextPlugin.extract('style', 'css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss!sass')
        }, {
            //global css files
            test: /[\/\\](node_modules|global)[\/\\].*\.css$/,
            loader: ExtractTextPlugin.extract('style', 'css')
        }, {
            //JS/JSX files
            test: /\.(js|jsx)$/,
            exclude: /node_modules/,
            loaders: ['react-hot-loader/webpack', 'babel?presets[]=es2015,presets[]=stage-0,presets[]=react,plugins[]=transform-runtime']
        }]
    },
    node: {
        __filename: true,
        __dirname: true
    },
    plugins: [
        new WebpackCleanupPlugin(),
        new webpack.DefinePlugin({
            'process.env': {
                NODE_ENV: '"production"'
            }
        }),
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false,
                screw_ie8: true,
                drop_console: true,
                drop_debugger: true
            }
        }),
        new webpack.optimize.OccurenceOrderPlugin(),
        new ExtractTextPlugin('[contenthash].css', {
            allChunks: true
        }),
        new HtmlWebpackPlugin({
            template: './src/index.html',
            title: 'Webpack App'
        }),
        new webpack.optimize.DedupePlugin()
    ]
};

My objective: deploy this app in production. What is the correct command to run my app on the server, and what are the needed necessary changes? Hopefully someone can help :(

nic
  • 2,125
  • 1
  • 18
  • 33
  • Cheers for posting as much info as you did :). The issue here is that you need to use babel to compile your backend modules to use commonjs. Assuming you're using node6, it will support classes and such, but doesn't support modules yet. Webpack makes it work because it handles the compilation for you with the babel loader. I'm not replying as an answer, as i really dont know the best solution for it on the nodejs backend. Something i still need to learn myself. – agmcleod Nov 08 '16 at 15:18
  • @agmcleod, yeah, at first, I thought that the Node.js itself need updating, so I tried updating. But no, that doesn't work. Lol. – nic Nov 08 '16 at 15:19
  • Are you trying to create isomorphic react app? – Everettss Nov 08 '16 at 15:35
  • @Everettss, I'm not quite aware of the term(isomorphic react app), but all I want to do is actually prepare a web app with Express as the backend, and React at the front-end (for now). I guess Webpack will help me in optimizing the assets, compressing the js files and such to be delivered as a bundle (CMIIW). For now, that's my current objective :) – nic Nov 08 '16 at 15:46
  • It looks like you are trying to run function `renderToString` on server so it is isomorphic app. Just show us your `server.js`. – Everettss Nov 08 '16 at 15:48
  • @Everettss Ah, I see :) – nic Nov 08 '16 at 15:49

1 Answers1

0

1. If you want to create isomorphic react app

Since you are using JSX, .css loader and other fancy weback stuff you must use webpack to bundle server side code too. For more information look on this post Webpack for back-end?

2. If you want to react only on the client side

Just remove code for rendering static html on server side by function renderToString and only leave element hook for bootstrapping on client side.

Community
  • 1
  • 1
Everettss
  • 15,475
  • 9
  • 72
  • 98