Images are not loading in browser with react, webpack and express - reactjs

I am working on a site build in react. It was working fine until I have implemented express. After implementation of express, I am not able to load some resources, especially images in the browser. The image path is coming correct but images are not showing in the browser.
webpack.config.js is:
var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
devtool: 'eval-source-map',
entry: [
'webpack-hot-middleware/client?reload=true',
path.join(__dirname, 'app/index.js')
],
output: {
path: path.join(__dirname, '/dist/'),
filename: '[name].js',
publicPath: '/'
},
plugins: [
new ExtractTextPlugin('/bundle.css', { allChunks: true }),
new HtmlWebpackPlugin({
template: 'app/index.html',
inject: 'body',
filename: 'index.html'
}),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
],
resolve: {
extensions: ['', '.scss', '.css', '.js', '.json'],
modulesDirectories: [
'node_modules',
path.resolve(__dirname, './node_modules')
]
},
module: {
loaders: [{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel',
query: {
"presets": ["react", "es2015", "stage-0", "react-hmre"]
}
}, {
test: /\.json?$/,
loader: 'json'
}, {
test: /\.scss$/,
loader: ExtractTextPlugin.extract('style', 'css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss!sass')
}, {
test: /\.css$/,
loader: 'style-loader!css-loader'
},{
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2)$/,
loader: "url-loader?limit=10000"
},{
test: /\.less$/, loader: "style-loader!css-loader!less-loader"
},{
test: /\.(ttf|eot|svg|woff|woff2)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: "file-loader"
}]
}
};
server.js file content is as follows:
const path = require("path");
const express = require("express");
const webpack = require("webpack");
const webpackDevMiddleware = require("webpack-dev-middleware");
const webpackHotMiddleware = require("webpack-hot-middleware");
const config = require("./webpack.config.js");
const app = express(),
DIST_DIR = path.join(__dirname, "dist"),
HTML_FILE = path.join(DIST_DIR, "index.html"),
isDevelopment = process.env.NODE_ENV !== "production",
DEFAULT_PORT = 3000,
compiler = webpack(config);
app.set("port", process.env.PORT || DEFAULT_PORT);
if (isDevelopment) {
app.use(webpackDevMiddleware(compiler, {
publicPath: config.output.publicPath
}));
app.use(webpackHotMiddleware(compiler));
app.get("*", (req, res, next) => {
compiler.outputFileSystem.readFile(HTML_FILE, (err, result) => {
if (err) {
return next(err);
}
res.set('content-type', 'text/html');
res.send(result);
res.end();
});
});
}
else {
app.use(express.static(DIST_DIR));
app.get("*", (req, res) => res.sendFile(HTML_FILE));
}
app.listen(app.get("port"));
package.json is as follows:
"main": "server.js",
"script": {
"start": "babel-node server-es6.js",
"build:server": "babel server-es6.js --out-file server.js",
"build:client": "webpack -p --config webpack.config.js --progress"
},
Site is loading but some css are not loading. Console throw error:
GET http://bundle.css/ net::ERR_NAME_NOT_RESOLVED
Image path comes correctly as http://localhost:3000/img/img1.png but it's not showing in the browser. I think the issue is with webpack public path.
When I am using <img src={require('/images/image-name.png')} />, its working fine. But I don't want to do that because it's very heavy codebase and also I think it's not a nice solution.
I have taken help from webpack-express-boilerplate.
In chrome Network tool, image type is coming as text/html.

If your file path is static, you can import the file once and then provide it as a src
import image from '/path/to/images/image-name.png';
...
<img src={image} />

Related

WEBPACK with React router gives 404 while serving the build

Recently i am learning webpack with react and i build a app that runs wells in Dev enviroment but when i build the app and tries to change the route it throws 404 error.
Here are my webpack Config.
webpack.common.js
const path = require("path");
const HTMLWebpackPlugin = require("html-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
module.exports = {
entry: path.resolve(__dirname, "..", "./src/index.tsx"),
resolve: {
extensions: [".tsx", ".ts", ".jsx", ".js"],
},
module: {
rules: [
{
test: /\.(ts|js)x?$/,
exclude: /node_modules/,
use: [
{
loader: "babel-loader",
},
],
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
{
test:/\.(?:ico|gif|png|jpg|jpeg)$/i,
type:'asset/resource'
},
{
test:/\.(woff(2)?|eot|ttf|otf|svg)$/i,
type:'asset/inline'
}
],
},
output: {
path: path.resolve(__dirname, "..", "./build"),
filename: "bundle.js",
},
plugins: [
new HTMLWebpackPlugin({
template: path.resolve(__dirname, "..", "./public/index.html"),
filename:'index.html'
}),
// new CopyWebpackPlugin({
// patterns:[{from:"src",to:'dest'}]
// })
],
};
webpack.dev.js
const ReactRefreshWebpackPlugin = require('#pmmmwh/react-refresh-webpack-plugin');
const path=require('path')
module.exports={
mode:"development",
devServer:{
hot:true,
open:true,
historyApiFallback: { index: "/", disableDotRule: true },
port:3001
},
devtool:'cheap-module-source-map',
plugins:[
new ReactRefreshWebpackPlugin()
]
}
webpack.prod.js
module.exports={
mode:"production" ,
}
i changed lots of configuration like public path and other, but it didn't help.

Window is not defined after a build with Webpack

I am developing a reactJS application and also I am using WebPack 4.29.6 the problem that I face here it is that locally it works everything perfect when I run the npm run dev command while when I want to deploy in server I don't know how to do it I am building the app with the build:production command then it generates /dist folder inside with all files now here I try to run bundle.js it gives me this error: ReferenceError: window is not defined.
these are command's that i use to start my app:
"scripts": {
"dev": "cross-env webpack-dev-server --config ./webpack.config.dev.js --mode development",
"build:production": "cross-env webpack --config webpack.config.production.js --mode production"
}
this is my webpack.config.common.js
const path = require('path');
const webpack = require('webpack');
const outputPath = path.join(__dirname, '/dist');
const port = process.env.PORT || 4000;
module.exports = {
context: __dirname,
entry: './src/index.jsx',
resolve: {
extensions: ['*', '.js', '.jsx'],
},
output: {
path: outputPath,
publicPath: '/',
filename: 'bundle.js',
sourceMapFilename: 'bundle.map',
},
devServer: {
port,
historyApiFallback: true,
compress: true,
contentBase: './dist',
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader', 'eslint-loader'],
},
{
test: /\.less$/,
exclude: /node_modules/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
},
{
loader: 'less-loader',
},
],
},
{
test: /\.css$/,
use: ['css-loader'],
},
{
test: /\.svg$/,
loader: 'svg-inline-loader',
},
{
test: /\.(png|jpg|gif|woff(2)?|ttf|eot|svg)$/,
exclude: [
/\.(js|jsx|mjs)$/,
/\.html$/,
/\.json$/,
/\.(less|config|variables|overrides)$/,
],
use: [
{
loader: 'file-loader',
},
],
},
],
},
plugins: [
new webpack.ProvidePlugin({
Promise: 'es6-promise-promise',
}),
],
};
this is my webpack.config.dev.js
const webpack = require('webpack');
const merge = require('webpack-merge');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpackCommonConfig = require('./webpack.config.common');
module.exports = merge(webpackCommonConfig, {
mode: 'development',
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, '/index.html'),
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.EnvironmentPlugin({ NODE_ENV: 'development' }),
],
devtool: 'inline-source-map',
devServer: {
hot: true,
open: true,
},
externals: {
// global app config object
config: JSON.stringify({
apiUrl: 'http://localhost:3000',
}),
},
});
this is my webpack.config.production.js
const webpack = require('webpack');
const merge = require('webpack-merge');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const webpackCommonConfig = require('./webpack.config.common');
module.exports = merge(webpackCommonConfig, {
mode: 'production',
plugins: [new webpack.EnvironmentPlugin({ NODE_ENV: 'production' })],
optimization: {
minimizer: [
// we specify a custom UglifyJsPlugin here to get source maps in production
new UglifyJsPlugin({
cache: true,
parallel: true,
uglifyOptions: {
compress: false,
ecma: 6,
mangle: true,
},
sourceMap: true,
}),
],
},
devtool: 'source-map',
devServer: {
compress: true,
},
});
It may be late to answer but it may help someone else. I also had the ReferenceError: window is not defined. issue with Webpack 4, and found that adding globalObject: 'this' line to the output section in webpack config file fixed my problem:
output: {
globalObject: "this",
filename: "[name].js",
path: path.join(__dirname, "build/package"),
publicPath: "/resources/",
}
You can see the issue was discussed here
and the Webpack documentation about the globalObject setting here.
Using global worked for me.
const window = global.window
if (window && window.localStorage) {
const storageLogLevel = window.localStorage.getItem(LOG_LEVEL_KEY)
switch (storageLogLevel) {
case LogLevel.DEBUG:
logLevel = 0
break
case LogLevel.INFO:
logLevel = 1
break
case LogLevel.WARNING:
logLevel = 2
break
case LogLevel.CRITICAL:
logLevel = 3
break
default:
logLevel = 1
}
}

Webpack gzip bundle - Uncaught SyntaxError: Unexpected token <

I am working on a react project using webpack for bundling. I wanted to reduce my bundle size so decided to use a compression plugin to serve a gzip file to get a nice small bundle size. The project builds fine and I get a nice small bundle size but here's my issues..when I go to serve my current project here is the error i get:
Looking into I realized that for whatever reason instead of serving the contents of main.js or vendor.js it's returning my index.html file
I am fairly certain my apache server is configured to handle gzip encoding this as I can see it in the response header:
Here is the webpack config I am using:
const appConstants = function() {
switch (process.env.NODE_ENV) {
case 'local':
const localConfig = require('./config/local');
return localConfig.config();
case 'development':
const devConfig = require('./config/development');
return devConfig.config();
case 'production':
default:
const prodConfig = require('./config/production');
return prodConfig.config();
}
};
const HtmlWebPackPlugin = require("html-webpack-plugin");
const webpack = require('webpack');
const CompressionPlugin = require('compression-webpack-plugin');
const htmlWebpackPlugin = new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html",
hash: true
});
const compressionPlugin = new CompressionPlugin({
filename: "[path].gz[query]",
test: /\.(js|css)$/,
algorithm: 'gzip',
deleteOriginalAssets: true
});
let webpackConfig = {
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.css$/,
exclude: [ /assets/, /node_modules/ ],
use: [
{
loader: "style-loader"
},
{
loader: "css-loader",
options: {
modules: true,
importLoaders: 1,
localIdentName: "[name]_[local]_[hash:base64]",
sourceMap: true,
minimize: true
}
}
]
},
{
test: /\.(pdf|jpg|png|gif|svg|ico)$/,
exclude: [/node_modules/],
use: [
{
loader: 'file-loader'
},
]
},
{
test: /\.(woff|woff2|eot|ttf|svg)$/,
exclude: [/node_modules/],
use: {
loader: 'url-loader?limit100000'
}
}
]
},
entry: [ "#babel/polyfill", "./src/index.js"],
output: {
publicPath: appConstants().DS_BASENAME ? JSON.parse(appConstants().DS_BASENAME) : '/',
chunkFilename: '[name].[chunkhash].js'
},
optimization: {
splitChunks: {
chunks: 'all',
},
},
plugins: [
htmlWebpackPlugin,
compressionPlugin,
new webpack.DefinePlugin({
'process.env': appConstants()
}),
new webpack.EnvironmentPlugin(['NODE_ENV']),
],
devServer: {
historyApiFallback: true
}
};
// configure source map per-env
if (process.env.NODE_ENV === 'local') {
webpackConfig.devtool = 'source-map';
} else {
webpackConfig.devtool = 'hidden-source-map';
}
module.exports = webpackConfig;
I cannot figure out why the gzip is not being read/recognized by the browser. I've tried several post with similar issues but no solutions.
You need to add middleware function to handle .js and .css file with suffix .gz
Like that
const app = express()
app.get('*.js', function(req, res, next) {
req.url = req.url + '.gz'
res.set('Content-Encoding', 'gzip')
res.set('Content-Type', 'text/javascript')
next()
})
app.get('*.css', function(req, res, next) {
req.url = req.url + '.gz'
res.set('Content-Encoding', 'gzip')
res.set('Content-Type', 'text/css')
next()
})
app.use('/dist', serve('./dist', true))
app.use(express.static('./dist'));
You have to add middleware function before express.static
Good luck!

React error even after using DefinePlugin

I am using React 15.4.2 and Redux 3.6.0 with Webpack and this is my webpack.config.js file contents: (some of the code is omitted for brevity)
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
const FaviconsWebpackPlugin = require('favicons-webpack-plugin');
const pkg = require('./package.json');
const TARGET = process.env.npm_lifecycle_event;
const PATHS = {
src: path.join(__dirname, 'src/js'),
dist: path.join(__dirname, 'dist')
};
process.env.BABEL_ENV = TARGET;
const common = {
resolve: {
extensions: ['', '.js', '.jsx']
},
entry: {
app: PATHS.src
},
output: {
path: PATHS.dist,
publicPath: '/',
filename: '[name].[hash].js'
},
module: {
loaders: [
{ test: /\.jsx?$/, loaders: ['babel?cacheDirectory'], include: PATHS.src },
{ test: /\.scss$/, exclude: /node_modules/, loaders: ['style', 'css', 'sass'] },
{ test: /(\.ttf|\.woff2?|\.eot|\.svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, exclude: /node_modules/, loader: 'url' },
{ test: /\.(jpe?g|png|gif|svg)$/i, exclude: /node_modules/, loader: 'url?limit=10000!img?progressive=true' },
{ test: /\.json/, loaders: ['json']}
]
},
plugins: [
new HTMLWebpackPlugin({
template: 'src/index.html',
inject: 'body'
})
]
};
if (TARGET === 'build') {
module.exports = merge(common, {
entry: {
vendor: Object.keys(pkg.dependencies)
},
output: {
path: PATHS.dist,
filename: '[name].[chunkhash].js',
chunkFilename: '[chunkhash].js'
},
module: {
loaders: [
{ test: /\.css$/, loader: ExtractTextWebpackPlugin.extract('style', 'css'), include: PATHS.src }
]
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production')
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
new CleanWebpackPlugin([PATHS.dist]),
new ExtractTextWebpackPlugin('[name].[chunkhash].css'),
new webpack.optimize.CommonsChunkPlugin({
names: ['vendor', 'manifest']
})
]
});
}
Running npm run build gives the minified code. But it still gives the error
Warning: It looks like you're using a minified copy of the development build of React. When deploying React apps to production, make sure to use the production build which skips development warnings and is faster. See https://facebook.github.io/react/docs/optimizing-performance.html#use-the-production-build for more details.
I have also tried reordering the plugins in build TARGET, but its giving the same error.
What am I missing here?
P.S. Redux gives the same minification error too.
EDIT
This is my package.json build script:
"scripts": {
...
"build": "NODE_ENV=production webpack --progress"
...
}
EDIT #2
This is the output to a console.log statement from within the application.
You could use this syntax for the DefinePlugin.
new webpack.DefinePlugin({
'process.env':{
'NODE_ENV': JSON.stringify('production')
}
}),
I enabled source maps to see that its a package I have been using that was minified using non-standard ways. So, setting NODE_ENV to 'production' had no effect on the said package. Nevertheless, my Webpack config and my build scripts have been working perfectly fine. Thank you for your help guys!

Babel/Webpack - Configuration for Hot Reloading Confusion?

I have been working on ReactJS for sometime now,I have come over quite a lot of modules eco-system (Webpack,Babel,React) etc..
I have some knowledge on webpack configuration,I have done basic configuration. See below
const Path = require('path');
const Webpack = require('webpack');
const envs = require('../utils/env');
const Possibles = envs.possibles;
const NODE_ENV = process.env.NODE_ENV;
const miniOps = {
development: Possibles.dev.indexOf(NODE_ENV) > -1,
production: Possibles.prod.indexOf(NODE_ENV) > -1
};
const configuration = {
target: 'web',
output: {
path: Path.join(__dirname, '..', 'public'),
filename: 'bundle.js',
publicPath: '/assets/'
},
module: {
loaders: []
},
resolve: {
extensions: ['', '.js', '.jsx']
},
plugins: [
new Webpack.DefinePlugin({ NODE_ENV: JSON.stringify(NODE_ENV) })
]
};
if (miniOps.development) {
configuration.resolve.alias = {};
configuration.module.noParse = [];
configuration.cache = true;
configuration.devtool = 'cheap-eval-source-map';
configuration.entry = [
Path.join(__dirname, '..', 'app/main.js')
];
const minideps = [
'react/dist/react.min.js'
];
const NODE_MODULES_DIR = Path.join(__dirname, '..', 'node_modules');
minideps.forEach(dep => {
const depPath = Path.resolve(NODE_MODULES_DIR, dep);
configuration.resolve.alias[dep.split(Path.sep)[0]] = depPath;
configuration.module.noParse.push(depPath);
});
configuration.plugins.push(
new Webpack.optimize.OccurenceOrderPlugin(),
new Webpack.NoErrorsPlugin(),
new Webpack.HotModuleReplacementPlugin()
);
configuration.module.loaders.push({
test: Path.resolve(NODE_MODULES_DIR, minideps[0]),
loader: 'expose?React'
});
configuration.module.loaders.push({
test: /\.(js|jsx)$/,
include: Path.join(__dirname, '..', 'app'),
exclude: /node_modules/,
loader: 'babel',
query: {
cacheDirectory: true
}
});
}
if (miniOps.production) {
configuration.entry = {
app: [
Path.join(__dirname, '..', 'app/main.js')
],
vendor: ['react']
};
configuration.output.path = Path.join(__dirname, '..', 'dist');
configuration.module.loaders.push({
test: /\.(js|jsx)$/,
include: Path.join(__dirname, '..', 'app'),
exclude: /node_modules/,
loader: 'babel'
});
configuration.plugins.push(
new Webpack.optimize.UglifyJsPlugin({
compress: {
unused: true,
dead_code: true,
warnings: false,
screw_ie8: true
}
})
);
configuration.plugins.push(
new Webpack.optimize.OccurrenceOrderPlugin(),
new Webpack.optimize.DedupePlugin(),
new Webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.bundle.js')
);
}
console.log(`Bundling modules...... NODE_ENV: ${NODE_ENV}`);
module.exports = configuration;
The babelrc configuration is,
{
"presets": ["es2015", "react"],
"env": {
"development": {
"plugins": [
[ "transform-runtime" ],
[
"react-transform", {
"transforms": [
{
"transform": "react-transform-hmr",
"imports": ["react"],
"locals": ["module"]
},
{
"transform": "react-transform-catch-errors",
"imports": ["react", "redbox-react"]
}
]
}
]
]
}
}
}
I have planned not to use dev-server, instead I am planning to write Webserver which runs on Hapi.JS.
Questions:
Now that I am using react-transform-hmr. Do I need to use webpack-dev-middleware and webpack-hot-middleware ?
How should I implement / connect react-transform-hmr with my Hapi webserver ?
If I am gonna use webpack-dev-server and webpack-hot-middleware once again with this plugin
https://www.npmjs.com/package/hapi-webpack-plugin
Then what is the use of react-transform-hmr ?
& I see one of the boilerplate is also using this
https://github.com/Dindaleon/hapi-react-starter-kit/blob/master/webpack/hapiWebpack.js
Can someone explain what is the use of webpack-hot-middleware,webpack-dev-middleware,babel-transform-hmr ?

Resources