Reputation: 363
Good afternoon,
I am working on a React/Redux app and the images that are being loaded into my store are not displaying. My galleryObject.js
includes information about each image I want to display like so:
pastry1: {
name: "Pastry!",
image: "./client/images/cake1.jpg",
desc: "Tasty Pastry"
},
pastry2: {
name: "Pastry!",
image: "./client/images/cake2.jpg",
desc: "Tasty Pastry"
} ... (all the way to pastry17)
What baffles me is that the absolute path does not lead to the image being displayed, the state is being loaded correctly because I can see it in my React dev tools. I even threw in a hyperlink to an image online and it works to test it out.
My file structure is like so:
// Project
// client
//images (where the actual pictures are stored)
//data (where galleryObject.js resides)
//main.js (where everything eventually becomes bundled
In my experience this is normally a problem with how my devServer.js
accesses static files in my project. The real admission here is that I copy pasta-d this devServer.js
from Wes Bos' Learn Redux tutorial and this is what it looks like:
devServer.js
var path = require('path');
var express = require('express');
var webpack = require('webpack');
var config = require('./webpack.config.dev');
var PORT = process.env.PORT || 7770
var app = express();
var compiler = webpack(config);
app.use(require('webpack-dev-middleware')(compiler, {
noInfo: true,
publicPath: config.output.publicPath
}));
app.use(require('webpack-hot-middleware')(compiler));
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname, 'index.html'));
});
app.listen(PORT, "localhost", function(err) {
if (err) {
console.log(err);
return;
}
console.log(__dirname);
console.log('Listening at http://localhost:7770');
});
Seeing a lot of webpack stuff I figured that is where I am going wrong so I checked out tcoopman's image-webpack-loader. I npm installed the module and my webpack.config.dev/prod.js
both look the same as the example from tcoopman:
webpack.config.dev.js:
var path = require('path');
var webpack = require('webpack');
module.exports = {
devtool: 'source-map',
entry: [
'webpack-hot-middleware/client',
'./client/main'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/static/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
],
module: {
loaders: [
// js
{
test: /\.js$/,
loaders: ['babel'],
include: path.join(__dirname, 'client')
},
// CSS
{
test: /\.css$/,
include: path.join(__dirname, 'client'),
loader: 'style-loader!css-loader!stylus-loader'
},
// images
{
test: /\.(jpe?g|png|gif|svg)$/i,
include: path.join(__dirname, 'client'),
loaders: [
'file?hash=sha512&digest=hex&name=[hash].[ext]',
'image-webpack?bypassOnDebug&optimizationLevel=7&interlaced=false'
]
}
]
}
};
webpack.config.prod.js:
var path = require('path');
var webpack = require('webpack');
module.exports = {
devtool: 'source-map',
entry: [
'./client/main'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/static/'
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': "'production'"
}
}),
new webpack.optimize.UglifyJsPlugin({
compressor: {
warnings: false
}
})
],
module: {
loaders: [
// js
{
test: /\.js$/,
loaders: ['babel'],
include: path.join(__dirname, 'client')
},
// CSS
{
test: /\.scss$/,
include: path.join(__dirname, 'client'),
loaders: ["style", "css", "sass"]
},
// IMAGES
{
test: /\.(jpe?g|png|gif|svg)$/i,
include: path.join(__dirname, 'client'),
loaders: [
'file?hash=sha512&digest=hex&name=[hash].[ext]',
'image-webpack?bypassOnDebug&optimizationLevel=7&interlaced=false'
]
}
]
}
};
I'm certain that my combination of copy pasta and lack of knowledge when it comes to web pack are at fault. Bad dev. But I'd really appreciate some insight as to what else I am doing wrong not getting my images to display.
Cheers
edit showing how the images make it into the store:
project/client/store.js
import { createStore, compose } from "redux";
import { syncHistoryWithStore } from "react-router-redux";
import { browserHistory } from "react-router";
// all roots
// root reducer
import rootReducer from "./reducers/mainReducer";
// data Objects
import cakeGallery from './data/galleryObject'; // the object is passed into the default state
// default state object
const defaultState = {
cakeGallery,
open: false
};
const store = createStore(rootReducer, defaultState);
export const history = syncHistoryWithStore(browserHistory, store);
export default store;
project/client/reducers/cakeGalleryReducer.js
function cakeGallery(state={}, action){
console.log("cake gallery reducer")
console.log(state, action);
return state;
}
export default cakeGallery; // this gets combined with another reducer
// in project/client/reducers/mainReducer.js
I think here is where I run into trouble. When the page is loaded the cakeGalleryReducer.js
function is firing off, so am I passing an empty object continually? This is a picture of my javascript console when the page loads initially, it still seems like I have an object that should be full.
project/client/components/App.js
// this file is basically creating a component that will
// "sprinkle on" props and dispatchers to our Main component
import { bindActionCreators } from "redux";
import { connect } from "react-redux";
import * as actionCreators from "../actions/userActions.js";
import StoreShell from "./StoreShell.js";
// cakeGallery is now known simply as images when referred to in components
function mapStateToProps(state){
return {
images: state.cakeGallery,
open: state.open
}
}
function mapDispatchToProps(dispatch){
return bindActionCreators(actionCreators, dispatch);
}
const App = connect(mapStateToProps, mapDispatchToProps)(StoreShell);
// immediately call what component you want to connect to (Main)
export default App;
project/client/components/StoreShell.js
import Main from "./Main"
const StoreShell = React.createClass({
render(){
return(
<div>
<Main {...this.props} />
</div>
)
}
})
export default StoreShell;
From here the information in the intial galleryObject.js
accessible as {this.props.images}
.
Upvotes: 2
Views: 3754
Reputation: 363
Check it out
devServer.js
var path = require('path');
var express = require('express');
var webpack = require('webpack');
var config = require('./webpack.config.dev');
var PORT = process.env.PORT || 7770
var app = express();
var compiler = webpack(config);
app.use(require('webpack-dev-middleware')(compiler, {
noInfo: true,
publicPath: config.output.publicPath
}));
// SOLVED IT
app.use(express.static(path.join(__dirname + "/client")));
app.use(require('webpack-hot-middleware')(compiler));
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname, 'index.html'));
});
app.listen(PORT, "localhost", function(err) {
if (err) {
console.log(err);
return;
}
console.log(__dirname);
console.log('Listening at http://localhost:7770');
});
So this line: app.use(express.static(path.join(__dirname + "/client")));
was not originally in my copy pasta'd devServer.js
. What I did was make my static files (css, javascript, and most importantly images) accessible using the express.static middleware that allows you to serve up static files.
This is how I normally solve this issue but I assumed that images were already covered in the code above and below my soluton.
Thanks for everyone's input.
Upvotes: 0
Reputation: 3310
Webpack is not that smart to import images for you.
I suggest you to import all images required in your galleryObject.js
, and keep a reference of the image in each pastry object. Then when it gets to Main
component, you can just use them directly.
Upvotes: 1