Webpacker: Images not working ?

Created on 9 Oct 2017  路  15Comments  路  Source: rails/webpacker

Main problem:

My images (used in css or imported from js too) are not showing.

My little research:

Here's my manifest.json

{
  "_/_/frontend/src/components/shared/act-card-template/loading.svg": "/packs/_/_/frontend/src/components/shared/act-card-template/loading-6e55ac3085d4cd8651da32d87be226d1.svg",
  "_/_/frontend/src/components/shared/act-card-template/successBlack.svg": "/packs/_/_/frontend/src/components/shared/act-card-template/successBlack-de0a3c628cd7278df54be55bddac8fe2.svg",
  "_/_/frontend/src/components/shared/act-card-template/successGreen.svg": "/packs/_/_/frontend/src/components/shared/act-card-template/successGreen-3c4c4898f2f924212a0a11f69cd7600e.svg",
  "_/_/frontend/src/components/shared/act-card-template/successWhite.svg": "/packs/_/_/frontend/src/components/shared/act-card-template/successWhite-974fc1c1cbe6751ee469923a7ad5514d.svg",
  "_/_/frontend/src/components/shared/act-card/act-content/save-button/starBlack.svg": "/packs/_/_/frontend/src/components/shared/act-card/act-content/save-button/starBlack-b7b4f99072162243573dc36373a40cde.svg",
  "_/_/frontend/src/components/shared/act-card/act-content/save-button/starDark.svg": "/packs/_/_/frontend/src/components/shared/act-card/act-content/save-button/starDark-4173cc2a32cbae7f7c1a607564cc2a4c.svg",
  "_/_/frontend/src/components/shared/act-card/act-content/save-button/starGray.svg": "/packs/_/_/frontend/src/components/shared/act-card/act-content/save-button/starGray-7ef082685573660caa281c9a88782263.svg",
  "_/_/frontend/src/components/shared/act-card/act-content/update-profile/info.svg": "/packs/_/_/frontend/src/components/shared/act-card/act-content/update-profile/info-ca4b7a13cf8b16e9db2d1327cd62b574.svg",
  "_/_/frontend/src/components/shared/act-card/act-content/update-profile/user.svg": "/packs/_/_/frontend/src/components/shared/act-card/act-content/update-profile/user-8fc21994702eeed04eeb0e58f7cf4ff7.svg",
  "_/_/frontend/src/components/shared/avatar/placeholder.png": "/packs/_/_/frontend/src/components/shared/avatar/placeholder-02fc77ef408126c01fe778724da95b8d.png",
  "_/_/frontend/src/components/shared/button/spinner.svg": "/packs/_/_/frontend/src/components/shared/button/spinner-ef0d6a72d27c7ff2dd8a7e44633c4fea.svg",
  "_/_/frontend/src/components/shared/file-uploader/ic-panorama.png": "/packs/_/_/frontend/src/components/shared/file-uploader/ic-panorama-6192af34be4187bad03edcfbfa5b9e32.png",
  "_/_/frontend/src/components/shared/form/checkbox/check-symbol.png": "/packs/_/_/frontend/src/components/shared/form/checkbox/check-symbol-388a21d1895c3d5781347728e0cd878e.png",
  "_/_/frontend/src/components/shared/form/checkbox/facebook.svg": "/packs/_/_/frontend/src/components/shared/form/checkbox/facebook-a7d2e219cf52ddf3f10ae25e051e0012.svg",
  "_/_/frontend/src/components/shared/publish-act-form/facebook.svg": "/packs/_/_/frontend/src/components/shared/publish-act-form/facebook-118108b9b9d25f8a2f57c4ebf067dc03.svg",
  "application.js": "/packs/application-fc48aa5fe166535c7daa.js",
  "check-symbol.png": "/packs/66c38fac9f04cbd261a1809f4d323de9.png",
  "facebook.svg": "/packs/443ce8483351d98a6b3faaff0c734e90.svg",
  "ic-panorama.png": "/packs/9149b6f99e1b25867e8afd956f2f9528.png",
  "info.svg": "/packs/fe9435a22986ed7f6948dbfd15453f34.svg",
  "loading.svg": "/packs/19fd21c1f5f70cc53f44645d5d86bed9.svg",
  "placeholder.png": "/packs/eb2b82c57dda81c9aa7546a27b8399c1.png",
  "server-bundle.js": "/packs/server-bundle-fab377996a7864efcd1d.js",
  "spinner.svg": "/packs/704a7db74ce1094a28330dc4cfb46943.svg",
  "starBlack.svg": "/packs/2a0871cec73ef296adf025627775ef50.svg",
  "starDark.svg": "/packs/d3a436284e6bc71a7aaf468144c8c6a1.svg",
  "starGray.svg": "/packs/a7a12eb5fd39c5d8d977c4d7949c64e2.svg",
  "successBlack.svg": "/packs/5e180ce99100566a005b7ed79f67bce7.svg",
  "successGreen.svg": "/packs/e47d5dddf44ac470c1cdbe94e9bcb74b.svg",
  "successWhite.svg": "/packs/dac311d92504af9685e719d7d2901bd2.svg",
  "user.svg": "/packs/d0ba76249cc2d2190fc7af41258dffbc.svg"
}

(Bold text is an example I will talk about but everything below applies to other images too)

I use my spinner.svg in my css (.styl actually):

background: url('components/shared/act-card-template/spinner.svg') center no-repeat

In browser it looks like:

background: url(/packs/_/_/frontend/src/components/shared/button/spinner-ef0d6a72d27c7ff2dd8a7e44633c4fea.svg) center no-repeat;

Everything is ok right now. We have a strange /_/_/ in url, whatever... BUT LOOK!
If you open this image, you can see there (instead of typical XML/SVG markup) some shit:

(this is ef0d6a72d27c7ff2dd8a7e44633c4fea.svg file)

module.exports = __webpack_public_path__ + "704a7db74ce1094a28330dc4cfb46943.svg";

Of course, this is not an actual image so my image is not showing:
image

Meanwhile, look at basic url (without /_/_/ shit; hello, spinner!):
image

Sorry for a bit of offensive language. But what's wrong with these urls/images?

Most helpful comment

I had the same issue with both react-svg-loader and svg-react-loader so I looked at npm dependents of svg-react-loader. Inspired by https://www.npmjs.com/package/@jacobmischka/gatsby-plugin-react-svg I noticed that svg is on the test list of built in file loader. I modified my config/webpack/environment.js:

const { environment } = require('@rails/webpacker');

const fileLoader = environment.loaders.get('file');

// exclude 'svg' from file loader
fileLoader.test = /\.(jpg|jpeg|png|gif|eot|otf|ttf|woff|woff2)$/i;

environment.loaders.set('svg', {
  test: /\.svg$/,
  exclude: /node_modules/,
  loader: 'svg-react-loader'
});

module.exports = environment;

and all started working.

All 15 comments

I've actually encountered the same issue. I'm trying to import a SVG with the use of react-svg-loader. The file doesn't seem to compile, instead view-sourcing the output shows uncompiled JavaScript:


var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

import React from "react";

var SVG = function (_React$Component) {
_inherits(SVG, _React$Component);

function SVG() {
_classCallCheck(this, SVG);

return _possibleConstructorReturn(this, (SVG.__proto__ || Object.getPrototypeOf(SVG)).apply(this, arguments));

}

_createClass(SVG, [{
key: "render",
value: function render() {
return React.createElement(
"svg",
_extends({ xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 20 20" }, this.props),
React.createElement("path", { d: "M9.5 20c-2.538 0-4.923-.988-6.718-2.782S0 13.038 0 10.501c0-2.538.988-4.923 2.782-6.718S6.962 1 9.5 1c2.538 0 4.923.988 6.718 2.783S19 7.963 19 10.501s-.988 4.923-2.782 6.717A9.438 9.438 0 0 1 9.5 20zm0-18C4.813 2 1 5.813 1 10.5S4.813 19 9.5 19s8.5-3.813 8.5-8.5S14.187 2 9.5 2z" }),
React.createElement("path", { d: "M7.5 14.5a.502.502 0 0 1-.354-.146l-3-3a.5.5 0 0 1 .707-.707l2.646 2.646 6.646-6.646a.5.5 0 0 1 .707.707l-7 7a.498.498 0 0 1-.354.146z" })
);
}
}]);

return SVG;
}(React.Component);

export default SVG;

@JerryGreen What folder structure you have for your app?

frontend: 
  src: 
  packs: 

like so ?

Also, could you post paths from config/webpacker.yml?

@richardvenneman Not sure if yours is related, how is react-svg-loader setup in your app?

@gauravtiwari I created an example repo! https://github.com/richardvenneman/webpacker-react-svg. Please take a look and let me know if you have any remarks.

@gauravtiwari I can tell you an interesting story about my paths 馃槂

Ok, let's start with webpacker.yml (it's almost like default one, just added svg in extensions list):

# Note: You must restart bin/webpack-dev-server for changes to take effect

default: &default
  source_path: app/javascript
  source_entry_path: packs
  public_output_path: packs
  cache_path: tmp/cache/webpacker

  # Additional paths webpack should lookup modules
  # ['app/assets', 'engine/foo/app/assets']
  resolved_paths: []

  #聽Reload manifest.json on all requests so we reload latest compiled packs
  cache_manifest: false

  extensions:
    - .coffee
    - .erb
    - .js
    - .jsx
    - .ts
    - .vue
    - .sass
    - .scss
    - .styl
    - .css
    - .png
    - .svg
    - .gif
    - .jpeg
    - .jpg

development:
  <<: *default
  compile: true

  dev_server:
    host: localhost
    port: 3035
    hmr: false
    https: false

test:
  <<: *default
  compile: true

  # Compile test packs to a separate directory
  public_output_path: packs-test

production:
  <<: *default

  # Production depends on precompilation of packs prior to booting for performance.
  compile: false

  # Cache manifest.json for performance
  cache_manifest: true

So, about the paths... I'm not sure if this taking effect but I have symlinks in my app/javascript/bundles/FrontendComponents. FrontendComponents stores nothing but symlinks to some files of the folder frontend. The folder is lying in root of rails repository (yes, one repository in another, don't ask 馃槃 ), near the folders like app, config, db, etc. These _symlinked_ files are part of another repository so I can't just copy them.

P.S. All I want is to render some dumb components of another app with rails. It's actually worked. But images don't appear.

So, about the paths... I'm not sure if this taking effect but I have symlinks in my app/javascript/bundles/FrontendComponents. FrontendComponents stores nothing but symlinks to some files of the folder frontend. The folder is lying in root of rails repository (yes, one repository in another, don't ask 馃槃 ), near the folders like app, config, db, etc. These symlinked files are part of another repository so I can't just copy them.

Right I see, this seems to be the source of your problem I think since the root directory for assets is app/javascript and that's why you are getting ../../ it's two levels up i.e. under rails root directory.

What you could do is modify this loader in your environment to have process.cwd() as context: https://github.com/rails/webpacker/blob/master/package/loaders/file.js#L11

More documentation here on updating loaders: https://github.com/rails/webpacker/blob/master/docs/webpack.md#overriding-loader-options-in-webpack-3-for-css-modules-etc

thanks @richardvenneman will take a look later today 馃憤

@gauravtiwari holy moly! I solved it (with your help, of course 馃槃). That's my custom webpack config's problem! The paths are good but looks like they're conflicting. That's no symlinks problem.

I had these lines (I copied from another repo when added webpacker):

      {
        test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        use: 'file-loader',
      },

This should be conflicting with default config when merged:

module.exports = merge(environment.toWebpackConfig(), customConfig)

The defaults (that I saw by clicking your link) are handling svgs by itself. So I removed this part:

      {
        test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        use: 'file-loader',
      },

Images are showing now. New manifest.json (just if you interested):

{
  "_/_/frontend/src/components/shared/act-card-template/loading.svg": "/packs/_/_/frontend/src/components/shared/act-card-template/loading-19fd21c1f5f70cc53f44645d5d86bed9.svg",
  "_/_/frontend/src/components/shared/act-card-template/successBlack.svg": "/packs/_/_/frontend/src/components/shared/act-card-template/successBlack-5e180ce99100566a005b7ed79f67bce7.svg",
  "_/_/frontend/src/components/shared/act-card-template/successGreen.svg": "/packs/_/_/frontend/src/components/shared/act-card-template/successGreen-e47d5dddf44ac470c1cdbe94e9bcb74b.svg",
  "_/_/frontend/src/components/shared/act-card-template/successWhite.svg": "/packs/_/_/frontend/src/components/shared/act-card-template/successWhite-dac311d92504af9685e719d7d2901bd2.svg",
  "_/_/frontend/src/components/shared/act-card/act-content/save-button/starBlack.svg": "/packs/_/_/frontend/src/components/shared/act-card/act-content/save-button/starBlack-2a0871cec73ef296adf025627775ef50.svg",
  "_/_/frontend/src/components/shared/act-card/act-content/save-button/starDark.svg": "/packs/_/_/frontend/src/components/shared/act-card/act-content/save-button/starDark-d3a436284e6bc71a7aaf468144c8c6a1.svg",
  "_/_/frontend/src/components/shared/act-card/act-content/save-button/starGray.svg": "/packs/_/_/frontend/src/components/shared/act-card/act-content/save-button/starGray-a7a12eb5fd39c5d8d977c4d7949c64e2.svg",
  "_/_/frontend/src/components/shared/act-card/act-content/update-profile/info.svg": "/packs/_/_/frontend/src/components/shared/act-card/act-content/update-profile/info-fe9435a22986ed7f6948dbfd15453f34.svg",
  "_/_/frontend/src/components/shared/act-card/act-content/update-profile/user.svg": "/packs/_/_/frontend/src/components/shared/act-card/act-content/update-profile/user-d0ba76249cc2d2190fc7af41258dffbc.svg",
  "_/_/frontend/src/components/shared/avatar/placeholder.png": "/packs/_/_/frontend/src/components/shared/avatar/placeholder-eb2b82c57dda81c9aa7546a27b8399c1.png",
  "_/_/frontend/src/components/shared/button/spinner.svg": "/packs/_/_/frontend/src/components/shared/button/spinner-704a7db74ce1094a28330dc4cfb46943.svg",
  "_/_/frontend/src/components/shared/file-uploader/ic-panorama.png": "/packs/_/_/frontend/src/components/shared/file-uploader/ic-panorama-9149b6f99e1b25867e8afd956f2f9528.png",
  "_/_/frontend/src/components/shared/form/checkbox/check-symbol.png": "/packs/_/_/frontend/src/components/shared/form/checkbox/check-symbol-66c38fac9f04cbd261a1809f4d323de9.png",
  "_/_/frontend/src/components/shared/form/checkbox/facebook.svg": "/packs/_/_/frontend/src/components/shared/form/checkbox/facebook-922fc47e2dbe2b38a4a6980218a76e86.svg",
  "_/_/frontend/src/components/shared/publish-act-form/facebook.svg": "/packs/_/_/frontend/src/components/shared/publish-act-form/facebook-443ce8483351d98a6b3faaff0c734e90.svg",
  "application.js": "/packs/application-fc48aa5fe166535c7daa.js",
  "server-bundle.js": "/packs/server-bundle-20558ff34acf5c13ced1.js"
}

Thanks a lot!

Hi ! @richardvenneman did you find out how to load using react-svg-loader ?
I'm struggling with it and still have an Error: Invalid tag:/packs/...

@glevha Unfortunately not! I ended up using kesne/babel-plugin-inline-react-svg

@richardvenneman ok thanks ! I will try this one, you just added

environment.loaders.set('svg', {
  test: /\.svg$/,
  use: 'babel-plugin-inline-react-svg'
})

to your webpack/environment.js and

  "plugins": [
    ...,
    "inline-react-svg"
  ]

to your .babelrc ?

@glevha after installing you'll only need to add it to the plugins section in your .babelrc as you've described :)

I had the same issue with both react-svg-loader and svg-react-loader so I looked at npm dependents of svg-react-loader. Inspired by https://www.npmjs.com/package/@jacobmischka/gatsby-plugin-react-svg I noticed that svg is on the test list of built in file loader. I modified my config/webpack/environment.js:

const { environment } = require('@rails/webpacker');

const fileLoader = environment.loaders.get('file');

// exclude 'svg' from file loader
fileLoader.test = /\.(jpg|jpeg|png|gif|eot|otf|ttf|woff|woff2)$/i;

environment.loaders.set('svg', {
  test: /\.svg$/,
  exclude: /node_modules/,
  loader: 'svg-react-loader'
});

module.exports = environment;

and all started working.

@richardvenneman Apologies for late reply, Could you please try this:

const { environment } = require("@rails/webpacker");
const babelLoader = require("@rails/webpacker/package/loaders/babel");

babelLoader.use = [
  {
    loader: babelLoader.loader,
    options: babelLoader.options
  }
]

delete babelLoader.options
delete babelLoader.loader

environment.loaders.delete('file')
environment.loaders.set("svg", {
  test: /\.svg$/,
  use: babelLoader.use.concat([
    {
      loader: "react-svg-loader",
      options: {
        jsx: true // true outputs JSX tags
      }
    }
  ])
});

module.exports = environment;

Just got this issue too.

Here is what worked for me, based on @arthwood's comment:

  1. Install the svg-react-loader package
yarn add svg-react-loader
  1. Update the config/webpack/environment.js file like so:
const { environment } = require('@rails/webpacker')
const fileLoader = environment.loaders.get('file')

// exclude 'svg' from file loader
fileLoader.test = /\.(jpg|jpeg|png|gif|eot|otf|ttf|woff|woff2)$/i;
environment.loaders.append('svg', {
  test: /\.svg$/,
  exclude: /node_modules/,
  loader: 'svg-react-loader'
})

module.exports = environment
  1. Restart webpack
Was this page helpful?
0 / 5 - 0 ratings