How to change the src attribute of <img> in .vue files with webpack and vue-loader?
Asked Answered
A

4

6

I have a vue.js (version 2.4.4) application built with webpack (version 3.6.0) and vue-loader (version 13.0.5).

In the .vue files, I need to modify the url contained in the src attribute of the <img> tags according to the environment of my application.

  • In the development environment, the images must come from the application folder, with a relative path: "/src/images/exemple.png"
  • In the production environment, the images must come from a cdn, with an absolute path: "https://my-cdn.net/images/exemple.png"

In the "webpack.config.js" file, I already differentiate the different environments using "process.env.NODE_ENV", like this:

const isDev = process.env.NODE_ENV === 'dev';

But I don't know how to modify the src attribute of the img tags in my .vue files with vue-loader (or with something else).

For information, here is the definition of the vue-loader in the "webpack.config.js" file:

{
  test: /\.vue$/,
  loader: 'vue-loader',
  options: {
    loaders: {
      'scss': [
        'vue-style-loader',
        'css-loader',
        'sass-loader'
      ]
    }
  }
}

Is there a simple way to do this?

Aspergillus answered 19/12, 2019 at 16:54 Comment(0)
M
3

Piggybacking off of @Michael Levy's answer:

I am currently having this issue with Vue 3, @vue/cli 4.5.10, and webpack. I've solved it after much research.

Webpack configurations go into vue.config.js, where there is a lot of abstraction. To fine tune control, you can use chain webpack configs. To help you, use Vue Inspect when you are trying to access specific loaders via chaining.

$ vue inspect > output.js

That will give you a nice list of all the loaders that vue-cli is using.

For example - to modify webpack image options within vue.config.js, you can use vue inspect > output.js, search the output.js file, and discover the loader that's managing images.

Which is: /* config.module.rule('images').use('url-loader') */

To answer the question - in your vue.config.js

module.exports = {
  chainWebpack: (config) => {
    config.module
      .rule("images")
      .use("url-loader")
      .tap((options) => {

        options.name = "images/[name].[ext]";
        options.publicPath = isDev ? __webpack_public_path__ : 'https://my-cdn.net/';

        return options;
      });
  },
};

Mcmillin answered 12/1, 2021 at 6:48 Comment(0)
S
2

Vue-loader is preconfigured to handle src attributes in Vue single file components as you can see here. So for example <img src="../image.png"> in the template is transformed into:

createElement('img', {
  attrs: {
    src: require('../image.png') // this is now a module request
  }
})

What Webpack do with this require depends on configured loaders. Usual there is a file-loader configured. It looks like this (from project generated by Vue CLI + simplified):

module: { 
  rules: [
    {
        test: /\.(png|jpe?g|gif|webp)(\?.*)?$/,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: 'img/[name].[hash:8].[ext]'
            }
          }
        ]
      }
  ]
}

Loader is responsible for copying your file into dist directory and returning public URI, which will be inserted into src attribute.

So what you want can be configured here, by specifying right options. For example:

options: {
  name: 'images/[name].[ext]'
  publicPath: isDev ? __webpack_public_path__ : 'https://my-cdn.net/'
}

Just take content of dist/images directory after the build and deploy it so it is accessible by https://my-cdn.net/images and it should work....

Slaveholder answered 19/12, 2019 at 20:22 Comment(0)
B
0

You can create an alias for/src/images and alter the url at transpile time based on the environment:

{
//..
  resolve: {
    alias: {
      '/src/images': isDev ? '/src/images' : process.env.IMAGE_CDN + '/images'
    }
  }
}
Bautram answered 19/12, 2019 at 16:59 Comment(1)
I do not think this is correct answer. Aliases are for resolution only (when webpack is looking for all dependencies)....Keenankeene
A
0

Another way to handle this would be to use DefinePlugin to create a global variable that each of your images reference.

module.exports = {
  chainWebpack: config => {
    console.log('\n')
    console.log('Setting global variables:')
    console.log(`__YOUR_GLOBAL_CONSTANT__: ${JSON.stringify(process.env.YOUR_GLOBAL_CONSTANT)}`)
    console.log('\n')

    config
      .plugin('provide')
      .use(require('webpack').DefinePlugin, [{
        __YOUR_GLOBAL_CONSTANT__: JSON.stringify(process.env.YOUR_GLOBAL_CONSTANT)
      }])
  }
}

The example above is utilizing a vue.config.js file, but the strategy should be pretty similar. Also, if you're using something like eslint, you'll need to specify the variable in the globals section as readonly.

Age answered 19/12, 2019 at 17:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.