Webpack bundled express app fails to lookup view - node.js

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

Related

Why express.js can not find static files?

I created simple express.js server
Server config:
const app = express();
const config = require('./webpack.config.js');
const compiler = webpack(config);
const SERVER_PORT = 3000;
if (process.env.NODE_ENV === "development") {
app.use(
webpackDevMiddleware(compiler, {
publicPath: config.output.publicPath,
})
);
app.use(webpackHotMiddleware(compiler));
}
app.use(express.static("build"));
app.get("/", (req, res) => {
res.sendFile(__dirname + '/build/index.html', { root: __dirname })
});
app.listen(SERVER_PORT, (error) => {
if (error) {
console.error(error)
} else {
console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", SERVER_PORT, SERVER_PORT)
}
});
I build project with webpack. here is webpack config:
const BUILD_DIR = path.resolve(__dirname, './build');
const ASSETS_PATH = path.resolve(__dirname, './src/js');
const STATIC_PATH = path.resolve(__dirname, './public')
var webpack_config = {
mode: ( process.env.NODE_ENV === "production" ) ? "production" : "development",
context: __dirname,
entry: {
main: [
"react",
"react-dom",
"react-router"
],
react_app: [
path.join(ASSETS_PATH, "/index.tsx"),
"webpack-hot-middleware/client?path=/__webpack_hmr&reload=true"
]
},
output: {
path: BUILD_DIR,
filename: 'js/[name].min.js',
publicPath: '/build',
hotUpdateChunkFilename: '.hot/hot-update.js',
hotUpdateMainFilename: '.hot/hot-update.json',
},
resolve: {
extensions: [' ', '.web.js', '.ts', '.tsx', '.js', '.jsx', 'css'],
},
devtool: ("production" === process.env.NODE_ENV) ? "source-map" : "eval-source-map",
module: {
rules: [
{
test: /\.(jsx|js)$/,
use: ['babel-loader?compact=true&comments=true&minified=true', 'eslint-loader'],
exclude: /node_modules/
},
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: '/node_modules/'
},
{
test: /\.(ttf|woff|woff2)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: {
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: '/css/fonts/'
}
}
},
{
test: /\.(eot|svg|png|jpg|gif|ico)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: {
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: '/css/media/'
}
}
},
{
test: /\.jpe?g$|\.ico$|\.gif$|\.png$/,
exclude: /node_modules/,
use: {
loader: 'file-loader',
options: {
limit: 1024 * 10,
name: '[name].[ext]',
outputPath: 'images/'
}
}
},
{
test: /\.json$/,
loader: "json-loader"
},
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
}
}
, 'css-loader'],
},
]
},
plugins: [
new webpack.DefinePlugin({
"process.env": {
NODE_ENV: JSON.stringify(process.env.NODE_ENV)
}
}),
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
title: ' Appointment-APP | Stefanini EMEA ',
template: './public/index.html',
filename: path.join(BUILD_DIR, '/index.html'),
chunks: ['main', 'react_app']
}),
new CopyWebpackPlugin({
patterns: [
{
from: path.join(STATIC_PATH, '/images'),
to: path.join(BUILD_DIR, '/images'),
toType: 'dir'
},
]
}),
new MiniCssExtractPlugin({
filename: 'css/[name].css',
chunkFilename: '[id].css',
}),
],
};
Here I have 2 mods- production and delete. In delete mode it works nice, but when I launch server and try to enter http://localhost:3000/ I get errors like:
Refused to apply style from 'http://localhost:3000/build/css/react_app.css' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.
localhost/:9 GET http://localhost:3000/build/js/main.min.js net::ERR_ABORTED 404 (Not Found)
So, I specified static folder path - app.use(express.static("build"));, but no result. It seems, that express cannot find files in "buid" folder
You have to code like this
app.use('/', express.static(path.join(__dirname, 'build')))
then check.
may be this will be useful for somebody. to solve this issue I used express documentation and Jay Suchak variant. Code
app.use('/build', express.static(path.join(__dirname, 'build')));
worked for me

asset_url_for() returns None in flask cookie cutter (flask-webpack)

Im new to webpack. Im using flask-cookie-cutter which in turn uses Flask-Webpack
Im having issues in that App wont find my images in development.
Images are in assets/img folder
Ive tried using {{ asset_url_for('img/img_name.png') }} and various variations of it - and it just returns none.
Ive tried the usual flask way of {{ url_for('static', filename='img/img_name.png') }}
But I cant seem to access them.
const path = require('path');
const webpack = require('webpack');
/*
* Webpack Plugins
*/
const ManifestRevisionPlugin = require('manifest-revision-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// take debug mode from the environment
const debug = (process.env.NODE_ENV !== 'production');
// Development asset host (webpack dev server)
const publicHost = debug ? 'http://0.0.0.0:2992' : '';
const rootAssetPath = path.join(__dirname, 'assets');
module.exports = {
// configuration
context: __dirname,
entry: {
main_js: './assets/js/main',
main_css: [
path.join(__dirname, 'node_modules', 'materialize-css', 'dist', 'css', 'materialize.css'),
path.join(__dirname, 'assets', 'css', 'style.css'),
],
},
output: {
path: path.join(__dirname, 'dsi_website', 'static', 'build'),
publicPath: `${publicHost}/static/build/`,
filename: '[name].[hash].js',
chunkFilename: '[id].[hash].js',
},
resolve: {
extensions: ['.js', '.jsx', '.css'],
},
devtool: 'source-map',
devServer: {
headers: { 'Access-Control-Allow-Origin': '*' },
},
module: {
rules: [
{
test: /\.less$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: debug,
},
},
'css-loader!less-loader',
],
},
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: debug,
},
},
'css-loader',
],
},
{
test: /\.html$/,
loader: 'raw-loader'
},
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/font-woff'
}
},
{
test: /\.(ttf|eot|svg|png|jpe?g|gif|ico)(\?.*)?$/i,
loader: `file-loader?context=${rootAssetPath}&name=[path][name].[hash].[ext]`
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['env'],
cacheDirectory: true
}
},
],
},
plugins: [
new MiniCssExtractPlugin({ filename: '[name].[hash].css', }),
new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }),
new ManifestRevisionPlugin(path.join(__dirname, 'dsi_website', 'webpack', 'manifest.json'), {
rootAssetPath,
ignorePaths: ['/js', '/css'],
}),
].concat(debug ? [] : [
// production webpack plugins go here
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production'),
}
}),
]),
};
I was the same problem with flask-cookie-cutter and solve it by update/upgrade npm and add extensionsRegex: /\.(jpe?g|png|gif|svg)$/i at down file: webpack.config.js like this:
ManifestRevisionPlugin(path.join(__dirname, '<your app>', 'webpack', 'manifest.json'), {
rootAssetPath,
ignorePaths: ['/js', '/css'],
extensionsRegex: /\.(jpe?g|png|gif|svg)$/i
}),
source solution. Proper call to show image in temaplate:
{{ asset_url_for('img/img_name.png') }}
after that i check startup screen and i see that all my images load properly
[WEBPACK] _/assets/img/image_name.20aed528d50316c91ffedb5ba47b8c74.jpg 18.9 KiB [emitted]

Webpack 2 - Problems parsing node_module

I'm unit testing with mocha-webpack v1.0.1, node v6.10. However, I'm getting an error from one of our node modules, where webpack couldn't parse a #. This is an internal library that we use that runs fine in another development environment. So, I'm confused why this is happening since you would think that a library in your node_module would be sort of self-sustaining and would know how to parse itself (and is validated as working in another environment).
Error in ./~/abc-components/src/abc-theme/index.scss
Module parse failed: /path/to/app/node_modules/abc-components/src/abc-theme/index.scss Unexpected character '#' (1:0)
You may need an appropriate loader to handle this file type.
| #charset "UTF-8";
| #import "abc-variables";
| #import "alert";
I believe # is an alias we use for resolving the module path in that library. I've modeled my setup after this tutorial.
From package.json:
"unit": "BABEL_ENV=test mocha-webpack --webpack-config build/webpack.test.conf.js --require test/unit/.setup src/**/*.spec.js --recursive --watch"
From build/webpack.test.conf.js config, including some comments of things I've tried:
var path = require('path')
var webpack = require('webpack')
var utils = require('./utils')
var config = require('../config')
// var nodeExternals = require('webpack-node-externals');
function resolve(dir) {
return path.join(__dirname, '..', dir)
}
module.exports = {
entry: {
app: './src/main.js'
},
resolve: {
modules: [path.resolve('./src'), "node_modules"],
extensions: ['.js', '.vue', '.json', '.ts'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'#': resolve('src')
}
},
// externals: [nodeExternals()],
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
},
// plugins: [
// new webpack.optimize.CommonsChunkPlugin({
// name: "vendor",
// filename: "vendor.js",
// minChunks: function (module) {
// // This prevents stylesheet resources with the .css or .scss extension
// // from being moved from their original chunk to the vendor chunk
// if(module.resource && (/^.*\.(css|scss)$/).test(module.resource)) {
// return false;
// }
// return module.context && module.context.indexOf("node_modules") !== -1;
// }
// }),
// new webpack.DefinePlugin({
// 'process.env': require('../config/test.env')
// })
// ],
module: {
loaders: [
{
test: /\.(js|vue)$/,
// loader: 'eslint-loader',
// enforce: 'pre',
include: [resolve('src'), resolve('test'), resolve('node_modules')],
/* options: {
formatter: require('eslint-friendly-formatter')
} */
},
{
test: /\.pug$/,
loader: 'pug-loader'
},
{
test: /\.vue$/,
loader: 'vue-loader'
// options: vueLoaderConfig
},
{
test: /\.ts$/,
loader: "awesome-typescript-loader",
include: [resolve('src'), resolve('test')]
},
{
test: /\.js$/,
loader: 'babel-loader',
query: {
presets: ['es2015']
},
include: [resolve('src'), resolve('test')]
// exclude: /node_modules/
},
{
test: /\.(mp3|wav)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('audio/[name].[hash:7].[ext]')
}
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
]
},
resolveLoader: {
alias: {
// necessary to to make lang="scss" work in test when using vue-loader's ?inject option
// see discussion at https://github.com/vuejs/vue-loader/issues/724
'scss-loader': 'sass-loader'
}
}
}
Include following config in loader.
module: {
loaders: [
{
test: /\.(scss|sass)$/i,
include: [
path.resolve(__dirname, 'node_modules'),
path.resolve(__dirname, 'path/to/imported/file/dir'), <== This solved the issue
],
loaders: ["css", "sass"]
},
]
},

React + Webpack Dev Server: page is NOT interactive when visiting http://localhost:8080/webpack-dev-server/

When I visit http://localhost:8080, everything works as expected including hot reloading.
However, when I visit http://localhost:8080/webpack-dev-server/, nothing seems to work; can't type into the input components, can't scroll, etc.
It's almost like the page is frozen. This just started happening after a fresh npm install. It wasn't a problem previously.
Is anyone else experiencing this?
Here's my webpack.config.js:
const webpack = require('webpack');
const path = require('path');
const PATHS = {
app: './src/index.js',
html: './src/index.html',
dist: path.join(__dirname, 'dist')
};
module.exports = {
entry: {
javascript: PATHS.app,
html: PATHS.html
},
output: {
path: PATHS.dist,
publicPath: '/',
filename: 'bundle.js'
},
devServer: {
historyApiFallback: true,
contentBase: PATHS.dist
},
eslint: {
emitWarning: true
},
module: {
preLoaders: [
{
test: /\.(js|jsx)$/,
loaders: ["eslint-loader"],
exclude: /node_modules/
}
],
loaders: [
{
test: /\.html$/,
loader: "file?name=[name].[ext]"
},
{
test: /\.(js|jsx)/,
exclude: /node_modules/,
loaders: ["react-hot", "babel-loader"]
}
]
},
resolve: {
extensions: ['', '.js', '.jsx']
}
};
Here's my file layout:
-dist
-node_modules
-src
- components
--index.js
--index.html
--webpack.config.js
try changing your public path like below
module.exports = {
entry: {
javascript: PATHS.app,
html: PATHS.html
'webpack/hot/dev-server', // For hot style updates
// The script refreshing the browser on none hot updates
'webpack-dev-server/client?http://localhost:8080',
},
output: {
path: PATHS.dist,
publicPath: '/webpack-dev-server/',
filename: 'bundle.js'
},

babel having trouble with import statement

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.

Resources