javascript - How to handle dynamic image paths with webpack
问题描述
I've managed to process the majority of my icons within a large application but there are still two use cases which don't get caught.
Dynamic paths used within angular templates
<md-icon md-svg-src="{{'/assets/icons/ic-' + $ctrl.icon + '.svg'}}"></md-icon>
Paths used as varibled within components that are passed to angular templates
i.e something along the lines of
class Comp {
this.settingsLinks = [
{name: 'advanced settings', icon: '/assets/icons/ic-settings.svg'}
]
}
and then that gets used within a template like so
<div ng-repeat="setting in $ctrl.settingsLinks">
<md-icon md-svg-src="{{setting.icon}}"></md-icon>
</div>
My webpack config is like so
module.exports = {
module: {
loaders: [
{
test: /\.html$/,
loaders: 'html-loader',
options: {
attrs: ['md-icon:md-svg-src', 'img:ng-src'],
root: path.resolve(__dirname, '../src'),
name: '[name]-[hash].[ext]'
}
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
enforce: 'pre'
},
{
test: /\.(jpe?g|png|gif|svg)$/,
loader: 'file-loader',
options: {
name() {
return '[name]-[hash].[ext]';
}
}
},
{
test: /\.js$/,
exclude: /node_modules/,
loaders: [
'ng-annotate-loader',
'babel-loader'
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: conf.path.src('index.html')
}),
new ExtractTextPlugin('index-[contenthash].css'),
],
output: {
path: path.join(process.cwd(), conf.paths.dist),
filename: '[name]-[hash].js'
},
entry: {
app: [`./${conf.path.src('app/app.module.js')}`],
vendor: Object.keys(pkg.dependencies)
},
};
I've been looking at the webpack.ContextReplacementPlugin
as a potential way of handling the dynamic paths does anyone have any insight into what I'm trying to achieve? I want to be able to hash names for cache busting purposes but am struggling to work out how to handle dynamic paths in both js and templates.
解决方案
webpack gives access to require.context
which allows telling webpack what the dynamic path could/should be, it removed the uncertainty of what is being required and allows you to return the newly hashed icon name from its original name. It does not require them all having an import cost it merely creates a map between the old and new name if I have understood correctly.
for example, this is saying grab all the file names in the icons folder grab the ones starting with ic- as that's our naming scheme for icons, this creates an object at build time I believe of all the possible icons to be used.
const ICONS = require.context('../../../assets/icons', true, /ic-[a-zA-Z0-9.-]/);
whats returned is a function where you can pass the original icon name and get back the hashed version. You can also use ICONS.keys()
to get an array of icons.
here is an example usage I've used to provide some icons.
const ICONS = require.context('../../../assets/icons', true, /ic-[a-zA-Z0-9.-]/);
export function getIconFromPath(path) {
return ICONS(path);
}
function getIconsFromPaths(obj) {
Object.keys(obj).forEach(key => Object.assign(obj, {[key]: ICONS(obj[key])}));
return obj;
}
export default getIconsFromPaths({
ARCHIVED: './ic-status-warning.svg',
CANCELLED: './ic-status-cancelled.svg',
CONFLICT: './ic-status-warning.svg',
DRAFT: './ic-status-draft.svg',
EARLIER: './ic-status-published.svg',
ENDED: './ic-status-ended.svg',
ERROR: './ic-status-published-failure.svg',
FAILURE: './ic-status-failure.svg',
INVALID: './ic-status-warning.svg',
IN_PROGRESS: './ic-content-publish-in-progress.svg',
LATEST: './ic-status-published-latest.svg',
LOCKED: './ic-status-locked.svg',
PUBLISHED: './ic-status-published.svg',
PUBLISHING: './ic-content-publish-in-progress.svg',
SCHEDULED: './ic-status-scheduled.svg',
SCHEDULING: './ic-content-publish-in-progress.svg',
UNLOCKED: './ic-status-unlocked.svg',
UPDATED: './ic-webhook-request-success.svg',
UNPUBLISHING: './ic-content-publish-in-progress.svg',
UNSCHEDULING: './ic-content-publish-in-progress.svg',
VALID: './ic-content-valid-tick.svg',
WARNING: './ic-status-warning.svg'
});
Because webpack now knows what could be returned from here it can now hash the name and you can do all sorts of good stuff like optimizing at build time.
so the example class given in my question would be resolved by
import { getIconFromPath } from '../icons/;
class Comp {
this.settingsLinks = [
{
name: 'advanced settings',
icon: getIconFromPath('./ic-settings.svg')
}
]
}
推荐阅读
- javascript - How to make skype like floating window?
- android - Gson parser isnt working with doAsync from Anko in specific cases
- ruby - 即使使用“打印”,也无法在 ruby 的同一行上打印数据。应该使用什么?
- swift - Loading cached remote audio files to AKPlayer on iOS, instead of using local file
- android - JSON Object value assign to a multiple dynamically button
- mongodb - $and and $or from two collections in mongodb
- html - Setting minimum and maximum number of columns using CSS Grid
- javascript - Svg.js 中的同步容器和对象
- react-native - Xcode 10 archive build failed
- spring-boot - Stomp Socket not working in tomcat cluster having 2 instances. I am broadcasting messages using simpMessagingTemplate. This is Not chat application