Question

I am trying to use requirejs in an Apple TV project. We have a lot of requirejs modules written for web, would be cool if we could re-use them.

Apple TV platform has certain limitations and it's sorta impossible to use requirejs "as is". There's no DOM in common sense. One possible way I found to overcome the problem is: first to load require.js itself and then override its .load() method, so whenever require('foo') gets called it would load foo.js via a simple XHR call:

 requirejs.load = (context, moduleName, moduleUrl) ->
    reqModule = new XMLHttpRequest()
    reqModule.open('GET', appRoot+moduleUrl, true)
    reqModule.send(null)
    reqModule.onreadystatechange = ->
     if reqModule.readyState is 4 and reqModule.status is 200
          fn = (new Function(reqModule.responseText))() # parse module                             
          context[moduleName] = fn
          context.completeLoad(moduleName)

So this works for normally defined modules like this:

  define [], ->
       someField: 'empty field'

Even works for self executing functions like this (with shim configured):

  (myFoo = ->
      someField:"empty field"
  )()

for example Undercore.js contains itself in a self executing wrapper

However, that doesn't work with modules defined like this:

 myFoo = ->
    someField:"empty field"

Question: how can I make it work for all 3 cases? When used in browser, requirejs successfully loads all of them.

One solution I found is to wrap the function in define block for non-wrapped modules like in the last example, so instead of doing fn = (new Function(reqModule.responseText))() I would do:

fn = define [], (new Function("return "+reqModule.responseText))()

But then that would break load for both first and second cases. Is there a way to find out if a function wrapped in a self-executing block or not? How can I distinguish first two cases from the last one?

Was it helpful?

Solution

Using the code in the question as a starting point, I was able to get the following code to work. I don't have Apple TV so I cannot test it on Apple TV. I've tested it in a browser. It is able to load all 3 types of modules you've shown in your question, provided that the 2nd and 3rd modules have appropriate shims. So the logic is sound. The missing piece is what needs to stand in for window in eval.call(window, ...). In Node.js, it would be global. I don't know the equivalent in Apple TV.

  requirejs.load = function(context, moduleName, moduleUrl) {
      var reqModule = new XMLHttpRequest();
      reqModule.open('GET', moduleUrl, true);
      reqModule.send(null);
      return reqModule.onreadystatechange = function() {
          if (reqModule.readyState === 4 && reqModule.status === 200) {
              eval.call(window, reqModule.responseText);
              return context.completeLoad(moduleName);
          }
      };
  };

OTHER TIPS

If I were you, I would use Browserify

Write your browser code with node.js-style requires.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top