jwhitley / requirejs-rails

RequireJS support for your Rails 3 or 4 application
MIT License
592 stars 202 forks source link

Per-page modules not compiling #228

Closed benwalsh closed 9 years ago

benwalsh commented 9 years ago

I think I am misunderstanding something about the "Layered builds" section of the docs.

(function () {
  'use strict';
  require(['jquery', 'common'], function () {
    require(['$pages/home'], function (initialize) {
      initialize();
    });
  });
}());
paths:
  $pages: "gr/pages/"
modules:
  - name: "gr-page-home"
  = requirejs_include_tag("gr-page-home")

The problem is that the "page" module is not building/compiling. The requirejs tag appears. The script gr-page-home loads. It tries to load the dependency (the page file) in the browser, but it is not there.

I thought it might have been a reluctance to parse the $pages var so I have tried generating paths: entries that point explicitly to each page file, e.g. page-file-home: "gr/pages/home", but I get the same result.

Any insight into what I'm doing wrong would be much appreciated.

carsomyr commented 9 years ago

@benwalsh You can't just refer to home under $pages/home: Every script needs to be explicitly declared for the precompiler to find.

carsomyr commented 9 years ago

@benwalsh This is failing in production and not development, right?

benwalsh commented 9 years ago

I don't understand -- there is a script gr/pages/home.js. Yes, this is in production (Well, staging, but production-like).

carsomyr commented 9 years ago

@benwalsh paths refers to scripts: It's not a variable. I see now why you're using a dollar sign. If you want to make this stuff work in production for a dynamically generated set of pages, you'll have right a whole bunch of custom discovery logic.

benwalsh commented 9 years ago

We use dollar sign variables for various things which we then expand in the paths: declaration, but I have also tried it without that by pointing to the script in long form, so the JS file is:

(function () {
  'use strict';
  require(['jquery', 'common'], function () {
    require(['gr/pages/home'], function (initialize) {
      initialize();
    });
  });
}());

It makes no difference -- the script still attempts to pull in gr/pages/home.js dynamically instead of precompiling it.

carsomyr commented 9 years ago

@benwalsh You need to add gr/pages/home under modules.

benwalsh commented 9 years ago

I do that, and it works in that it loads gr/pages/home.js. But then it tries to load all of that page's dependencies dynamically, so now I have the same problem, one level down. Is there not a way to get all of the top-level pages to build fully? So that I have a single script that includes all the dependencies?

carsomyr commented 9 years ago

@benwalsh There's a difference between define and require. The former is used for module code: RequireJS will scan for define calls and inline all transitive dependencies during precompilation. The latter is used for application code: Make sure anything you require is listed under modules. It's like the difference between rewriting libraries and using said libraries.

benwalsh commented 9 years ago

Yes, and there are no require statements in the application code, only define statements. So I have created module listings for the pages I am importing with require:

modules:
  - name: "gr-page-home"
  - name: "gr/pages/home"

(and the same for all my other pages)

Now the page pulls in require-xxxxx.js, that pulls in gr-page-home-xxxxx.js, that pulls in the original script file gr/pages/home-xxxx.js page and that tries to pull in all its dependencies -- which are all defined and not required -- dynamically.

benwalsh commented 9 years ago

The question really is how should all these components fit together? I have:

modules:
  - name: "gr-page-home"

etc.

And I create a "wrapper" JS file for each page that looks like:

(function () {
  'use strict';
  require(['jquery', 'common', 'gr/pages/home'], function (_j, _c, initialize) {
    initialize();
  });
}());

I name each of those files accordingly as gr-page-home.js at the top level, and include that file in the HAML code with a requirejs_include_tag.

On deploy and page render, I end up with a require-xxxxx.js script. That imports the gr-page-home-xxxxx.js which seems to have compiled the jquery and common modules, but it imports the file at gr/pages/home.js separately and unchanged, which then keeps trying to import its dependencies dynamically.

"RequireJS will scan for define calls and inline all transitive dependencies during precompilation" -- this is what it is not doing.

benwalsh commented 9 years ago

@carsomyr Ah, so, it turns out that the files were actually compiling and building fine. The issue is with AssetSync which is scanning the assets directory and uploading the source files. Dealing with that is another fun exercise.