I am building an app with react in the front end and nodejs on the backend . y react is packed by webpack and configure my server to run concurrently with the front end. For months, i have been building my app successfully, suddenly my build begins to fail throwing warnings like below followed by errors
WARNING in ./server/~/sequelize/lib/sequelize.js Critical
dependencies: 388:61-74 the request of a dependency is an expression
# ./server/~/sequelize/lib/sequelize.js 388:61-74
And errors like
ERROR in ./server/models/index.js Module not found: Error: Cannot
resolve module 'fs' in /PATH/static/server/models
My webpack used to be config like below
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: ['babel-polyfill', 'react-hot-loader/patch', path.normalize(__dirname + '/src/index')],
devtool: 'cheap-module-source-map',
devServer: {
hot: true
},
output: {
filename: 'bundle.js',
publicPath: '/',
path: path.join(__dirname, 'server')
},
module: {
loaders: [
{
loader: 'babel-loader',
test: /\.js$/,
exclude: /node_modules/
},
{
loader: 'style!css',
test: /\.css$/,
include: [path.resolve(__dirname, 'public', 'css')]
},
{
test: /\.json$/,
loader: "json-loader"
}
],
plugins: [
new webpack.NoErrorsPlugin(),
new webpack.DefinePlugin({
//'process.env.NODE_ENV': JSON.stringify('development')
}),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin()
],
}
};
ANd my server config below
var webpack = require('webpack');
var config = require('./webpack.config');
var path = require('path');
var express = require('express');
var app = express();
const http = require('http');
const port = process.env.PORT || 3000;
var compiler = webpack(config);
require('./server/config/express')(app, port, compiler, config);
const server = http.createServer(app);
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function (err, req, res, next) {
res.status(err.code || 500)
.json({
status: 'error',
message: err
});
});
}
app.use(function (err, req, res, next) {
res.status(err.status || 500)
.json({
status: 'error',
message: err.message
});
});
server.on('close', () => {
models.sequelize.close();
});
My server config above is based in server folder and i wasn't expecting my webpack to build that folder. My build has being working fine for months until 3 days when it suddenly stopped throwing the errors above. It occurs to me that it is building/packaging the server folder which i wasn't expecting.
I then update my babel-loader to
{
loader: 'babel-loader',
test: /\.js$/,
exclude: [/node_modules/, /server/]
}
yet to no avail. I am really confused on how i can best configure this. My development suddenly stopped. Pls any help would be appreciated.
It turns out a colleague mistakenly referenced/imported a file from the server folder hence the issue. The line
import { authenticateUser } from '../../../server/controllers/user';
in one of the components in the src folder caused that.
Related
I've tried almost every solution but I can't find any solution for this problem. I'm using express to render my ReactJS code, build with webpack. I can open pages without any issues until I'm being redirected from home page. But when I tried entering the URL on browser or refresh the page, I cannot see the page. Instead I see this error:
Cannot GET /path
I have also tried adding historyApiFallback: true to my webpack.config.js but no luck there.
Below are my scripts from package.json
{
...
"scripts": {
"build": "webpack --config webpack.config.js",
"dev": "webpack-dev-server --mode development --open",
"start": "npm run build && node server.js"
},
...
}
And this is my webpack.config.js:
const HtmlWebPackPlugin = require("html-webpack-plugin");
const path = require('path');
const htmlPlugin = new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html"
});
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.js',
publicPath: '/',
},
devServer: {
historyApiFallback: true,
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
},
]
},
plugins: [htmlPlugin],
resolve: {
extensions: ['*', '.js', '.jsx']
},
};
And the server.js file:
const path = require('path');
const express = require('express');
const PORT = process.env.PORT || 3000;
const app = express();
app.use(express.static(path.join(__dirname, 'dist')));
app.get('/', function(request, response) {
response.sendFile(__dirname + '/dist/index.html');
});
app.listen(PORT, error => (
error
? console.error(error)
: console.info(`Listening on port ${PORT}. Visit http://localhost:${PORT}/ in your browser.`)
));
Important NOTE
When I run server with npm run dev, there is no issues. I can enter URL manually and refresh the page.
But when I run server with npm run start, I am facing the issue I described above.
app.get('/', ... ); only sends back the index.html on the / path, you need to return it on every path
app.get('*', function(request, response) {
response.sendFile(__dirname + '/dist/index.html');
});
I have my React app compiling all fine in dev & prod scripts, however, now that I am deploying on DigitalOcean, I am running into a problem with process.env.port being undefined and therefore falling back to 3000 and not the expected port 80.
Package.json npm script:
"build": "webpack -p --config webpack.config.production.js &&
cross-env NODE_ENV=production node server/server.js"
Webpack.config.production.js script which includes the DefinePlugin() for process.env:
module.exports = {
entry: {
app: ["./src/scripts/index.js"]
},
output: {
filename: "[name]-bundle.js", path: __dirname, publicPath: "/"
},
devtool: "source-map",
module: {
rules: [
{
test: /\.(js)$/,
exclude: /node_modules/,
use: ["babel-loader"]
},
{
test: /\.(scss|css)$/,
use: [
{loader: "style-loader"}, {
loader: "css-loader"}, {
loader: "sass-loader"}, {
loader: "postcss-loader"}
}
]
},
{
test: /\.(jpg|png|svg)$/,
use: {
loader: "file-loader",
options: {
name: "[path][name].[ext]"
}
}
}
]
},
plugins: [
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.DefinePlugin({
"process.env": {
NODE_ENV: JSON.stringify("production")
}
}),
extractSass,
new UglifyJsPlugin({
sourceMap: true,
uglifyOptions: {
output: {
comments: false
}
}
}),
new HtmlWebpackPlugin({
template: "public/index.html",
favicon: "public/assets/img/favicon.ico"
}),
new ExtractTextPlugin({
filename: "styles/styles.css",
allChunks: true
})
]
};
my express server file:
const path = require("path");
const express = require("express");
const app = express();
const port = process.env.PORT || 3000;
let useFolder;
if (process.env.NODE_ENV !== "production") {
useFolder = "/public/";
const webpack = require("webpack");
const config = require("../webpack.config.development");
const compiler = webpack(config);
app.use(
require("webpack-dev-middleware")(compiler, {
noInfo: true,
publicPath: config.output.publicPath,
hot: true
})
);
app.use(
require("webpack-hot-middleware")(compiler, {
log: console.log,
path: "/__webpack_hmr",
heartbeat: 10 * 1000
})
);
} else {
useFolder = "/dist/";
}
app.use(express.static("dist"));
app.get("/", function(req, res) {
res.sendFile(path.join(__dirname, ".." + useFolder + "index.html"));
});
app.listen(port, function(err) {
if (err) {
return console.error(err);
}
console.log("Listening at port: ", port);
});
There are no errors, and when it runs on backup port 3000 all is good on the live server, but I am expecting port 80.
I have tried swapping where NODE_ENV=production gets set: removing from NPM script, and DefinePlugin() but no success either.
Webpack will by default bundle for web. This means it will replace all process.env. statements with what you have defined in the DefinePlugin. You never set PORT to anything, so it will be undefined.
You have two options, either define PORT in the DefinePlugin, or change the webpack target to node and remove the DefinePlugin. This will make webpack use the actual environment variables on runtime.
https://webpack.js.org/concepts/targets/
To create environment variable within the project create a .env file at the root of the project and add values in that file. You may have to re-run the deployment script you have to bundle them all again. We normally comment values related to other environments during the deployment, we have a script to do that.
#dev
PORT=6000
URL=Blahhh.dev.com
#prod
PORT=7000
URL=Blahhh.com
I just copy-pasted webpack-dev-server + express settings from webpack docs, but it doesn't work because the server can't find files to serve. What is wrong with this setup?
server.js
const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const app = express();
const config = require('../webpack.config.js');
const compiler = webpack(config);
app.use(webpackDevMiddleware(compiler, {
publicPath: config.output.publicPath
}));
/*app.use('/',express.static('public')) it works when used insted of webpack dev middleware */
// Serve the files on port 3000.
app.listen(3000, function () {
console.log('Example app listening on port 3000!\n');
});
webpack.config.js
const path = require('path');
const webpack = require('webpack');
const scssRules = {
test:/\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
};
const jsRules = {
test: /\.js$/,
use: [
{loader: 'babel-loader'}
]
};
module.exports = {
entry: './js/App.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'public'),
publicPath: '/'
},
module: {
rules: [
jsRules,
scssRules
]
},
devServer: {
contentBase: './public'
},
plugins:[
new webpack.HotModuleReplacementPlugin()
],
devtool: 'inline-source-map'
}
File structure:
What i see:
I also came across this problem.
Turns out webpack-dev-middleware doesn't output any files, instead serves from memory. While the express server is expecting physical files.
Here, this plugin might help: https://github.com/gajus/write-file-webpack-plugin
I am following a few tutorials, but mainly the one by Dan Abramov on setting up react hot loader but I am having some issues. I think I have a basic configuration working, however hot reloading of component does not seem to work, so obviously the hot loader set up is wrong :(
When I change a component, my browser console logs this:
The following modules couldn't be hot updated: (Full reload needed)
This is usually because the modules which have changed (and their parents) do not know how to hot reload themselves. See http://webpack.github.io/docs/hot-module-replacement-with-webpack.html for more details.
- ./app/components/Home/index.jsx
To start off, here is my file structure:
.
|++[app]
|----[actions]
|----[modules]
|----[reducers]
|----[store]
|----index.html
|----index.js
|--[config]
|----server.js
|----webpack.config.js
|--[node_modules]
|--package.json
Here's my webpack config:
var webpack = require('webpack');
var path = require('path');
var autoprefixer = require('autoprefixer');
var isProd = process.env.NODE_ENV === 'production';
module.exports = {
devtool: isProd ? null : 'source-map',
entry: [
'webpack-hot-middleware/client',
path.resolve('app/index.js')
],
output: {
path: path.resolve('dist'),
filename: 'bundle.js',
publicPath: '/static/'
},
resolve: {
root: path.resolve( 'app/'),
extensions: ['', '.js', '.jsx']
},
module: {
loaders: [
{
test: /\.jsx?$/,
loaders: [
'babel'
],
include: path.resolve('.'),
exclude: /node_modules/
},
{
test: /\.(png|jpg)$/,
loader: 'file-loader?name=img/[name].[ext]'
},
{
test: /\.scss$/,
loader: 'style!css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]!postcss!sass'
}
]
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin()
],
postcss: [
autoprefixer({ browsers: ['last 3 versions'] })
]
};
And my server.js
var webpack = require('webpack');
var webpackDevMiddleware = require('webpack-dev-middleware');
var webpackHotMiddleware = require('webpack-hot-middleware');
var config = require('./webpack.config');
var path = require('path');
var app = new (require('express'))();
var port = 3000;
var compiler = webpack(config);
app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath }));
app.use(webpackHotMiddleware(compiler));
app.get('/*', function(req, res) {
res.sendFile(path.resolve('app/index.html'));
});
app.listen(port, function(error) {
if (error) {
console.error(error);
} else {
console.info('started on localhost://%s.', port);
}
});
The react-hot loader is missing within your module.loaders array. More into this.
Next we need to tell Webpack to use React Hot Loader for the components. If you configured Webpack for React, you may already use babel-loader (ex 6to5-loader) or jsx-loader for JS(X) files. Find that line in webpack.config.js and put react-hot before other loader(s).
So you need to add the react-hot loader before your babel loader, like so:
{
test: /\.jsx?$/,
loader: 'react-hot',
exclude: /node_modules/
}
And also you need to install the react-hot-loader module if you haven't already.
npm i -D react-hot-loader
I am trying to run webpack from within nodejs. My directory structure looks like this:
build
|- dev.js
dist
|- bundle.js
src
|- layout
|- App.js
|- server
|- app.js
dev.js:
const webpack = require('webpack');
const path = require('path');
// returns a Compiler instance
const compiler = webpack(
{
context: path.resolve(__dirname, '../src'),
entry: [
'./server/app.js'
],
output: {
path: path.join(__dirname, '../dist'),
filename: 'bundle.js'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader?presets[]=es2015&presets[]=react'
}
]
}
}
);
compiler.run(function(err, stats) {
if(err) {
console.log('Err');
}
});
app.js:
import express from 'express';
import React from 'react';
import { renderToString } from 'react-dom/server';
import App from '../layout/App';
const app = express();
app.get('*', (req, res) => {
res.send(renderToString(<App />));
});
app.listen(3000, () => {
});
If I now run node build/dev.js it generates my bundle.js, but it does not find my entry module.
(function webpackMissingModule() { throw new Error("Cannot find module \"./server/app.js\""); }());
Even though I think this is how the entry point should be defined, I have tried many combinations, even the absolute path. But always the same result, it cannot find the entry module. What am I missing here?
It looks like something is going wrong with bundling the assets - since webpack looks in your node_modules to find its assets it, would be best if you could post your package.json alongside the other files.
You're using webpack programatically instead of the default webpack command, which normally gives a lot of debug output (along with information about the build-steps, errors, etc.) - I would suggest using that to debug it, and then switch to the programmatical approach when you know that everything is working.
It looks like you want to do server-side rendering with react. Some special configuration is needed for your webpack configuration then. This is already handled here: http://jlongster.com/Backend-Apps-with-Webpack--Part-I
Without having the package.json it is really hard to debug exactly what goes wrong here.
Assuming your package.json is correct, here's a dev.js file that would work with the above code:
const webpack = require('webpack');
const path = require('path');
const fs = require('fs');
var nodeModules = {};
fs.readdirSync('node_modules')
.filter(function(x) {
return ['.bin'].indexOf(x) === -1;
})
.forEach(function(mod) {
nodeModules[mod] = 'commonjs ' + mod;
});
// returns a Compiler instance
const compiler = webpack(
{
context: path.resolve(__dirname, "../src"),
target: 'node',
entry: [
'./server/app.js'
],
output: {
path: path.join(__dirname, '../dist'),
filename: 'bundle.js'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader?presets[]=es2015&presets[]=react'
}
]
},
externals: nodeModules
}
);
compiler.run(function(err, stats) {
console.log(err, stats);
});