Reputation: 4345
I am loading an image with angular, e.g.
<img ng-src="{{::path-to-image}}"/>
When I bundle my application with webpack the image URL is resolved in runtime, thus not bundled by webpack's loaders.
This is the image loader I am using:
{
test: /\.(jpe?g|png|gif|svg)$/i,
loader: 'url?limit=8192!img'
}
How can webpack bundle those images resolved in runtime?
Upvotes: 12
Views: 8009
Reputation: 1660
im just using CopyWebpackPlugin and no overhead at all
const CopyWebpackPlugin = require('copy-webpack-plugin');
// WriteFilePlugin needed only for webpack 3-4 and webpack dev-server
const WriteFilePlugin = require('write-file-webpack-plugin');
plugins: [
...
new WriteFilePlugin(),
new CopyWebpackPlugin([
{from: 'files', to: 'files'},
{from: 'images-2x', to: 'images-2x'},
{from: 'images', to: 'images'},
]),
]
Upvotes: 0
Reputation: 3902
I needed to dynamically resolve images at runtime with hashes generated by webpack, e.g., imgA.bd79a5ba.png
.
{
test: /\.png$/,
loader: 'file-loader?name=images/[name].[hash].[ext]',
}
I ended up creating a module to alias and required the images:
let map = {
'imgA': require('./images/imgA.png'),
'imgB': require('./images/imgB.png'),
'imgC': require('./images/imgC.png')
}
This produces the map:
{
'imgA': imgA.bd79a5ba.png,
'imgB': imgB.e51f66a2.png,
'imgC': imgC.d84ae37c.png
}
In my component I resolved the url from the map:
self.link = function link(scope) {
scope.imageUrl = function(name) {
function return map[name];
}
};
It was then trivial to load the image:
<img ng-src="{{ imageUrl('imgA') }}">
The above is simplified. I found it useful to create a module for the map:
export default {
'imgA': require('./images/imgA.png'),
'imgB': require('./images/imgB.png'),
'imgC': require('./images/imgC.png')
}
then import it into the component module:
import urlMap from './imageUrlMap'
console.log(urlMap.imgA)
> imgA.bd79a5ba.png
Upvotes: 0
Reputation: 4160
Because I also needed thus functionality and found the original answer was far from a perfect solution I ended up figuring it out on my own.
Write a function in the controller:
$scope.loadImage = function(image) {
return require('/images/' + image);
};
And use it in your ng-src:
<img ng-src="{{loadImage('myImage')}}" />
After that to make dynamic requires work you can use a context.
For example: https://github.com/webpack/webpack/tree/master/examples/require.context#examplejs
Upvotes: 18
Reputation: 10691
I created a uiImage
directive which requires
the images.
function uiImage() {
return {
restrict: 'A',
link: function(scope, element, attr) {
var src = attr.uiImage || attr.src;
function loadImage(image) {
return require(`Images/${image}`);
}
// required for webpack to pick up image
element.attr('src', loadImage(src));
}
};
}
uiImage.$inject = [];
export default uiImage;
Usage:
<img ui-image='myimage.png' />
webpack.config.js
I have a Webpack resolve Images
which points to the location of all my images.
resolve: {
alias: {
'Images': path.join(config.appDir, '/images')
}
}
Upvotes: 2
Reputation: 349
If you need an image path that is programmatically generated, it means you have some logic expecting this image to exist. In other words, you should consider this image as a dependency of that piece of logic, thus you need to require it explicitely.
In your JS code (eg: controller)
this.imageUrl = require('path-to-image' + someDynamicValue + '.jpg');
In your template:
<img ng-src="{{::myCtrl.imageUrl}}"/>
Webpack is smart enough to understand the dynamic require
statement and bundle your images that will match that expression.
Check the documentation for more details: https://webpack.github.io/docs/context.html)
Upvotes: 10