Thursday, October 8, 2015

mainConfigFile in requirejs

Today I got two errors when do requirejs build.

The first error is:
[Error: Error: ENOENT, no such file or directory 'undefinedjquery.js'
    at Error (native)
]

Googled a while and realized I do something like below in main.js while I use mainConfigFile in Gruntfile.js
var options = {}
require.config(options)
The second error is:
[Error: Error: The config in mainConfigFile /Users/jimz/Workshop/boardUI/trunk/moxtra/site/scripts/app/main.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.

Source error from parsing: /Users/jimz/Workshop/boardUI/trunk/moxtra/site/scripts/app/main.js: ReferenceError: navigator is not defined

This error is more self-descriptive and it means build environment is different from browser context, so navigator is not defined.

From above 2 errors, we should understand two facts about mainConfigFile option. It is used in build environment instead of browser env, so most JavaScript functions will not work. Let's take further study about this.

Sometimes we want to avoid duplicate path/shim mapping using main.js file as configuration file in requirejs through mainConfigFile setting in requirejs build file. The documentation describes as below to clarify this option.

https://github.com/jrburke/r.js/blob/master/build/example.build.js#L27
//By default all the configuration for optimization happens from the command
//line or by properties in the config file, and configuration that was
//passed to requirejs as part of the app's runtime "main" JS file is *not*
//considered. However, if you prefer the "main" JS file configuration
//to be read for the build so that you do not have to duplicate the values
//in a separate configuration, set this property to the location of that
//main JS file. The first requirejs({}), require({}), requirejs.config({}),
//or require.config({}) call found in that file will be used.
//As of 2.1.10, mainConfigFile can be an array of values, with the last
//value's config take precedence over previous values in the array.
mainConfigFile: '../some/path/to/main.js',

https://github.com/jrburke/r.js/issues/270
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.

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.

The typical configuration in main.js looks like below, first config is static, second config is using dynamic with variables and javascript.
require.config({
  paths: { /*snip*/ },
  shim: { /*snip*/ }
});
require.config({
  baseUrl: $app.configuration.mediaDomain + 'scripts/',
  urlArgs: 'c=' + $app.configuration.version
});

No comments:

Post a Comment