mainConfigFile cannot be evaluated correctly #270

Closed
belshire opened this Issue Aug 27, 2012 · 17 comments

Comments

Projects
None yet
8 participants

I'm trying to use the mainConfigFile key in our optimizer script, pointing it to our main file (bootstrap.js). We are using the node.js require module inside a node script to do our optimization and I'm getting the following error:

Error: Error: The config in mainConfigFile website/web/javascript/shell/bootstrap.js 
cannot be used because it cannot be evaluated correctly while running in the optimizer. 
Try only using a config that is also valid JSON, or do not use mainConfigFile and instead 
copy the config values needed into a build file or command line arguments given to the optimizer.

According to the documentation "The first requirejs({}), require({}), requirejs.config({}), or require.config({}) call found in that file will be used." Our main file is using a require({}) call. I've tried every permutation mentioned above and all return the same error. The only thing that doesn't throw this error is a file with a variable holding a json object of the config. Am I missing something?

Owner

jrburke commented Aug 27, 2012

What does the require({}) call look like? It is probably referencing variables that do not work when evaluated outside of a browser context. For instance if you do something like this, it will not work:

requirejs.config({
  baseUrl: location.href
});

Since location is not available in the build environment. Same thing if you use functions to set up part of the config.

That would be the issue, we are referencing some local variables that aren't available in the build environment. Thanks for the quick response.

belshire closed this Aug 27, 2012

rochal commented Feb 5, 2013

Any idea how to handle situation when you actually need to pass a variable into you config file?

For instance, I use this to define the path to the resources:

require.config({

  baseUrl: $app.configuration.mediaDomain + 'scripts/'

  paths: { /* snip */ }
});

My back end populates $app.configuration.mediaDomain which then points to different path depending on the current environment set up (dev/test/staging/production).

The problem I'm having is the same as OPs - how can I pass this variable in OR how can I override baseUrl from mainConfig in the actual build config as this doesn't seem to work:

{
  mainConfigFile: '../app/config.js',

  dir: 'build',

  baseUrl: '../app/scripts/',

 //snip
}

Being able to specify path to your resources dynamically is quite important especially when your html is deployed on different server compared to your javascript. Simple relative paths just won't do and you must pass a variable into the config somehow. It would be great if you didn't have to duplicate the config values in your build config just to support it.

rochal commented Feb 5, 2013

Another example I can think of, in my main application config file:

{
urlArgs: 'c=' + $app.configuration.version
}

Above works perfectly allowing me to load javascript files with cache-busting using current software version. Unfortunately I'm not allowed to use this config file in my build task as mainConfigFile as it fails over because of the "cannot be evaluated correctly" error.

Owner

jrburke commented Feb 5, 2013

@rochal: You could try leaving out the baseUrl in a first require.config() call in the mainConfigFile, as I believe right now the optimizer will only read the first one. Then do a require.config({ baseUrl: ''}) call after that first config call. So, just two config calls in a row. The config values are merged by requirejs.

rochal commented Feb 5, 2013

awesome, that worked. Now in my appconfig.js I've got 2 config segments:

require.config({
  paths: { /*snip*/ },
  shim: { /*snip*/ }
});
require.config({
  baseUrl: $app.configuration.mediaDomain + 'scripts/',
  urlArgs: 'c=' + $app.configuration.version
});

And when my buildconfig.js loads appconfig.js in mainConfigFile, it only picks up the first one.

thanks

@ghost

ghost commented May 24, 2013

Thanks, the second config call worked for me too.

@jrburke Any chance that the original error could be raised? It's a little hard to debug what's wrong with the conf as is.

Owner

jrburke commented Jun 10, 2013

@matthewwithanm that is a bit difficult to do. The error is likely triggered via this line in parse.findConfig:
https://github.com/jrburke/r.js/blob/master/build/jslib/parse.js#L362

but that eval is only of the code segment parsed out of the original file. I am open to someone trying a pull request, but it could take a bit of work to translate the error back to the original source file layout.

Yeah, when I dug into the source I saw what the error was. (Before I had assumed that the whole conf file was eval'd—not just a slice parsed out of it.) I'd love it if the errors were more transparent so I didn't have to go down the rabbit hole and poke around the source whenever there was an error, but I appreciate the complexity in making that happen.

I'm running into this issue as well because I'm trying to set the value of which jQuery to use as described here: http://stackoverflow.com/a/15231699

So I have this:

var jqPath = ('querySelector' in document
    && 'localStorage' in window
    && 'addEventListener' in window) ? 'libs/vendor/jquery/jquery-2.0.3.min' : 'libs/vendor/jquery/jquery-1.10.2.min';

and in my paths:

paths: {
    'jquery': jqPath,

That produces the error. I tried setting it separately in a second require.config call but that didn't work either and produced this error:

Running "requirejs:dist" (requirejs) task

Error: Error: ENOENT, no such file or directory '/Users/mprzybylski/Work/Sapient/2013/sapientnitro/app/js/jquery.js'
In module tree:
main
app

at Object.fs.openSync (fs.js:427:18)

How can I get this working properly?

This fails for me, when I try to run optimizer, can somebody help, how make this work?
var shim = {
'underscore' : {
exports: '_'
}
};

requirejs.config({
paths: {
'underscore' : '../../common/js/libs/underscore/underscore',
},
shim: shim
});

@gghukasyan As I mentioned above, only a small slice of your code is evaluated: the part between the parens in the require.config call. In your case, this won't be valid as it contains a reference to the shim variable which won't be defined (as that part of the code is not evaluated).

Unfortunately, this is certainly somewhat magical and the error reporting doesn't really give much information. The solution is to just make sure that the expression within the parens stands on its own. For example, use an object literal for your shim value. If the shim object needs to be generated programmatically, an IIFE should do the trick though it's admittedly an unexpected hack:

require.config({
...
  shim: (function () {
    // build the shim object here and return it from the function.
  }())
});

@reintroducing That hack should work for you too. (Disclaimer: I haven't actually tried it…I'm just going on my understanding of the config parser.)

@matthewwithanm looks like it worked, thanks (though I tried the same approach, but I was trying to pass the whole config as function and return generated config, but haven't worked).

@gghukasyan Yeah, the parser is looking for an ObjectExpression so that won't match.

sbay commented May 12, 2014

Including the second require call does solve the issue of dynamic variables being properly evaluated.

totty90 commented Jul 24, 2014

I had the same key twice in the config...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment