I have a project I'm doing with node in ES6 which was using babel-node to run. Now I'm trying to implement babel in a more production manner and have tried two attempts.
Webpack babel-loader with following configuration:
module.exports = {
entry: './src/cloud/main.js',
devtool: 'source-map',
output: {
path: './src/static/build',
filename: 'bundle.js'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loaders: [
'babel-loader?presets[]=es2015',
],
},
{
test: /\.css$/,
loaders: [
'style-loader',
'css-loader',
],
},
{
test: /\.html$/,
loaders: [
'raw-loader',
],
},
],
},
}
It started complaining about the import statement in main.js and to silence it I used ?presets[]=es2015 which I found in a similar question. Then the problem arrived in which it filtered to the import statements that went to node_modules with the following message:
ERROR in ./~/socket.io/lib/index.js
Module not found: Error: Cannot resolve module 'fs' in
My other approach was with the register hook like this:
require('babel-core/register')({
ignore: /node_modules/,
});
require('./main.js');
but it threw this message:
import express from 'express';
^^^^^^
SyntaxError: Unexpected reserved word
//main.js - simplified
import express from 'express'
const app = express()
const server = app.listen(port, () => {
console.log(`Listening at http://${server.address().address === '::' ? 'localhost' : server.address().address}:${server.address().port}`)
})
I don't think you need to exclude the node_modules in your loader config. However, you might want to let webpack know what to resolve. Try adding something like this:
resolve: {
root: path.join(__dirname),
fallback: path.join(__dirname, 'node_modules'),
modulesDirectories: ['node_modules'],
extensions: ['', '.json', '.js', '.jsx', '.scss', '.png', '.jpg', '.jpeg', '.gif']
},
The modulesDirectories key should keep webpack from running down every single require / import in your working directory.
Also, adding target to the top of your config should resolve issues with builtins like fs
target: 'node'
Ok I figured it out thanks to other answers and 4m1r' answer. I post the example code.
var path = require('path');
var fs = require('fs');
var nodeModules = {};
fs.readdirSync('node_modules')
.filter(function (x) {
return ['.bin'].indexOf(x) === -1;
})
.forEach(function (mod) {
nodeModules[mod] = 'commonjs ' + mod;
});
module.exports = {
name: 'server',
target: 'node',
context: path.join(__dirname, 'src', 'cloud'),
entry: {
server: './main.js'
},
output: {
path: path.join(__dirname),
filename: '[name].js'
},
externals: nodeModules,
module: {
loaders: [
{test: /\.js$/, exclude: /node_modules/, loaders: ['babel-loader?presets[]=es2015']}
]
},
resolve: {
root: path.join(__dirname),
fallback: path.join(__dirname, 'node_modules'),
modulesDirectories: ['node_modules'],
}
};
What was really important too was the externals key which prevented it fro leaking to the node_modules through requires and specifying for some reason ?presets[]=2015 in the babel-loader. I'm accepting 4m1r because it was what finally fixed the code.
Related
I'm struggling with webpack setup for my ssr react server. I've read several posts here on stackoverflow, other articles and nothing works. Issue is connected with webpack-node-externals package. I've tried several configurations:
without nodeExternals: my app throws an error "process.hrtime" is not a function
with nodeExternals: my bundle is missing dependencies listed in mypackage.json (compression, etc.). This is because it leaves require('moduleName') everyywhere, obvious
with nodeExternals and with options.modulesFromFile argument set to
modulesFromFile: {
fileName: path.resolve(__dirname),
includeInBundle: ['dependencies']
}
I ended up here with error from user-agent module (not listed in my deps) "Cannot find module request". When I installed request manually, there where other errors I don't remember now.
Finally I don't know what I'm doing wrong. Here sample of my webpack config file:
const path = require('path');
const {
CleanWebpackPlugin
} = require('clean-webpack-plugin');
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
const nodeExternals = require('webpack-node-externals');
const {
BundleAnalyzerPlugin
} = require('webpack-bundle-analyzer');
const IS_PRODUCTION = process.env.MODE === 'production';
const config = {
entry: path.resolve(__dirname, 'src/server/index.ts'),
mode: IS_PRODUCTION ? 'production' : 'development',
output: {
path: path.resolve(__dirname, 'dist/server'),
publicPath: IS_PRODUCTION ? 'dist/' : undefined,
filename: 'index.js',
},
externals: [nodeExternals()],
resolve: {
extensions: ['.js', '.ts', '.tsx', '.json'],
fallback: {
fs: false,
yamlparser: false,
tls: false,
net: false,
},
},
target: 'node',
module: {
rules: [{
test: /\.((t|j)s(x?))$/u,
exclude: /node_modules/,
use: {
loader: 'swc-loader',
},
},
{
test: /\.(ts|tsx)$/u,
exclude: /node_modules/,
loader: 'ts-loader',
options: {
configFile: path.resolve(__dirname, 'tsconfig.webpack.json'),
},
},
{
test: /\.(png|jpg|jpeg|ico)$/u,
exclude: /node_modules/,
loader: 'file-loader',
},
],
},
plugins: [new NodePolyfillPlugin(), new CleanWebpackPlugin()],
};
if (IS_PRODUCTION) {
config.optimization = {
minimize: true,
};
}
if (process.env.BUNDLE_ANALYZER === 'true') {
config.plugins.push(
new BundleAnalyzerPlugin({
analyzerMode: 'static',
reportFilename: 'bundle-report-server.html',
})
);
}
module.exports = config;
I've already managed to fix it on myself.
The problem was in node polyfill plugin which was not necessary in my webpack config and it was causing errors like process.hrtime is not a function
Goal. Configuring app, which has: React, Webpack and MongoDB.
So, I've already setup Webpack for React and tried import Mongoose. The problem: React client-side and Mongoose - server-side, and because of that Webpack must have configurations for both. Using this answer: https://stackoverflow.com/a/37391247/7479176 I tried to configure Webpack. After that, I tried import Mongoose in my server.jsx file, but it didn't work.
Question. How to configure Webpack, so I can work with MongoDB?
Edited. I figured out how to rid of warnings (see Warnings):
output: {
filename: 'bundle.node.js',
libraryTarget: 'commonjs',
path: path.resolve(__dirname, 'dist')
},
externals: [
/^(?!\.|\/).+/i
],
But, when I added code into server.jsx (see server.jsx), it didn't log message in console.
Webpack configurations:
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')
module.exports = [
{
entry: {
index: './src/app/app.jsx'
},
devtool: 'inline-source-map',
devServer: {
port: 3000,
host: 'localhost',
historyApiFallback: true,
noInfo: false,
stats: 'minimal',
hot: true, // Tell the dev-server we're using HMR
contentBase: path.resolve(__dirname, './dist'),
publicPath: '/'
},
plugins: [
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(), // Enable HMR
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
inject: 'body'
})
],
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader']
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
},
{
entry: {
index: './src/server/server.jsx'
},
target: 'node',
output: {
filename: 'bundle.node.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader']
}
]
}
}
]
server.jsx:
import mongoose from 'mongoose'
import '../config/database.js'
mongoose.Promise = global.Promise
mongoose.connect(config.database)
// check connection
mongoose.connection.once('open', () => console.log('Connected to MongoDB'))
// check for db errors
mongoose.connection.on('error', err => console.log(err))
Warnings:
WARNING in ./node_modules/mongoose/lib/drivers/index.js
10:13-49 Critical dependency: the request of a dependency is an expression
WARNING in ./node_modules/require_optional/index.js
82:18-42 Critical dependency: the request of a dependency is an expression
WARNING in ./node_modules/require_optional/index.js
90:20-44 Critical dependency: the request of a dependency is an expression
WARNING in ./node_modules/require_optional/index.js
97:35-67 Critical dependency: the request of a dependency is an expression
WARNING in ./node_modules/es6-promise/dist/es6-promise.js
Module not found: Error: Can't resolve 'vertx' in 'D:\Projects\JavaScriptProjects\pizzaday\node_modules\es6-promise\dist'
# ./node_modules/es6-promise/dist/es6-promise.js 131:20-30
# ./node_modules/mongodb/lib/mongo_client.js
# ./node_modules/mongodb/index.js
# ./node_modules/mongoose/lib/index.js
# ./node_modules/mongoose/index.js
# ./src/server/server.jsx
Solution. I used webpack-dev-middleware and webpack-hot-middleware with basic Express server. I tried launch MongoDB with React on webpack-dev-server and thats was main problem.
I made new server.js within separate folder following advice from Neil Lunn and setup basic Express server with middleware and split Webpack config into 3 separate files common, dev and prod.
This fragment of code in server.js helped me to run server and client together with Webpack which bonded everything together:
app.use(webpackDevMiddleware(compiler, {
publicPath: config.output.publicPath
}))
app.use(webpackHotMiddleware(compiler))
New Webpack config (webpack.common.js):
const webpack = require('webpack')
const path = require('path')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: {
app: [
'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=2000&reload=true',
'./src/index.jsx'
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
template: './index.html',
filename: 'index.html',
inject: 'body'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/'
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader']
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
}
I was reading all this week about this issue, but any of the solutions that are in the web doesn't work with the project that I am developing. I am working in a webapp using react and its related technologies. To make the compile process I am using the new version of webpack (v2.3.2). I have my server webpack configuration separate from my client webpack configuration. All were working good until I add socket.io in order to make some real-time components. Applying all the solutions that are in the web I am still get the following warning when I run my bundle script:
WARNING in ./~/express/lib/view.js
80:29-41 Critical dependency: the request of a dependency is an expression
WARNING in ./~/socket.io/lib/index.js
109:11-32 Critical dependency: the request of a dependency is an expression
WARNING in ./~/engine.io/lib/server.js
115:15-37 Critical dependency: the request of a dependency is an expression
And when I try to start my project, I get the following error:
return /*require.resolve*/(!(function webpackMissingModule() { var e = new Error("Cannot find module \".\""); e.code = 'MODULE_NOT_FOUND'; throw e; }()));
^
Error: Cannot find module "."
at webpackMissingModule (/Users/macpro/Documents/lisa_project/pos_lisa/built/server/index.js:357017:76)
at Server.serveClient (/Users/macpro/Documents/lisa_project/pos_lisa/built/server/index.js:357020:25)
at new Server (/Users/macpro/Documents/lisa_project/pos_lisa/built/server/index.js:356959:8)
at Server (/Users/macpro/Documents/lisa_project/pos_lisa/built/server/index.js:356951:41)
at Object.<anonymous> (/Users/macpro/Documents/lisa_project/pos_lisa/built/server/index.js:72569:33)
at __webpack_require__ (/Users/macpro/Documents/lisa_project/pos_lisa/built/server/index.js:20:30)
at Object.<anonymous> (/Users/macpro/Documents/lisa_project/pos_lisa/built/server/index.js:344445:18)
at __webpack_require__ (/Users/macpro/Documents/lisa_project/pos_lisa/built/server/index.js:20:30)
at /Users/macpro/Documents/lisa_project/pos_lisa/built/server/index.js:66:18
at Object.<anonymous> (/Users/macpro/Documents/lisa_project/pos_lisa/built/server/index.js:69:10)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
Here is my webpack.client.config.js
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: ['babel-polyfill', path.join(__dirname, '../source/client.jsx')],
output: {
filename: 'app.js',
path: path.join(__dirname, '../built/statics'),
},
module: {
rules: [
{
test: /\.json$/,
use: 'json-loader',
},
{
test: /\.jsx?$/,
exclude: /(node_modules)/,
loader: 'babel-loader',
query: {
presets: ['es2016', 'es2017', 'react'],
plugins: ['transform-es2015-modules-commonjs'],
},
},
{
test: /\.css$/,
exclude: /(node_modules)/,
loader: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'css-loader?modules',
}),
},
{
test: /\.inline.svg$/,
loader: 'babel-loader!react-svg-loader?' + JSON.stringify({
svgo: {
// svgo options
plugins: [{removeTitle: false}],
floatPrecision: 2
}
}),
},
{
test: /\.jpe?g$|\.gif$|\.png$|^(?!.*\.inline\.svg$).*\.svg$/,
loader: 'url-loader?limit=400000'
},
],
noParse: [ path.join(__dirname, '../node_modules/ws') ],
},
externals: [ path.join(__dirname, '../node_modules/ws'), path.join(__dirname, '../node_modules/socket.io') ],
target: 'web',
resolve: {
extensions: ['.js', '.jsx', '.css', '.json'],
},
plugins: [
new webpack.DefinePlugin({
'process.env.BROWSER': true,
}),
new ExtractTextPlugin({
filename: '../statics/styles.css',
ignoreOrder: true,
}),
],
watch: true,
};
Here is my webpack.server.config.js
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: ['babel-polyfill', path.join(__dirname, '../source/server.jsx')],
output: {
filename: 'index.js',
path: path.join(__dirname, '../built/server'),
},
module: {
rules: [
{
test: /\.json$/,
use: 'json-loader',
},
{
test: /\.jsx?$/,
exclude: /(node_modules)/,
loader: 'babel-loader',
query: {
presets: ['latest-minimal', 'react'],
},
},
{
test: /\.css$/,
exclude: /(node_modules)/,
loader: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'css-loader?modules',
}),
},
{
test: /\.inline.svg$/,
loaders: [ 'babel-loader',
{
loader: 'react-svg-loader',
query: {
svgo: {
plugins: [{removeTitle: false}],
floatPrecision: 2
}
}
}
]
},
{
test: /\.jpe?g$|\.gif$|\.png$|^(?!.*\.inline\.svg$).*\.svg$/,
loader: 'url-loader?limit=400000'
},
],
noParse: [ path.join(__dirname, '../node_modules/ws') ],
},
externals: [ path.join(__dirname, '../node_modules/ws'), path.join(__dirname, '../node_modules/socket.io') ],
target: 'node',
resolve: {
extensions: ['.js', '.jsx', '.css', '.json'],
},
plugins: [
new webpack.DefinePlugin({
'process.env.BROWSER': false,
}),
new ExtractTextPlugin({
filename: '../statics/styles.css',
ignoreOrder: true,
}),
],
watch: true,
};
And my server.jsx (the important parts)
import http from 'http';
import express from 'express';
import socketio from 'socket.io';
const lisaApp = express();
const server = http.createServer(lisaApp);
const io = socketio(server);
In advance, thanks for your help and answers
Well, I found the solution, maybe it helps someone else. In the server side configuration with webpack we have to read the list of directories inside node_modules and give to externals, keeping the "require" of our modules, so we have to add the following to our server side config. (Only the server side, the client side webpack works fine):
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;
});
This code must be between const webpack and module.exports. And just after "module" object, add the following line:
externals: nodeModules,
Hope this helps to somebody.
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'
}
;
I run npm run start and server is running fine. When I attempt to view client at localhost, server returns error:
GET / 500 62.700 ms - 2028
Error: Failed to lookup view "error" in views directory "/views"
The application runs fine when just using source files. This error occurs when running application from webpack bundle.
What are the differences between source and bundled files that would make this error occur?
npm:3.8.2
node: 4.2.6
express: 4.13.1
webpack: 1.12.13
babel-loader: 6.2.4
webpack.config.js
var webpack = require('webpack');
var path = require('path');
var nodeModules = {};
fs.readdirSync('node_modules')
.filter(function(x) {
return ['.bin'].indexOf(x) === -1;
})
.forEach(function(mod) {
nodeModules[mod] = 'commonjs ' + mod;
});
module.exports = [
{
entry: {
'app_bundle': './server.js'
},
target: 'node',
query: {
cacheDirectory: true,
presets: ['es2015']
},
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
exclude: /node_modules/
}
]
},
resolve: {
extensions: ['', '.js']
},
output: {
path: './',
filename: '[name].js'
},
externals: nodeModules
},
{
entry: [
'./src/index.jsx'
],
target: 'web',
query: {
cacheDirectory: true,
presets: ['es2015']
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel'
},
{
test: /\.css$/,
loader: 'style!css!autoprefixer'
},
{ test: /\.(woff|woff2)$/, loader: "url-loader?limit=10000&mimetype=application/font-woff" },
{ test: /\.ttf$/, loader: "file-loader" },
{ test: /\.eot$/, loader: "file-loader" },
{ test: /\.svg$/, loader: "file-loader" }
]
},
resolve: {
alias: {
'react': path.join(__dirname, 'node_modules', 'react')
},
extensions: ['', '.js', '.jsx']
},
output: {
path: __dirname + '/public',
publicPath: '/',
filename: 'webpack_bundle.js'
}
}
];
The error trace tells me that the error is being handled by the production error handler in my app.js file:
// production error handler
app.use(function(err, req, res, next) {
console.log(err);
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
I console.log the error with the following output:
{ [Error: Failed to lookup view "error" in views directory "/views"]
view:
View {
defaultEngine: 'ejs',
ext: '.ejs',
name: 'error',
root: '/views',
engine: [Function],
path: undefined } }
View engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
I'm not sure how to start debugging...
I believe the answer lies in how webpack handles the special __dirname global variable. Webpack's default behavior is to replace __dirname with the "mock" value /. This can be seen in the error you get from express where it's looking for a file at the root of /views, not ./views.
The solution is to add the following section to your webpack configuration:
node: {
__dirname: true
}
Here's the docs which explain this behavior:
https://webpack.github.io/docs/configuration.html#node