Webpack-dev-server doesn't find files to serve - node.js

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

Related

Cannot GET /path using ReactJS, webpack, express

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');
});

Dynamic require inside a webpacked express server can not find module

I have a really small express application. Basically a poor man's server less function provider. However this is nothing I use in production and it works in an unpackaged mode. But after I webpack this application the dynamic require always fails with an Error: Cannot find module exception. But the module is there and the path is correct.
devserver.js:
const express = require('express')
const fs = require('fs')
const resourceMapper = fs.existsSync(__dirname + '/../webpack.config.js') ? require('../webpack.config') : null
const app = express()
// enable express json
app.use(express.json())
// add dynamic lambda functions
app.post('/api/:lambda', function(request, response) {
const resource = resourceMapper
? `${__dirname}/.${resourceMapper[1].entry[request.params.lambda.replace(/^common-/, "").replace(/\.js$/, "")]}`
: `${__dirname}/${request.params.lambda}`
const lambda = require(resource) // <--------- problematic require
const result = lambda.main(request.body)
response.status(200).json(result)
});
app.listen(3000)
webpack.conf.js:
module.exports = [
{
name: "development-server",
target: 'node',
externals: [(require('webpack-node-externals'))()],
node: {
__dirname: false,
__filename: false,
},
entry: {
devserver: "./devserver/server.js",
},
output: {
filename: "./server.js",
path: __dirname + '/build/node/'
}
},
{
name: "lambdas",
target: 'node',
externals: [(require('webpack-node-externals'))()],
entry: {
returns: "./lambdas/returns/src/main/index.js",
echo: "./lambdas/echo/src/main/echo.js"
},
output: {
library: "[name]",
libraryTarget: "commonjs2",
filename: "./common-[name].js",
path: __dirname + '/build/node/'
}
}
]
I have really tried lots of things and various modules and plugins. In the end they only way I got it working is using a very nasty eval trick.
const require2 = eval('require')
//[snip]
const lambda = resourceMapper
? require(`${__dirname}/.${resourceMapper[1].entry[request.params.lambda.replace(/^common-/, "").replace(/\.js$/, "")]}`)
: require2(`./${request.params.lambda}`)

Webpack production process.env.PORT=undefined on server compile (React app)

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

Uncaught ReferenceError: global is not defined setting up node/express server and webpack

I'm trying to set up a very simple script that fetch's data from an API and consumes it's data. I need to use CORS, so I set up a node/express server and pointed it to my Webpack bundle. The error I am getting is global is not defined. From googling this I've seen people fix their problems by disabling react/redux tools which seemed to point at hot reloading. Problem is, I'm not using hot reloading.
After seeing that I looked into what I am using global which pointed at my fetch expression. However, removing all my fetch code didn't solve anything
My server looks like this
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const app = express();
const cors = require('cors');
const port = process.env.PORT || 3000;
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(cors());
app.use(express.static(path.join(__dirname, '../dist')));
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, '../index.html'));
});
app.listen(port, function(){
console.log('server running on http://127.0.0.1:' + port + '/');
});
and my webpack config looks like this
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: ['babel-polyfill', './scripts/app.js'],
target: "node",
output: { path: __dirname, filename: './dist/bundle.js' },
devtool: 'source-map',
module: {
loaders: [
{
test: /.js?$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015'],
"plugins": ["transform-object-rest-spread"]
}
}
]
}
};
All i can think of now is that I didn't set up my express server correctly or I'm missing something in my webpack config.
Alright, The issue was being caused by placing babel-polyfill in my entry point in my webpack.config. As I already had a preset for ES2015 I didn't need the polyfill.
I am unsure as to why I had placed the babel-polyfill in my entry.

Having some trouble setting up my webpack config

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

Resources