requirejs / r.js

Runs RequireJS in Node and Rhino, and used to run the RequireJS optimizer
Other
2.57k stars 672 forks source link

Put config before an included loader #842

Open sholladay opened 9 years ago

sholladay commented 9 years ago

Problem

I need to do both of the following and would prefer to make it happen using only r.js (aka, without doing my own file concatenation):

However, I have only been able to achieve the first one (via the r.js include option).

I have tried a few combinations of includeing my own hand written file that does ...

var require = {
    skipDataMain : true
};

... but r.js always puts it below Alameda, regardless of its order in the include array. My hunch here is that r.js is being clever and detecting the presence of Alameda and assuming (in this case, wrongly) that it needs to be at the top. So the config which defines skipDataMain never gets a chance to take effect, because it is defined after Alameda.

Use Case

I have a 3rd-party JavaScript application, which customers load into their pages almost exactly like Disqus or Google Analytics. Let's call my app banana, for sake of discussion.

Customers implement banana like this:

<script type="application/javascript">
    window.banana = window.banana || {};
    // Customer settings.
    banana.config = {
        foo : 'bar'
    };
    (function () {
        var script = document.createElement('script'),
            first  = document.getElementsByTagName('script')[0];
        script.type  = 'application/javascript';
        script.async = true;
        script.src   = 'https://js.banana.com/banana.js';
        first.parentNode.insertBefore(script, first);
    }());
</script>

Hopefully it's obvious that this has a few consequences. I need to use the banana namespace (and I got that working easily), etc. I need to make an optimized banana.js that contains everything essential to start the app, but then also a dynamic loader so I can get code on-demand only when it is needed.

But skipping the data-main logic is crucial because who knows what my customers will be doing.

jrburke commented 9 years ago

r.js hoists the first file that seems to implement an AMD API so that the AMD calls in the other files work. If you try usingonBuildRead and when alameda.js is read, prepend to the file a config that adds the skipDataMain: true value? That snippet you add could also do the work of merging any banana config provided by the site with this local internal config, which I think is what #843 is about. Does that work?

sholladay commented 9 years ago

@jrburke I expanded upon ticket #843 and re-worded it, as I don't think the onbuild callbacks are a clean solution there (think: regex that needs to be maintained in tandem with r.js).

However, for this issue of doing a simple prepend, it's a reasonable solution, so thank you for making me aware of that.

Maybe this is a bug and should be filed separately, but I am seeing onBuildRead be called twice for each file (including Alameda), where I expect it to only be called once, on a very simple setup. Can't find much documentation to support whether this is a bug or not. Thoughts?

sholladay commented 9 years ago

To be clear, I consider this and #843 to be independent of each other. I don't always want to declare a config and prepend it in this way. And the require = banana just generally makes me nervous, which is what that ticket is about. Even if I do intend to define a config like this, a bug on my end could easily lead to a bad scenario because of the behavior in that ticket.