How to produce react bundle.js through webpack via server.js? - node.js

Server.js
var express = require('express');
app.use(express.static('public'));
app.listen(PORT, function () {
console.log('Express server is up on port ' + PORT);
});
Webpack.config.js
var path = require('path');
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
const extractSass = new ExtractTextPlugin({
});
// const autoprefixer = require('autoprefixer');
module.exports = {
entry: path.resolve(__dirname, 'src', 'Main.js'),
output: {
path: __dirname,
publicPath: '/',
filename: 'bundle.js'
},
module: {
loaders: [{
exclude: /node_modules/,
test: /\.js$/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015', 'stage-1'],
plugin
s: ["react-html-attrs"]
}
}
, {
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2)$/,
loader: 'url-loader?limit=10000',
},
{
test: /masonry|imagesloaded|fizzy\-ui\-utils|desandro\-|outlayer|get\-size|doc\-ready|eventie|eventemitter/,
loader: 'imports-loader?define=>false&this=>window'
},
{
test: /\.css$/,
loader: "style-loader!css-loader"
},
{
test: /\.scss$/,
loaders: ["style-loader", "css-loader", "sass-loader"]
}]
},
plugins: [
extractSass
],
resolve: {
extensions: ['.js', '.jsx', '.css', '.scss'],
},
devServer: {
historyApiFallback: true,
contentBase: './',
}
};
I am trying to deploy on Heroku But before that when I run on cmd through npm start it starts on localhost but say Cannot GET / and nothing else runs but when I pass on cmd webpack-dev-server --config webpack.config.js it runs on localhost 8080 and works fine! I need to add serve.js before deploying on heroku what I am missing?

Make sure you have a file named Procfile that includes web: <command to run your project>. That command might be node server.js or something else dependent on Webpack, which has a Production Guide here (possibly webpack -p).

Related

Can't find index.html when bundling Node.js server with Webpack

I'm trying to setup webpack to bundle my backend code.
My webpack config looks like:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const nodeExternals = require('webpack-node-externals');
const outputDirectory = 'dist';
const client = {
mode: 'production',
entry: {
'app': [
'babel-polyfill',
'./client/index.js'
]
},
output: {
path: path.join(__dirname, outputDirectory),
publicPath: '/',
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.(js|jsx)$/, exclude: /node_modules/, loader: 'babel-loader'
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.(gif|svg|jpg|png)$/,
loader: "file-loader"
}
]
},
plugins: [
new CleanWebpackPlugin([outputDirectory]),
new HtmlWebpackPlugin({
template: './index.html',
})
]
}
const server = {
mode: 'production',
target: 'node',
entry: {
'app': [
'./server/server.js'
]
},
externals: [nodeExternals()],
output: {
path: path.join(__dirname, '/server'),
filename: 'server.bundle.js'
}
}
module.exports = [client, server]
If I run the non-webpack server.js, everything works fine. However if I run the webpack bundled server.bundle.js, express throws:
Error: ENOENT: no such file or directory, stat '/dist/index.html'
Both server files are in the same directory. Has anyone run into this issue before?
I figured it out, it's not explicitly stated in webpack's documentation but you need to configure a "node" property when using express
Ex. add this to your config
node: {
// Need this when working with express, otherwise the build fails
__dirname: false, // if you don't put this is, __dirname
__filename: false, // and __filename return blank or /
},

React + Webpack: process.env is EMPTY after run build

A common problem but as usual, every solution found on this website, not fit my case.
I've create a .env.production file with specific constant.
In my package.json I have:
"build": "NODE_ENV=production webpack --config webpack.config.js --colors",
I run the build with the classic: npm run build
This is my webpack.config
const webpack = require('webpack');
const path = require('path');
var config = {
context: __dirname + '/src',
entry: {
javascript: "./index.js",
},
output: {
// path:path.join(__dirname, './dist'),
path: path.join(__dirname,'../static/js/'),
filename: 'bundle.js',
},
devServer: {
inline: true,
port: 8080
},
resolveLoader: {
modules: [path.join(__dirname, 'node_modules')]
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['react']
}
},
{
test: /\.css$/,
loader: 'style-loader'
},
{
test: /\.css$/,
loader: 'css-loader',
query: {
modules: true,
localIdentName: '[name]__[local]___[hash:base64:5]'
}
},
{
test: /\.svg$/,
use: [
{
loader: "babel-loader"
},
{
loader: "react-svg-loader",
options: {
jsx: true // true outputs JSX tags
}
}
]
}
]
},
}
module.exports = config;
As you can see, Im not overriding ENV in webpack config using the webpack.DefinePlugin plugin.
So why my process.env is EMPTY?
When I start the app with npm start, the process.env is normally filled and process.env.NODE_ENV is set to development.
Thank you for any help!

webpack using with nodejs

I am new in reactjs. I am just start learning reactjs. I have problem using webpack in nodejs. I want to create node server which will run the webpack file. I have webpack file:
const {resolve} = require('path');
const webpack = require('webpack');
const validate = require('webpack-validator');
const {getIfUtils, removeEmpty} = require('webpack-config-utils');
module.exports = env => {
const {ifProd, ifNotProd} = getIfUtils(env)
return validate({
entry: './index.js',
context: __dirname,
output: {
path: resolve(__dirname, './build'),
filename: 'bundle.js',
publicPath: '/build/',
pathinfo: ifNotProd(),
},
devtool: ifProd('source-map', 'eval'),
devServer: {
port: 8080,
historyApiFallback: true
},
module: {
loaders: [
{test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader'},
{test: /\.css$/, loader: 'style-loader!css-loader'},
{test: /(\.eot|\.woff2|\.woff|\.ttf|\.svg)/, loader: 'file-loader'},
],
},
plugins: removeEmpty([
ifProd(new webpack.optimize.DedupePlugin()),
ifProd(new webpack.LoaderOptionsPlugin({
minimize: true,
debug: false,
quiet: true,
})),
ifProd(new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"',
},
})),
ifProd(new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
screw_ie8: true, // eslint-disable-line
warnings: false,
},
})),
])
});
};
How can i use this configuration with nodejs. please help
First of all your webpack configuration will not run on webpack 2+, because webpack-validator is deprecated, so I have removed it. I would recommend you to install npm install webpack-dev-server -g globally and use it as a server in your react development. This is how you can modify your configuration to use it (webpack.config.js):
const path = require("path");
const webpack = require('webpack');
const {getIfUtils, removeEmpty} = require('webpack-config-utils');
module.exports = env => {
const {ifProd, ifNotProd} = getIfUtils(env)
return {
entry: [
"webpack-dev-server/client?http://localhost:3003",
"webpack/hot/only-dev-server",
"react-hot-loader/patch"
],
context: __dirname,
output: {
path: path.join(__dirname, './build'),
filename: 'bundle.js',
publicPath: '/build/',
pathinfo: ifNotProd(),
},
devtool: ifProd('source-map', 'eval'),
devServer: {
contentBase: path.join(__dirname, "src"),
// 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: 3003
},
module: {
loaders: [
{test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader'},
{test: /\.css$/, loader: 'style-loader!css-loader'},
{test: /(\.eot|\.woff2|\.woff|\.ttf|\.svg)/, loader: 'file-loader'},
],
},
plugins: removeEmpty([
//...
// same as before
//...
])
};
};
package.json :
{
...
"dependencies": {},
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"react-hot-loader": "^3.1.1",
"webpack": "^3.8.1",
"webpack-config-utils": "^2.3.0",
"webpack-dev-server": "^2.9.4",
}
}
in the same folder where webpack.config.js is make one file webpack.development.js, that will just set enviorment:
var config = require('./webpack.config.js')
module.exports = config("development"); // can be "production" or "development"
Files structure:
root
build
bundle.js
src
index.html
index.js
package.json
webpack.config.js
webpack.development.js
At the end just run it:
webpack-dev-server --config webpack.development.js --progress -p --hot -w
--hot - will run server,
-w - watch files
My suggestion:
package.json scripts (install webpack (-g and –save-dev), nodemon (-g and –save-dev) and concurrently (–save-dev))
"scripts": {
"webpack-watch-client": "webpack -w",
"server": "nodemon server",
"dev": "concurrently --kill-others \"npm run webpack-watch-client\" \"npm run server\""
}
webpack.config.js example
'use strict'
const path = require('path');
const PATHS = {
app: path.join(__dirname, 'src'),
public: path.join(__dirname, 'public')
};
module.exports = {
entry: {
app: PATHS.app,
},
output: {
path: PATHS.public,
filename: 'js/bundle.js'
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['react', 'es2015']
}
}
]
},
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' }
]
},
{
test: /\.(woff|woff2|eot|ttf)$/,
use: [
{
loader: 'file-loader',
options: {
outputPath: 'assets/fonts/'
}
}
]
},
{
test: /\.(png|jpg|gif|svg)$/,
use: [
{
loader: 'file-loader',
options: {
outputPath: 'assets/img/'
}
}
]
}
]
},
plugins: [
// plugins
]
};
Node server start point is ./server.js
React client start point is ./src/index.js
Output path ./public contain index.html with lines:
<div id="root"></div>
<script type="text/javascript" src="/js/bundle.js" charset="utf-8"></script>
Output path for bundle.js is ./public/js
Output path for fonts is ./public/assets/fonts
Output path for images is ./public/assets/img
Start: npm run dev (listening port is defined in server.js)
etc.
I don't know if this would help, but i think that you want do the other way round:
Create your configuration un Webpack.config file (Webpack).
Your webpack file lauch the Node server (Express).
Your server return your font-end file (React).
You can learn some info about webpack in this post.
Try this. Save this code in webpackConfig.js
var webpack = require('webpack')
var config = require('./your_config')
var compiler = webpack(config)
compiler.run(function(err, stats){
console.log(err, stats)
})
run with "node webpackConfig.js"

WebPack and Express server not working together

I'm having a hard time finding resources that explain how to connect webpack to a express server app. I'm wanting to use webpack for babel to use es6 when writing react and use its hot-module and cheap-module-source-map. But, webpack runs it's own express server and that currently conflicts with my express app. I want my express app to dictate the port and routes but still get the benefits of using webpack.
Any ideas?
The express app looks something like this:
var express = require('express'),
Sequelize = require('sequelize'),
/*
set up sequelize ...
app.route ...
*/
app.listen(port), function () {
console.log('Express server listening on port ' + port
});
You don't need the webpack-dev-server to use Webpack for Babel to use ES2015 when writing React and use its hot-module and cheap-module-source-map.
Webpack configuration for React app in development env:
module.exports = {
entry: {
app: [
'react-hot-loader/patch',
'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000',
'app/index.js,
],
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
],
})
.babelrc looks like this:
{
"presets": ["react", "es2015", "stage-0"],
"env": {
"development": {
"plugins": ["react-hot-loader/babel"]
}
}
}
app/index.js:
import { AppContainer} from 'react-hot-loader'
...
<AppContainer>
<App />
</AppContainer>
...
if (module.hot) {
module.hot.accept('./routes', () => {
// Hot reloading
})
}
server/index.js:
import webpack from 'webpack'
import webpackDevMiddleware from 'webpack-dev-middleware'
import webpackHotMiddleware from 'webpack-hot-middleware'
import webpackConfig from './webpack.dev.config'
const compiler = webpack(webpackConfig)
app.use(webpackDevMiddleware(compiler, {
noInfo: true,
publicPath: webpackConfig.output.publicPath,
}))
app.use(webpackHotMiddleware(compiler, {
path: '/__webpack_hmr',
heartbeat: 10000,
}))
I am not sure if it's allowed to refer to my own repo here, but please check my Github repo here to see how I have integrated React, Express, Webpack, HMR and Babel.
What I ended up doing was I used 2 different configurations, 1 for packing the server stuff together using webpack, and 1 for packing all the browser stuff together and also run webpack dev server for hot reloading.
Server webpack config aka webpack.node.config.js now looks like this:
var webpack = require('webpack');
var path = require('path');
var fs = require('fs');
var nodeModules = {};
// note the path.resolve(__dirname, ...) part
// without it, eslint-import-resolver-webpack fails
// since eslint might be invoked with different cwd
fs.readdirSync(path.resolve(__dirname, 'node_modules'))
.filter(x => ['.bin'].indexOf(x) === -1)
.forEach(mod => { nodeModules[mod] = `commonjs ${mod}`; });
// es5 style alternative
// fs.readdirSync(path.resolve(__dirname, 'node_modules'))
// .filter(function(x) {
// return ['.bin'].indexOf(x) === -1;
// })
// .forEach(function(mod) {
// nodeModules[mod] = 'commonjs ' + mod;
// });
module.exports =
{
// The configuration for the server-side rendering
name: 'server',
target: 'node',
entry: './app/server/serverEntryPrototype.js',
output: {
path: './bin/',
publicPath: 'bin/',
filename: 'serverEntryPoint.js'
},
externals: nodeModules,
module: {
loaders: [
{ test: /\.js$/,
loaders: [
// 'imports?document=this',
// 'react-hot',
'babel-loader'
//,'jsx-loader'
]
},
{ test: /\.json$/, loader: 'json-loader' },
]
},
plugins: [
// new webpack.NormalModuleReplacementPlugin("^(react-bootstrap-modal)$", "^(react)$")
// new webpack.IgnorePlugin(new RegExp("^(react-bootstrap-modal)$"))
// new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
]
};
Browser webpack config aka webpack.browser.config.js now looks like this:
var webpack = require('webpack');
var path = require('path');
var buildPath = path.resolve(__dirname, 'assets');
var fs = require('fs');
var commonLoaders = [
{ test: /\.js$/,
loaders: [
'react-hot',
'babel-loader'
//,'jsx-loader'
]
}
];
module.exports =
{
// Makes sure errors in console map to the correct file
// and line number
name: 'browser',
devtool: 'eval',
entry: [
//'./bin/www.js',
'./app/index.js',
'webpack/hot/dev-server',
'webpack-dev-server/client?http://localhost:8081' // WebpackDevServer host and port
],
output: {
path: buildPath,
filename: '[name].js',
// Everything related to Webpack should go through a build path,
// localhost:3000/build. That makes proxying easier to handle
publicPath: 'http://localhost:8081/assets/'
},
extensions: [
'',
'.jsx', '.js',
'.json',
'.html',
'.css', '.styl', '.scss', '.sass'
],
module: {
loaders: [
// Compile es6 to js.
{
test: /app\/.*\.jsx?$/,
loaders: [
'react-hot',
'babel-loader'
]
},
///app\/.*\.json$/
{ test: /\.json$/, loader: 'json-loader' },
// Styles
{ test: /\.css$/, loader: 'style-loader!css-loader' },
{ test: /\.s(a|c)ss$/, loader: 'style!css?localIdentName=[path][name]---[local]---[hash:base64:5]!postcss!sass' },
// Fonts
{ test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'url-loader?limit=10000&minetype=application/font-woff' },
{ test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'file-loader' }
//{ test: /\.png$/, loader: 'url-loader?limit=100000' },
//{ test: /\.jpg$/, loader: 'file-loader' }
],
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
]
},
postcss: [
require('autoprefixer-core')
],
devtool: 'source-map'
}
;

webpack production config (react, es6)

I have webpack configuration for site development using ES6, react and react-router. It uses developer server with hot-reload and routes.
/config/webpack.dev:
var webpack = require('webpack');
var path = require('path');
var APP_DIR = path.join(__dirname, '..', 'app');
module.exports = {
debug: true,
devtool: 'eval',
entry: ['webpack-hot-middleware/client', './app/index.js'],
module: {
preLoaders: [{
test: /\.js?$/,
loaders: ["babel-loader", "eslint-loader"],
exclude: /node_modules/,
include: APP_DIR
}],
loaders: [
{test: /\.js?$/, loaders: ['react-hot', 'babel'], include: APP_DIR},
{
test: /\.scss$/, include: APP_DIR,
loader: 'style!css?modules&importLoaders=2&sourceMap&localIdentName=[local]___[hash:base64:5]!autoprefixer?browsers=last 2 version!sass?outputStyle=expanded&sourceMap'
},
{
test: /\.css$/, include: APP_DIR,
loader: "style!css!autoprefixer?browsers=last 2 version!"
},
{test: /\.(jpe?g|png|gif|svg)$/i, loaders: ['url?limit=8192', 'img']},
{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"}
]
},
output: {
filename: 'app.js',
path: path.join(__dirname, '..', 'build'),
publicPath: '/static/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
],
resolve: {
root: [path.resolve('../app')],
extensions: ['', '.jsx', '.js']
},
sassLoader: {
includePaths: [path.resolve(__dirname, "./app")]
}
};
I run build by npm start. Fragment of my package.json:
...
scripts": {
"build:webpack": "NODE_ENV=production webpack --config config/webpack.prod.js",
"clean": "rimraf build",
"start": "node dev_server.js"
}
...
dev_server.js:
var path = require('path');
var express = require('express');
var webpack = require('webpack');
var config = require('./config/webpack.dev');
var app = express();
var compiler = webpack(config);
var port = process.env.PORT || 3000;
app.use(require('webpack-dev-middleware')(compiler, {
noInfo: true,
publicPath: config.output.publicPath
}));
app.use(require('webpack-hot-middleware')(compiler));
app.use(express.static(path.join(__dirname, '..', 'static')));
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'index.html'));
});
app.listen(port, 'localhost', err => {
if (err) {
console.log(err);
return;
}
console.log(`Listening at http://localhost:${port}`);
});
I also have /config/webpack.prod:
var path = require('path');
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var CleanPlugin = require('clean-webpack-plugin');
var APP_DIR = path.join(__dirname, '..', 'app');
var projectRootPath = path.resolve(__dirname, '../');
var assetsPath = path.resolve(projectRootPath, './build');
module.exports = {
devtool: 'source-map',
context: path.resolve(__dirname, '..'),
entry: './app/index.js',
module: {
loaders: [
{
test: /\.js?$/,
loaders: ['babel'],
include: APP_DIR
},
{
test: /\.scss$/, include: APP_DIR,
loader: 'style!css?modules&importLoaders=2&sourceMap&localIdentName=[local]___[hash:base64:5]!autoprefixer?browsers=last 2 version!sass?outputStyle=expanded&sourceMap'
},
{
test: /\.css$/, include: APP_DIR,
loader: "style!css!autoprefixer?browsers=last 2 version!"
},
{test: /\.(jpe?g|png|gif|svg)$/i, loaders: ['url?limit=8192', 'img']},
{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"}]
},
output: {
path: assetsPath,
filename: 'app.js',
publicPath: '/build/'
},
plugins: [
new CleanPlugin([assetsPath], { root: projectRootPath }),
new ExtractTextPlugin('[name]-[chunkhash].css', {allChunks: true}),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.DedupePlugin(),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production')
}
}),
new webpack.optimize.UglifyJsPlugin({
compressor: {
warnings: false
}
})
],
progress: true,
resolve: {
root: [path.resolve('../app')],
extensions: ['', '.jsx', '.js']
},
sassLoader: {
includePaths: [path.resolve(__dirname, "./app")]
}
};
I run it by npm run build. It generate file in app directory. But when i open index.html in browser, page is empty. In firefox inspector i have comment: react-empty: 1
How can I use webpack to build my project to use it in browser without server?
I suggest using write-file-webpack-plugin to write bundled contents to disk and you should be able to open index.html in browser and start using the app without any server.
But remember that if you have used browserHistory from 'react-router' then it wouldn't work without configuring a server. You will have to replace it with hashHistory.
react-router documentation states
Hash history uses the hash (#) portion of the URL, creating routes
that look like example.com/#/some/path.
Hash history works without configuring your server, so if you're just
getting started, go ahead and use it. In general, though, production
web applications should use browserHistory for the cleaner URLs, and
for support for server-side rendering, which is impossible with
hashHistory.

Resources