rails / webpacker

Use Webpack to manage app-like JavaScript modules in Rails
MIT License
5.3k stars 1.47k forks source link

Images not working ? #918

Closed jerrygreen closed 7 years ago

jerrygreen commented 7 years ago

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?

richardvenneman commented 7 years ago

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;
gauravtiwari commented 7 years ago

@JerryGreen What folder structure you have for your app?

frontend: 
  src: 
  packs: 

like so ?

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

gauravtiwari commented 7 years ago

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

richardvenneman commented 7 years ago

@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.

jerrygreen commented 7 years ago

@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.

gauravtiwari commented 7 years ago

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

gauravtiwari commented 7 years ago

thanks @richardvenneman will take a look later today ๐Ÿ‘

jerrygreen commented 7 years ago

@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!

grothier commented 7 years ago

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/...

richardvenneman commented 7 years ago

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

grothier commented 7 years ago

@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 ?

richardvenneman commented 7 years ago

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

arthwood commented 7 years ago

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.

gauravtiwari commented 7 years ago

@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;
zedtux commented 4 years ago

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
  2. 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


3. Restart webpack
benbonnet commented 3 years ago

@gauravtiwari just had this issue with a 'fresh' rails app (@rails/webpacker 5.2.1); I was expecting to have it working out of the box + I haven't found any specific details about it within the docs (might have missed it though..); is the behaviour normal ? @zedtux setup is working