New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to get image paths in JSX? #211

Closed
jongbeau opened this Issue Mar 16, 2015 · 29 comments

Comments

Projects
None yet
@jongbeau

jongbeau commented Mar 16, 2015

Is there a way to use rails helpers like asset_path in JSX? If not, what is the best practice for accessing image paths?

@ericdfields

This comment has been minimized.

Show comment
Hide comment
@ericdfields

ericdfields Mar 16, 2015

Typically you've been able to name your file 'my_script.js.erb' and then call interpolated ruby in your code:

var image_path = "<%= asset_path(my_image.png) %>"

I don't see why my_script.js.jsx.erb wouldn't work!

ericdfields commented Mar 16, 2015

Typically you've been able to name your file 'my_script.js.erb' and then call interpolated ruby in your code:

var image_path = "<%= asset_path(my_image.png) %>"

I don't see why my_script.js.jsx.erb wouldn't work!

@ericdfields

This comment has been minimized.

Show comment
Hide comment
@ericdfields

ericdfields Mar 16, 2015

Might also be #{asset_path(my_image.png)}… that's what it was when I was writing coffee, but I assume that was coffeescript syntax.

ericdfields commented Mar 16, 2015

Might also be #{asset_path(my_image.png)}… that's what it was when I was writing coffee, but I assume that was coffeescript syntax.

@bogdan-dumitru

This comment has been minimized.

Show comment
Hide comment
@bogdan-dumitru

bogdan-dumitru Mar 16, 2015

Contributor

This depends a lot on your stack. What @ericdfields mentioned works if you're compiling JSX inside of the rails asset pipeline. If you're using browserify or webpack it's not as straightforward. In the case of browserify what I did for a while is a have a custom preprocessor for the build and a convention to signal that this needs to be processed like:

// ...
render: function() {
  return (
    <img src="%image_path(some_asset_that_rails_knows.png)%" />
  )
}
// ...

This way I would use my custom preprocessor to match /%([a-z]*)_path\((.*)\)%/ and use the proper rails helper with the argument to generate the full asset path and replace that in the build JS.

Nowadays we just use webpack to mange all our frontend assets and it's awesome. Long gone are the days of sprockets :).

Contributor

bogdan-dumitru commented Mar 16, 2015

This depends a lot on your stack. What @ericdfields mentioned works if you're compiling JSX inside of the rails asset pipeline. If you're using browserify or webpack it's not as straightforward. In the case of browserify what I did for a while is a have a custom preprocessor for the build and a convention to signal that this needs to be processed like:

// ...
render: function() {
  return (
    <img src="%image_path(some_asset_that_rails_knows.png)%" />
  )
}
// ...

This way I would use my custom preprocessor to match /%([a-z]*)_path\((.*)\)%/ and use the proper rails helper with the argument to generate the full asset path and replace that in the build JS.

Nowadays we just use webpack to mange all our frontend assets and it's awesome. Long gone are the days of sprockets :).

@ericdfields

This comment has been minimized.

Show comment
Hide comment
@ericdfields

ericdfields Mar 16, 2015

@bogdan-dumitru that sort of preprocessing was a blocker at fully converting our stack to webpack. Thanks for sharing. Still basically running a separate webpack process on dev and then having a compilation step for prod via CI or similar? There's still some gaps in the webpack<>sprockets<>rails relationship in my head.

ericdfields commented Mar 16, 2015

@bogdan-dumitru that sort of preprocessing was a blocker at fully converting our stack to webpack. Thanks for sharing. Still basically running a separate webpack process on dev and then having a compilation step for prod via CI or similar? There's still some gaps in the webpack<>sprockets<>rails relationship in my head.

@jongbeau

This comment has been minimized.

Show comment
Hide comment
@jongbeau

jongbeau Mar 16, 2015

I'm using ES6 and commonJS so I use browserify to do the compiling. Renaming to script.js.jsx.erb was the first thing that I tried and it did not work. Currently, i'm working around this by using a CSS style that sets the content-url. asset_path works fine in the CSS with sprockets.

I have been looking into webpack recently due to the react hot reload feature. How are things working out as a full replacement of sprockets?

jongbeau commented Mar 16, 2015

I'm using ES6 and commonJS so I use browserify to do the compiling. Renaming to script.js.jsx.erb was the first thing that I tried and it did not work. Currently, i'm working around this by using a CSS style that sets the content-url. asset_path works fine in the CSS with sprockets.

I have been looking into webpack recently due to the react hot reload feature. How are things working out as a full replacement of sprockets?

@bogdan-dumitru

This comment has been minimized.

Show comment
Hide comment
@bogdan-dumitru

bogdan-dumitru Mar 17, 2015

Contributor

It's going really good so for, minus some small snafus due to node instability (because of all the moving parts/dependencies). But it's really interesting. I'm working on a blog post about this so I'll keep you guys posted.

Contributor

bogdan-dumitru commented Mar 17, 2015

It's going really good so for, minus some small snafus due to node instability (because of all the moving parts/dependencies). But it's really interesting. I'm working on a blog post about this so I'll keep you guys posted.

@vipulnsward

This comment has been minimized.

Show comment
Hide comment
@vipulnsward

vipulnsward Mar 17, 2015

Contributor

I do what @jongbeau mentioned. Setting a url from style is easier and cleaner.
Another way is passing around the values from data attributes, or generated and passed from props.
In later case, helpers are freely available when generating props, so it shouldn't be an issue.

Contributor

vipulnsward commented Mar 17, 2015

I do what @jongbeau mentioned. Setting a url from style is easier and cleaner.
Another way is passing around the values from data attributes, or generated and passed from props.
In later case, helpers are freely available when generating props, so it shouldn't be an issue.

@andyyou

This comment has been minimized.

Show comment
Hide comment
@andyyou

andyyou Jun 2, 2015

Thanks @ericdfields , I also think if you are using react-rails that its a easiest way to solve this problem.

andyyou commented Jun 2, 2015

Thanks @ericdfields , I also think if you are using react-rails that its a easiest way to solve this problem.

@hongkim91

This comment has been minimized.

Show comment
Hide comment
@hongkim91

hongkim91 Jul 17, 2015

@bogdan-dumitru Did you end up writing that blog post? I'd be interested in learning about your experience.

hongkim91 commented Jul 17, 2015

@bogdan-dumitru Did you end up writing that blog post? I'd be interested in learning about your experience.

@andyyou

This comment has been minimized.

Show comment
Hide comment
@andyyou

andyyou Jul 20, 2015

In fact, it's just a bit trick and not prefect solution, I thought. You can append extension .erb to js(jsx) file and then you can use the ability of erb, but not all of helpers you can use.

andyyou commented Jul 20, 2015

In fact, it's just a bit trick and not prefect solution, I thought. You can append extension .erb to js(jsx) file and then you can use the ability of erb, but not all of helpers you can use.

@mikesea

This comment has been minimized.

Show comment
Hide comment
@mikesea

mikesea Aug 13, 2015

Contributor

If you're just using the asset pipeline, I found a solution.

This does not work:

render: function() {
  return (
    <img src="<%= asset_url('path/to/image.png') %>" />
  )
}

This did work (wrap the src prop in braces):

render: function() {
  return (
    <img src={"<%= asset_url('path/to/image.png') %>"} />
  )
}
Contributor

mikesea commented Aug 13, 2015

If you're just using the asset pipeline, I found a solution.

This does not work:

render: function() {
  return (
    <img src="<%= asset_url('path/to/image.png') %>" />
  )
}

This did work (wrap the src prop in braces):

render: function() {
  return (
    <img src={"<%= asset_url('path/to/image.png') %>"} />
  )
}
@j0214ack

This comment has been minimized.

Show comment
Hide comment
@j0214ack

j0214ack Aug 28, 2015

Why not

render: function() {
  return (
    <img src={this.props.img_src} />
  )
}

and then in your erb

render_component('Component', img_src: image_url('the_path'))

this way also makes the component more reusable I suppose

j0214ack commented Aug 28, 2015

Why not

render: function() {
  return (
    <img src={this.props.img_src} />
  )
}

and then in your erb

render_component('Component', img_src: image_url('the_path'))

this way also makes the component more reusable I suppose

@bcardiff

This comment has been minimized.

Show comment
Hide comment
@bcardiff

bcardiff Sep 24, 2015

@mikesea suggestion works, but since I am using es6 the file needed to be named *.es6.jsx.erb. And the enclosing {...} were not needed.

class MyImage extends React.Component {
  render () {
    return (
      <img src="<%= asset_url('path/to/image.png') %>" />
    );
  }
}

bcardiff commented Sep 24, 2015

@mikesea suggestion works, but since I am using es6 the file needed to be named *.es6.jsx.erb. And the enclosing {...} were not needed.

class MyImage extends React.Component {
  render () {
    return (
      <img src="<%= asset_url('path/to/image.png') %>" />
    );
  }
}
@arkhamRejek

This comment has been minimized.

Show comment
Hide comment
@arkhamRejek

arkhamRejek Dec 17, 2015

you guys are awesome ! I was ripping my hair trying to figure this out

arkhamRejek commented Dec 17, 2015

you guys are awesome ! I was ripping my hair trying to figure this out

@chalmagean

This comment has been minimized.

Show comment
Hide comment
@chalmagean

chalmagean Jan 19, 2016

Another thing you might prefer is to pass down the asset paths as props, or just use a global object that holds the paths to every asset.

That might look something like this:

# app/controllers/some_controller.rb
def some_action
  @images = {
    oneIcon: path_to_asset('one_icon.png'),
    twoIcon: path_to_asset('two_icon.png')
  }
end

private

  def path_to_asset(asset)
    ApplicationController.helpers.asset_path(asset)
  end
# app/views/some_controller/some_action.html.erb
<%= tag :div, data: { images: @images }, id: "root" %>
# app/assets/javascripts/app.js.jsx
var rootElement = document.getElementById("root");
var imagePaths = JSON.parse(rootElement.dataset.images);

window.ReactDOM.render(
  <MainComponent imagePaths={imagePaths} />
  rootElement
);

chalmagean commented Jan 19, 2016

Another thing you might prefer is to pass down the asset paths as props, or just use a global object that holds the paths to every asset.

That might look something like this:

# app/controllers/some_controller.rb
def some_action
  @images = {
    oneIcon: path_to_asset('one_icon.png'),
    twoIcon: path_to_asset('two_icon.png')
  }
end

private

  def path_to_asset(asset)
    ApplicationController.helpers.asset_path(asset)
  end
# app/views/some_controller/some_action.html.erb
<%= tag :div, data: { images: @images }, id: "root" %>
# app/assets/javascripts/app.js.jsx
var rootElement = document.getElementById("root");
var imagePaths = JSON.parse(rootElement.dataset.images);

window.ReactDOM.render(
  <MainComponent imagePaths={imagePaths} />
  rootElement
);
@pioz

This comment has been minimized.

Show comment
Hide comment
@pioz

pioz Feb 1, 2016

In my app/assets/javascripts/components/navbar.js.jsx.erb I can write something like this:

    render() {
      return(
        <div className="navbar-header">
          <button className="navbar-toggle collapsed" data-target="#navbar-collapse" data-toggle="collapse" type="button">
            <span className="sr-only">
              <%= I18n.t('menu.toggle_navigation') %>
            </span>
            <span className="icon-bar"></span>
            <span className="icon-bar"></span>
            <span className="icon-bar"></span>
          </button>
          <ul>
            <li>
              <%= link_to root_path, className: 'navbar-brand' do %>
                <span className='glyphicon glyphicon-home'></span>
                &nbsp;
                <%= I18n.t('menu.now') %>
              <% end %>
            </li>
            <li><%= link_to I18n.t('menu.archive'), archive_path%></li>
          </ul>
        </div>
      );
    }

All works fine except for the link_to with block... I have a syntax error: syntax error, unexpected keyword_end, expecting ')'
If I remove the block all works fine.
Any idea?

pioz commented Feb 1, 2016

In my app/assets/javascripts/components/navbar.js.jsx.erb I can write something like this:

    render() {
      return(
        <div className="navbar-header">
          <button className="navbar-toggle collapsed" data-target="#navbar-collapse" data-toggle="collapse" type="button">
            <span className="sr-only">
              <%= I18n.t('menu.toggle_navigation') %>
            </span>
            <span className="icon-bar"></span>
            <span className="icon-bar"></span>
            <span className="icon-bar"></span>
          </button>
          <ul>
            <li>
              <%= link_to root_path, className: 'navbar-brand' do %>
                <span className='glyphicon glyphicon-home'></span>
                &nbsp;
                <%= I18n.t('menu.now') %>
              <% end %>
            </li>
            <li><%= link_to I18n.t('menu.archive'), archive_path%></li>
          </ul>
        </div>
      );
    }

All works fine except for the link_to with block... I have a syntax error: syntax error, unexpected keyword_end, expecting ')'
If I remove the block all works fine.
Any idea?

@bcardiff

This comment has been minimized.

Show comment
Hide comment
@bcardiff

bcardiff Feb 1, 2016

@pioz not sure, but probably you reach something erb vs rails-erb around http://www.timelessrepo.com/block-helpers-in-rails3 . You may try to use a block with { ... } in the link_to instead of breaking it in multiple <% %>.

But that is just the tip of the iceberg. Rails helpers output html and not jsx-html. So class/className. for/htmlFor, etc attributes need to be translated. And you won't be able to use interpolation with jsx expression attr={...}, since they will be quoted attr="{...}". Knowing that, if those restriction are fine, go for it :-)

bcardiff commented Feb 1, 2016

@pioz not sure, but probably you reach something erb vs rails-erb around http://www.timelessrepo.com/block-helpers-in-rails3 . You may try to use a block with { ... } in the link_to instead of breaking it in multiple <% %>.

But that is just the tip of the iceberg. Rails helpers output html and not jsx-html. So class/className. for/htmlFor, etc attributes need to be translated. And you won't be able to use interpolation with jsx expression attr={...}, since they will be quoted attr="{...}". Knowing that, if those restriction are fine, go for it :-)

@gwong89

This comment has been minimized.

Show comment
Hide comment
@gwong89

gwong89 Feb 12, 2016

so if im compiling with webpack, which solution from these posts would work?

gwong89 commented Feb 12, 2016

so if im compiling with webpack, which solution from these posts would work?

@varun-raj

This comment has been minimized.

Show comment
Hide comment
@varun-raj

varun-raj Mar 1, 2016

Store it in a JS variable and use it

varun-raj commented Mar 1, 2016

Store it in a JS variable and use it

@TxsAdamWest

This comment has been minimized.

Show comment
Hide comment
@TxsAdamWest

TxsAdamWest Sep 11, 2016

I am having an issue with the src path... Console reads a bunch of 404 errors for each of the img's. Is there something wrong with my formatting or pathing ?

<img src={'../images/jesseleach.jpg'} />

screen shot 2016-09-11 at 11 35 44 am

TxsAdamWest commented Sep 11, 2016

I am having an issue with the src path... Console reads a bunch of 404 errors for each of the img's. Is there something wrong with my formatting or pathing ?

<img src={'../images/jesseleach.jpg'} />

screen shot 2016-09-11 at 11 35 44 am

@varun-raj

This comment has been minimized.

Show comment
Hide comment
@varun-raj

varun-raj Sep 12, 2016

@TxsAdamWest are you using it in a rails project?

varun-raj commented Sep 12, 2016

@TxsAdamWest are you using it in a rails project?

@TxsAdamWest

This comment has been minimized.

Show comment
Hide comment
@TxsAdamWest

TxsAdamWest Sep 12, 2016

No, JavaScript. I think what I was doing wrong was the img src paths
needed to be in curly braces. They wouldn't read otherwise..

On Sep 12, 2016 1:26 AM, "Varun Raj" notifications@github.com wrote:

@TxsAdamWest https://github.com/TxsAdamWest are you using it in a rails
project?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#211 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/APQ1z6hqF49J2uqtkuSpMRmY6AW6tfbgks5qpPCrgaJpZM4DvWU0
.

TxsAdamWest commented Sep 12, 2016

No, JavaScript. I think what I was doing wrong was the img src paths
needed to be in curly braces. They wouldn't read otherwise..

On Sep 12, 2016 1:26 AM, "Varun Raj" notifications@github.com wrote:

@TxsAdamWest https://github.com/TxsAdamWest are you using it in a rails
project?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#211 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/APQ1z6hqF49J2uqtkuSpMRmY6AW6tfbgks5qpPCrgaJpZM4DvWU0
.

@bcardiff

This comment has been minimized.

Show comment
Hide comment
@bcardiff

bcardiff Sep 12, 2016

@TxsAdamWest the problem is that the paths probably don't work from the url you are loading the scripts and that is why you get 404. This whole thread is about rendering absolute paths in the views that in production will have the fingerprint. You are using relative paths, that although it might seems right from the actual file location, when rendering from / or /:controller/:action they will fail at least in one.

bcardiff commented Sep 12, 2016

@TxsAdamWest the problem is that the paths probably don't work from the url you are loading the scripts and that is why you get 404. This whole thread is about rendering absolute paths in the views that in production will have the fingerprint. You are using relative paths, that although it might seems right from the actual file location, when rendering from / or /:controller/:action they will fail at least in one.

@vkhang55

This comment has been minimized.

Show comment
Hide comment
@nextofsearch

This comment has been minimized.

Show comment
Hide comment
@nextofsearch

nextofsearch Nov 10, 2016

Hi,

I am using Rails 5 with react-rails and browserify-rails gems and I can't figure out how to get image tag working with asset pipeline. It seems that browserify-rails take precedence over .js files so there is no chance for Rails process .erb syntax in .js.jsx. Can someone help to use both gems and figure out how to use asset pipeline successfully?

browserify-rails/browserify-rails#48 (comment)

nextofsearch commented Nov 10, 2016

Hi,

I am using Rails 5 with react-rails and browserify-rails gems and I can't figure out how to get image tag working with asset pipeline. It seems that browserify-rails take precedence over .js files so there is no chance for Rails process .erb syntax in .js.jsx. Can someone help to use both gems and figure out how to use asset pipeline successfully?

browserify-rails/browserify-rails#48 (comment)

@lakesare

This comment has been minimized.

Show comment
Hide comment
@lakesare

lakesare Dec 8, 2016

Appending erb to form js.jsx.erb worked. Now I'm using ES6 and can use:

<section>
    <%= image_tag 'common/star.svg' %>
    {reviews}
</section>

lakesare commented Dec 8, 2016

Appending erb to form js.jsx.erb worked. Now I'm using ES6 and can use:

<section>
    <%= image_tag 'common/star.svg' %>
    {reviews}
</section>
@rmosolgo

This comment has been minimized.

Show comment
Hide comment
@rmosolgo

rmosolgo Dec 9, 2016

Member

Thanks for sharing all your solutions here! I don't think there's anything particularly required from this gem, so I'll close this issue.

Member

rmosolgo commented Dec 9, 2016

Thanks for sharing all your solutions here! I don't think there's anything particularly required from this gem, so I'll close this issue.

@rmosolgo rmosolgo closed this Dec 9, 2016

@aurimus

This comment has been minimized.

Show comment
Hide comment
@aurimus

aurimus Mar 12, 2017

My sprockets 4.0.0beta4 simply does not include the file (does not see it) if I change the ending to .js.jsx.erb, works fine with js.jsx. Any ideas?

aurimus commented Mar 12, 2017

My sprockets 4.0.0beta4 simply does not include the file (does not see it) if I change the ending to .js.jsx.erb, works fine with js.jsx. Any ideas?

@liamm12

This comment has been minimized.

Show comment
Hide comment
@liamm12

liamm12 Jan 5, 2018

If you have a few images you can just import it directly in your component like this

import logo from './Pictures/1.jpg';

Then call it like this

<img src={logo} alt="logo" width={"240"} height={"240"}  />

If you want to get multi images like more than 50 img in own component, my own way to do that to specify each component has a images.js file,and then you can just import all the images that retarded of that component in images.js and name it as the related component name

(It will let you know what this images file for.)

As I prefer to keep all your images in public folder

images.js

import logo from './images/logo.svg';
import cover from './images/cover.svg';
import profile from './images/profile.svg';
import background1 from './images/body.svg';
export default {
    logo,
    cover,
    profile,
    background1
}

Then in your component you can just import images.js file like this, you can name it whatever you want

import images from './images';

Then you can call any img you want like this

      <img src={images.logo} className="App-logo" alt="logo" />
      <img src={images.cover} className="App-logo" alt="logo" />
      <img src={images.profile} className="App-logo" alt="logo" />
      <img src={images.background1} className="App-logo" alt="logo" />

liamm12 commented Jan 5, 2018

If you have a few images you can just import it directly in your component like this

import logo from './Pictures/1.jpg';

Then call it like this

<img src={logo} alt="logo" width={"240"} height={"240"}  />

If you want to get multi images like more than 50 img in own component, my own way to do that to specify each component has a images.js file,and then you can just import all the images that retarded of that component in images.js and name it as the related component name

(It will let you know what this images file for.)

As I prefer to keep all your images in public folder

images.js

import logo from './images/logo.svg';
import cover from './images/cover.svg';
import profile from './images/profile.svg';
import background1 from './images/body.svg';
export default {
    logo,
    cover,
    profile,
    background1
}

Then in your component you can just import images.js file like this, you can name it whatever you want

import images from './images';

Then you can call any img you want like this

      <img src={images.logo} className="App-logo" alt="logo" />
      <img src={images.cover} className="App-logo" alt="logo" />
      <img src={images.profile} className="App-logo" alt="logo" />
      <img src={images.background1} className="App-logo" alt="logo" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment