Skip to content
This repository has been archived by the owner on Mar 23, 2024. It is now read-only.

Assets being fetched without .js extension #65

Closed
auchenberg opened this issue Sep 3, 2012 · 15 comments
Closed

Assets being fetched without .js extension #65

auchenberg opened this issue Sep 3, 2012 · 15 comments

Comments

@auchenberg
Copy link

Hi,

I'm seing some really weird behaviour after upgrading to RequireJS 2.0, where assets that is outputted as "http://podio.dev/piped_assets/files_main-60bf86d78bb6e7fe62ece58006df4614" in the configuration, is being fetched without the .js file extension

This seems to have changed in RequireJS 2.0, and I can see that you are stripping out .js in file extension in the updated version of this gem (453089f).

Anyone else having these problems?

@erickreutz
Copy link

I just ran into this same problem.

@afroald
Copy link

afroald commented Sep 21, 2012

Me too. Have you found a solution yet?

@jbwyme
Copy link

jbwyme commented Oct 3, 2012

Also have this issue. Note that I am using RequireJS 2.0.6 using this branch https://github.com/Appboy/requirejs-rails so that running r.js doesn't break jQuery.

@jbwyme
Copy link

jbwyme commented Oct 3, 2012

John, glad to see you back! Any ideas on why this may be happening? It works fine in developer mode but after running the precompile and going to production mode, it tries to fetch the main-(md5hash).js file WITHOUT the .js extensions and therefore fails. The only solution I have so far is manually copying main-(md5hash).js to main-(md5hash). Once this is solved I'll be ready for a production deploy :)


Edit:

I've been attempting to debug this issue and have found that if edit the rjs_manifest.yml file entry to specify the .js extension TWICE it will then be loaded properly. Therefore, it seems the .js is just being stripped inappropriately. More to follow....


Edit 2:

Here are some more observations. Keep in mind I'm pretty new to rails to I'm still wrapping my head around some of the basics in the asset pipeline.

IN DEV MODE: - requirejs_include_tag "application" results in <script type="text/javascript" charset="utf-8" async="" data-requirecontext="_" data-requiremodule="/assets/application" src="/assets/application"></script> being injected once requirejs is loaded. This works because it falls back to the asset pipeline and finds the application.js file in the pipeline even though the actual HTTP request is to /assets/application

IN PROD MODE: - requirejs_include_tag "application" results in <script type="text/javascript" charset="utf-8" async="" data-requirecontext="_" data-requiremodule="/assets/application-f8162cdab722294e4c3e28e95d61cea3" src="/assets/application-f8162cdab722294e4c3e28e95d61cea3"></script> being injected once requirejs is loaded. This DOES NOT WORK because a) that file doesn't exist in the pipeline and b) more importantly, production mode (in my config) has config.assets.compile set to false and therefore only uses pre-compiled files.


Edit 3: Temporary Workaround

I decided to just skip the requirejs_include_tag all together and just manually include require.js and application.js using the javascript_include_tag function. Then I just put my config in the js file like traditional requirejs.

application.html.erb:
---
<%= javascript_include_tag "require" %>
<%= javascript_include_tag "application" %>
----

application.js:
---
require.config({
    baseUrl : "/assets/",
    paths: {
        jquery: 'https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min' ,
        jquerymobile: 'https://ajax.aspnetcdn.com/ajax/jquery.mobile/1.1.1/jquery.mobile-1.1.1.min',
        facebooklib: "https://connect.facebook.net/en_US/all",
        jqmconfig: 'conf/JQMConfig',
        underscore: 'underscore-min',
        backbone: 'backbone-0.9.2',
        text: 'text',
    },
    shim:  {
        backbone: {
            deps: ["jquery", "underscore"],
            exports: "Backbone"
        },
        underscore: {
            exports: "_"
        },
        jquery: {
            exports: "$"
        },
        jquerymobile : {
            deps: ["jquery", "jqmconfig"]
        }
    }
})

require([
    'jquery',    
    'jquerymobile', 
    'underscore',
    'backbone',  
    'facebooklib',
    'App'
], function($, jqmobile, _, Backbone, FB, App){
    App.initialize();
});
---

@jpurcell001
Copy link

We were running into this issue as well. Nto sure what the best solution is but think it is based on logic in require.js:

  • The rails requirejs_include tag defines the require global variable containing configuration before the requirejs library is loaded and initialized. This configuration includes a setting for baseUrl (in our case it was set to /assets)
  • The value for data-main in the requirejs script tag had the .js stripped but included the full path - in our case it was set to something like <script data-main="/assets/application-1d7bf7250e52cfd6cd0b69de59f2a6c8" src="/assets/require-035c6751f5a063d9bbf193f3d8b90ad3.js"></script>.
  • The logic in require.js around data-main only pulls off the parent path information from data-main if baseUrl was not defined in the configuration (which, in the case of requirejs-rails generated config, it was defined). Since the .js extension is not present - in which case I think require.js would have just loaded this as a file rather than as a relative module name - then this is viewed as a module name, and it shouldn't include this parent path.
  • I worked around this by adding a line in the requirejs tag helper to delete the baseUrl key - this way, requirejs takes over and infers the baseUrl based on the path included in data-main. (At line 41 of app/helpers/requirejs_helper.rb, inserted run_config.delete "baseUrl"). There are probably other ways to work around this - I think I could also have added a '.js' extension to the path referred to in data-main, and there is also probably a fix or enhancement that could be made to require.js to accomodate. But, this workaround seemed to work - we tried in both dev and in production mode (after a r.js rake assets:precompile) and everything is functional - which was not the case before.

Ideally somebody who understands require.js and requirejs-rails will be able to come up with a more robust solution, but hopefully this helps them track down the root cause.

@ptyagi16
Copy link

This is a bug but has a simple workaround. Change your requirejs_include tag from

requirejs_include_tag("mymain")

to

requirejs_include_tag{"mymain").sub("/assets/mymain","mymain")

If you are interested in why this is a bug and why workaround works, read on. In RequireJS 2.0.x the data-main is treated like any other module that requirejs loads. Also RequireJS uses the path specified in the data-main to set the baseUrl if one is not specified in the config. Now RailsRequireJS does all the work for us including setting the baseURL in config to "/asset". You can see that in the HTML page source in production. It would look something like this:

 <script>var require = {"baseUrl":"/assets","paths":{"mymain":"/assets/mymain-3f6154ab7d ..."

But the rails-requirejs incorrectly emits the data-main with "/assets/" prepended to it

<script data-main="/assets/mymain-3f6154ab7d...js" src="/assets/require-b4a3df ...js"> // wrong
// should be this
<script data-main="mymain-3f6154ab7d...js" src="/assets/require-b4a3df ...js"> // correct

The data-main in require.js include should not have a leading path (as explained in updated requirejs documentation). Because RequireJS treats it as an asset and not a module, it does not append ".js" when fetching it and worse it will not try to resolve it.

We just strip out the leading "/assets/" and it will work for dev and production with cache-busted names.

@beagleknight
Copy link

@ptyagi16 is right but I needed to use this code:

requirejs_include_tag{"mymain").gsub("/assets/mymain","mymain").html_safe

parknicker added a commit to parknicker/requirejs-rails that referenced this issue Dec 9, 2012
@jwhitley
Copy link
Owner

jwhitley commented Jan 5, 2013

I believe this should be fixed on master now. Would someone encountering this issue care to give that a quick spin and report back?

@jpurcell001
Copy link

Gave 0.9.1 a spin, problem still existed.
Gave master a spin, problem seems to have gone away - '/assets/' no longer prepends the data-main attribute.

Thanks!

@cloud8421
Copy link

Hello,

I can report the original issue (asset fetched without the .js extension) agains version 0.9.1.

My code looks like this:

  requirejs_include_tag("front")

This triggers the right baseUrl configuration, but the generated output for the requirejs javascript tag uses the path itself, so it looks like something along the lines of:

 <script data-main="/assets/front-3ace647c506ca6c582c7c01e93f847bf" src="/assets/require-5b3533f569958a108cf68c7f718c48ef.js"></script>

This is a problem because it misses the .js extension, however as explained by @ptyagi16 we're loading a module, so a clean workaround is to override the data-main attribute and request the front module, defined in the configuration that is printed a few lines above. Here's a sample from the conf (shortened):

var require = {"baseUrl":"/assets","paths":{"front":"/assets/front-3ace647c506ca6c582c7c01e93f847bf"};

Here's the workaround:

<%=
  requirejs_include_tag("front") do |controller|
    { 'main' => 'front' }
  end
%>

The workaround simply overrides the data-main attribute and uses a module name instead of the path, as explained above. I'd appreciate a feedback on this and I'd like to know if there's a reason why this isn't done by default (using the module name instead of the path). Thanks!

@krokhale
Copy link

krokhale commented Jan 7, 2013

Upgraded to 0.9.1 and i can confirm, the problem still exists, though as @jpurcell001 pointed out, works on master.

@jmaicher
Copy link

jmaicher commented Jan 9, 2013

I ran into the same problem and can confirm it's gone in the current master.
However, I have some questions for clarification.

My temporary fix looked like this: https://github.com/jmaicher/requirejs-rails/commit/903b3d0da91cc7a64b151f7ff0618aa5aa40306c

From what I know we're always referring to a module in the data-main attribute, right?
And paths for modules are already correctly defined in the generated requirejs configuration.
Can't we then just use the plain module name as I did in my temporary fix like this:

<script>
  var require = {"baseUrl":"/assets","paths":{"main":"/assets/main-d05ead5426af046bb15e96087f4d5f9d"}};
</script>
<script data-main="main" src="/assets/require-7a3e25721d9b587a9f08f003d50193af.js"></script>

Or am I missing something?

@jwhitley Great see you working again on this gem!!

@anselmo
Copy link

anselmo commented Jan 10, 2013

solved with:
= requirejs_include_tag('your_main_module_here'){ |c| {'main' => 'your_main_module_here'} }

@Breefield
Copy link

I just upgraded to Ruby 2.0 so my gemset had to be re-installed. I think my in-use version of require-rails changed from 0.9.0 to 0.9.1, causing this bug (the file is not automatically appended with .js when requested in production).

Rolling back:

gem 'requirejs-rails', '0.9.0'

fixed this problem, and now my assets are retrieved from S3 (asset_sync) correctly.

@carsomyr
Copy link
Collaborator

All, I think this problem is fixed, as the gem now detects whether assets are eligible for precompilation.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests