Cannot retrieve images in my react component - image

I am quite new at coding so please be indulgent... I searched a lot and I don't manage to get my issue fixed :(
I would like to get my images rendered through and html img tag. I saw that the best way in react is to import my images. Like this :
import avatar from './avatar.png';
export default class Connection extends React.Component {
render () {
return (
<div>
{this.props.user.firstname} {this.props.user.lastname}
<img src={avatar} className='img-circle' />
<a href='#' onClick={this.props.logout}>Déconnexion</a>
</div>
);
}
}
I use the following webpack config to load these images :
module: {
loaders: [
{ test: /\.jsx?$/, exclude: [/node_modules/], loader: 'babel' },
{ test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader') },
{ test: /\.(png|gif|jpe?g|svg|jpg)$/i, loader: 'file-loader?hash=sha512&digest=hex&name=[path][name]-[hash].[ext]' },
{ test: /\.(png|gif|jpe?g|svg|jpg)$/i, loader: 'url-loader?limit=10000' }
]
}
I see that webpack manage to load the jpg or png files but when it comes to display it, it seems that the file generated/copied is not available (ex: /MyApp/avatar-50b93a2df8aec266d7c8c1c0f5719d1b.png is not available).
I use the webpack dev server so I don't see my files bundled and the dist or build folder created.
Any idea of solving my issue ?
Thanks,
When using the require within the img tag I get the following error :
Module not found: Error: Cannot resolve 'file' or 'directory' ./avatar
I tried to get the extension in the webpack config but it does not solve anything :(
Here is my public path config in my webpack config :
output: {
path: path.join(__dirname, '/build'),
publicPath: '/',
filename: 'bundle.js'
}

To load images with Webpack you need to do:
<img src={require('./avatar.jpg'})/>
Webpack crawls through your application codebase, code gets bundled into a single file however files are not kept in the same structure, by calling require Webpack will do dependency management for you, in this case the file will move around and code will be injected so it is pointing to it's bundled location.

You can take a look at this article from SurviveJS Book. Load Images Chapter

Related

Laravel mix removes subfolder from image path

I've set up an alias for my public folder where I've placed my images.
So they are inside public/images. I have a subfolder for certain types of images - in this case, card brands.
They're in public/images/card-brands
Here is my alias config:
mix.webpackConfig({
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'#': __dirname + '/resources/js',
'#public' : __dirname + '/public'
},
},
})
I'm importing the images in my vue component file:
import amex from '#public/images/card-brands/amex.svg'
import discover from '#public/images/card-brands/discover.svg'
import visa from '#public/images/card-brands/visa.svg'
import mastercard from '#public/images/card-brands/mastercard.svg'
Then using it inside my components data like so:
export default {
name: 'PaymentMethod',
data() {
return {
...
visaSvg: visa,
mastercardSvg: mastercard,
discoverSvg: discover,
amexSvg: amex,
currentCardBrand: this.initialCurrentCardBrand
...
}
},
props: {
...
initialCurrentCardBrand: String,
...
}
computed: {
getCurrentCardBrandSvg() {
switch (this.currentCardBrand) {
case 'mastercard':
return this.mastercardSvg;
break;
case 'visa':
return this.visaSvg;
break;
case 'amex':
return this.amexSvg;
break;
case 'discover':
return this.discoverSvg;
break;
}
}
}
...
Finally, I'm using it on my template as and image src: <img class="w-10" :src="getCurrentCardBrandSvg">
Now, even though the images and my import path are using the card-brands subfolder, the URL that is generated ignores this and just looks for the images in the root images folder.
It should be:
/public/images/card-brands/visa.svg
but it's generating as
/public/images/visa.svg
How can I get it to keep my subfolder?
try this instead {{ asset('/images/card-brands/mastercard.svg')) }}
I faced a similar issue in laravel. I used the above format.Please correct me if Im wrong.
Edit: This could be slightly wrong. It works correctly for importing images via javascript, but I think grabbing images via laravel in blade templates still needs the images in the public folder.
The issue was not knowing that I was supposed to put my images folder inside the resources folder rather than public.
Laravel Mix will compile the images like it does the JS and SCSS and place it in public automatically.
So I created an images folder in resources, deleted my manually made images folder in public, and made an alias:
alias: {
'#images': __dirname + '/resources/images'
}
and now I can link to that inside my vue component.
import amex from '#images/card-brands/amex.svg'
import discover from '#images/card-brands/discover.svg'
import visa from '#images/card-brands/visa.svg'
import mastercard from '#images/card-brands/mastercard.svg'
The generated images will automatically be placed in public on the root level once I run npm run dev or npm run prod

Loading images in React with Webpack

I'm having trouble getting a simple image to show up in a simple app using Webpack and React.
I've read this thru and tried a few different ways, but keep getting various errors, or at best sometimes no errors, but also no image displaying.
Here is my React component:
import React from 'react';
import styles from '../css/main.css';
import Menu from './Menu';
const logo = require('./images/PIVX_Planet_1a_239x83.png');
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {test: 'foo'};
}
render() {
return (
<div>
<div id='container'></div>
<div className={styles.logo}>
<img src={logo}/>
</div>
<div>
<Menu/>
</div>
</div>
);
}
}
Here is my webpack config:
...
module: {
loaders: [{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel',
query: {
"presets": ["react", "es2015", "stage-0", "react-hmre"]
}
}, {
test: /\.(jpg|png|svg)$/,
loader: 'url-loader',
options: {
limit: 25000,
},
}, {
test: /\.json?$/,
loader: 'json'
}, {
test: /\.css$/,
loader: 'style!css?modules&localIdentName=[name]---[local]---[hash:base64:5]'
}]
}
...
With this, get error from webpack in console:
ERROR in ./app/components/App.js
Module not found: Error: Cannot resolve 'file' or 'directory' ./images/PIVX_Planet_1a_239x83.png in /Users/mac/_DEV/_LAB/PIVX/PIVX-Planet-2/app/components
# ./app/components/App.js 67:11-56
I've also tried using babel-plugin-transform-react-jsx-img-import
(https://www.npmjs.com/package/babel-plugin-transform-react-jsx-img-import)
And then just use:
<div className={styles.logo}>
<img src="./images/PIVX_Planet_1a_239x83.png"/>
</div>
In that case, there are no errors, but the image show up broken.
I've tried changing the relative path to the image with all these combinations.
Directory structure:
app
components
App.js
images
PIVX_Planet_1a_239x83.png
index.html
...
Any insights?
As per your directory structure the path that you need to use is
const logo = require('../images/PIVX_Planet_1a_239x83.png');
since images is under app directory and not under components from where you are trying to get the image location
Also make sure all your loaders are properly installed
you can also try let as:
let logo = require('../images/PIVX_Planet_1a_239x83.png');
Always use let as much as possible to avoid the scope monster
The problem I was having was using
import logo from './images/PIVX_Planet_1a_239x83.png'
instead of
const logo = require('./images/PIVX_Planet_1a_239x83.png');
in a typescript react app w/ a bespoke webpack config.
I have tried everything that you guys have suggested but nothing is working for me. when I put my code in and 'run dev' it come out with an error placeholder. I am using it in the app.js and would like my logo as a link to the home page or just show up at all, in this case I was attempting to just have it on the page.
import '../styles/globals.css'
import Link from 'next/link'
import bpdlogofull from '../public/bpdlogofull.png'
`function MyApp({ Component, pageProps }) {
return (
<div>
<nav className="border-b p-6">
<img src={bpdlogofull} alt='logo'className='flex justify-end'/>
<div className="flex mt-4">
<Link href="/" className="home-button">

How to combine `css-modules` with normal `sass`, preferably in `webpack`

TLDR: How to combine css-modules with normal sass, preferably in webpack.
The Setup:
I am working on the styling build process for an e-commerce website. The site's styles are currently done in sass along with the js through a gulp browserify build process.
I have recently added a single page app that is built using react with webpack and babel. Inside of that application I am taking advantage of css-modules provided by webpack to scope the class names to each react component.
The problem:
I would like to incorporate the styles from the webpack css-modules build in with the main styling bundle for the site. To do this, I was considering building a webpack configuration to build the styles for the whole site. The problem I have is how to get the styles which are currently built by the single page webpack configuration and inject just the style chunk into a global webpack configuration that handles styles for the whole site. I should mention that I would like to keep the two configurations as separate as possible
The Questions:
Is there a proper way of having decoupled webpack builds where one is still able to use chunks from the other?
If so, how do I do it so that the css-module setup stays in the single page configuration, and the extract-text-webpack part along with a boring sass build goes into a global configuarion?
If not, how should I go about having one section of sass go through the css-modules workflow, and still combine it with the bundle from the rest of the site.
Thanks in advance.
EDIT
based on #Alexandr Subbotin's answer, I have updated my webpack to look something like the code below. I did have to change names and paths because of the code belongs to my employer, so there may be slight errors.
var ExtractTextPlugin = require('extract-text-webpack-plugin');
const JSDIR = './build/js/';
const STYLES = './build/css/bundle.css';
module.exports = {
entry : {
'styles' : './src/styles.scss',
'app' : './src/index.js',
// a javascript file that includes the root of the single page app.
'single-page' : './src/single-page/styles-entry.js',
},
output : {
path : JSDIR,
filename : '[name].js', // normally compiles my
publicPath: 'http://localhost:8080/',
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader : 'babel-loader',
query : {
presets: [
'react','es2015','stage-0',
]
},
},
{
test : /\.scss$/,
loader: ExtractTextPlugin.extract('style?sourceMap', 'css?-url&sourceMap!sass?sourceMap'),
exclude : /\/single-page\//,
},
{
test : /\.scss$/,
loader: ExtractTextPlugin.extract(
'style?sourceMap',
'css?-url&modules&importLoaders=1&localIdentName=SinglePage__[name]__[local]!sass?sourceMap'
),
include : /\/single-page\//,
}
]
},
plugins : [
new ExtractTextPlugin(STYLES, {
allChunks : true,
}),
],
resolve : {
alias: {
"eventEmitter/EventEmitter": "wolfy87-eventemitter",
},
extensions: ['', '.js','.jsx'],
},
}
If I understood your question you want to apply css-modules only to one part of your application and leave simple sass building process in other parts.
To do this you can use exclude and include options in loaders. I.e. if you have your single page application inside single-page directory your webpack config can be:
module: {
entry: {
// it is your global sass styles
application_css: './css/application.scss',
// it is main file of your SPA bundle. Somewhere inside you will use require('./styles.scss') that should be processed by css-modules
spa_index: './single-page/index.js'
},
loaders: [
...,
{
// This loader will build all your sass that are not in `single-page` directory
test: /\.scss$/,
loader: ExtractTextPlugin.extract('style', 'css!sass'),
exclude: /\/single-page\//
},
{
// This loader will handle all your css module in `single-page` directory
test: /\.scss$/,
loader: 'style!css?modules!sass',
include: /\/single-page\//
},
],
...
}
So, in this case all css from single-page/ will use css modules, and the rest won't.
EDIT:
If you take a look in API section of ExtractTextPlugin documentation you find
The ExtractTextPlugin generates an output file per entry, so you must use [name], [id] or [contenthash] when using multiple entries.
In your example you have have two chunks with css (styles and single-page), but only one output ./build/css/bundle.css. If you change your output to ./build/css/[name].css your will have two css files: styles.css with your global css and single-page.css with SPA styles.

Webpack 2.1.0-beta.6 config file not picking up loaders for styling on windows

I'm trying to get webpack 2.1.0-beta.6's style, css, less, and file loaders to catch on Windows Server 2008, Babel 6, and Node 4.3. If webpack has this loader configuration:
loaders: [
{
test: /\.less$/,
loaders: ['style-loader', 'css-loader', 'less-loader']
},
{
test: /.gif$/,
loader: 'file'
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015-native-modules']
}
}
The import require('../styling/my-style.less') fails with
ERROR in ../styling/my-less.less Module parse failed:
.../my-style.less
Unexpected character '#' (1:0) You may need an appropriate loader to
handle this file type. | #import "other.css";
./my-js.js 8:0-38
require('style!css!less!../styling/my-style.less') sort of works though. At least until it gets to a .gif file.
ERROR in ../styling/themes/base/images/animated-overlay.gif Module
parse failed:
..\styling\themes\base\images\animated-overlay.gif
Unexpected character ' ' (1:7) You may need an appropriate loader to
handle this file type. (Source code omitted for this binary file) #
./~/css-loader!./~/less-loader!../styling/my-style.less
10:46994-47046
My webpack config is in with my src directory and styles is a parallel directory
src
webpack.config.js
my-js.js // file doing the import from styling
styling
my-style.less
None of my loaders were getting picked up because under module.exports, I didn't have a module wrapping my loaders.
module.exports.loaders //doesn't work and require acts like there aren't loaders associated with the file type
module.exports.module.loaders //works

using d3.js as an external in webpack

I'm using this tutorial to setup a React.js project with webpack. The webpack.config.js below is almost an exact copy (except that I'm using an app and 'dist' folder), and I am also adding d3.js as an external. Because React is added as an external it lets me do require('react') in any of my app files without including it in the bundle. I wish to do the same with d3.js and have installed it as a node_module, and listed it in the externals area of my webpack config, but when I do require('d3') i get an error message that it's not available.
How can I use d3 (or jQuery for that matter) as an external if I have it installed as a node_module?
this is my project setup
/app
/dist
/node_modules
package.json
webpack.config.js
module.exports = {
entry: './app/index.jsx',
output: {
path: './dist',
filename: 'bundle.js', //this is the default name, so you can skip it
//at this directory our bundle file will be available
//make sure port 8090 is used when launching webpack-dev-server
publicPath: 'http://localhost:8090/assets'
},
module: {
loaders: [
{
//tell webpack to use jsx-loader for all *.jsx files
test: /\.jsx$/,
loader: 'jsx-loader?insertPragma=React.DOM&harmony'
}
]
},
externals: {
//don't bundle the 'react' npm package with our bundle.js
//but get it from a global 'React' variable
'react': 'React',
'd3': 'd3'
},
resolve: {
modulesDirectories: ['app', 'node_modules'],
extensions: ['', '.js', '.jsx']
}
}
I know this question has been open a while, but hopefully this answer is still useful!
If you have installed d3 (or jQuery) as a node_module, you can use the webpack ProvidePlugin to tie an arbitrary key to a module.
The key will be then be available to require anywhere in your webpack app.
E.g. webpack.config.js
{
...lots of webpack config here...
...
plugins: [
new webpack.ProvidePlugin({
d3: 'd3',
$: 'jquery'
})
]
...
}
Then in my-file.js
var d3 = require('d3')
Hope that helps!

Resources