Require.js optimizer and variables in paths - javascript

I have a problem getting r.js to work the way we need it to.
I have the following problem: We have 2 domains (e.g. foo.de and bar.de) and different environments. Depending on what environment and what domain they are running on they need to load a different file from their origin servers. My initial solution was this:
// channelDomain and environmentPath get defined above this script
require.config({
paths: {
'fooscript': channelDomain+environmentPath
}
}
Testing this in the browser unoptimized works exactly as it should but the nightly build complained with:
[Error: Error: The config in mainConfigFile /absolute/path/app/public/js/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: /absolute/path/app/public/js/main.js: ReferenceError:
channelDomain is not defined
I tried doing lots of things but I'm running out of ideas. I tried doing the empty: thing in the build file but that didn't work either. I'd be glad if someone could point me into the right direction.

Use two require.config in the same file. The optimizer will only read the first one, as James says here https://github.com/jrburke/r.js/issues/270#issuecomment-13112859, and it will work in the browser after optimization.
So at the end you will have something like this in main.js:
require.config({
//only configurations needed for the transpiler's optimization
});
require.config({
paths: {
'fooscript': channelDomain+environmentPath
}
});

Related

Require file on runtime & unit test issue

I use require.js to load files at runtime like following
This is working as expected when I run the file in the right context(I mean when the call is coming from the right path.)
module1.js
define(["otherModule"], function(otherModule) {
working!!!
....
Now I want to create some unit test to this file (module1) from
other context (from folder of tests which is found in diffrent location in the project) and I get error
require.js:145 Uncaught Error: Script error for: otherModule
Since it tries to run the get on this path during the Unit Test
which is located in diffrent project structure ...
https://app/path1/path2/path3/otherModule.js
And in runtime which works (from different context) it find it in the path
https://app/path1/path2/path3/path4/path5/otherModule.js
There is additional path4 & path5 in the request that works,
How should I solve it to work on both cases (UT/Runtime) ?
http://requirejs.org
I think you should be able to get it working by applying a RequireJS configuration file, so that the module name is abstracted from its path:
E.g. in the test context, call something like this as initialization step:
require.config({
baseUrl: "/path1/path2/path3"
});
Alternatively, you can also remap single modules like so (this can also be used to inject a different implementation of a specific module for testing etc.):
require.config({
paths: {
"otherModule": "/path1/path2/path3/otherModule"
}
});
See here: http://requirejs.org/docs/api.html#config

RequireJS tries to load webpack externals

Using Webpack, I'm exporting two distribution files for a project. One with dependencies bundled and one without.
Throughout the application, we use commonjs require('lodash.assign'); includes which webpack understands.
However, I've configured one of our builds to ignore these (for users who already use lodash and have it available).
externals = {
'lodash.assign': 'var _.assign',
'lodash.clonedeep': 'var _.cloneDeep'
};
This works as expected. However, because our libraryTarget is umd we support RequireJS. However, RequireJS still actually thinks these files should be loaded and I'm seeing a ton of errors:
require.min.js:1 GET http://127.0.0.1/_.assign.js req.load
# Uncaught Error: Script error for "_.assign"
It can't figure out where to find script. How can I configure webpack, or even requirejs to ignore these, since they're being mapped by webpack?
By looking at the compiled output, I see the reason requirejs thinks it's supposed to load these files:
define(["_.assign", "_.cloneDeep"], factory);
When I manually modify code to the following, it works:
define(['lodash'], factory);

Why don't relative imports with AMD work in requirejs?

So, if you have a folder:
- demo/js/foo/foo.js
- demo/js/foo/bar/a.js
- demo/js/foo/bar/b.js
Then defining an AMD module's as:
foo.js: define(['./bar/a.js', './bar/b.js'], function(a, b) { console.log(a, b); });
a.js: define([], function() { return {a:'a'}; });
b.js: define([], function() { return {b:'b'}; });
Then if you import the module like this:
require(['./foo/foo'], function() { ... }
Gives:
"NetworkError: 404 Not Found - http://localhost:3005/demo/foo/bar/a.js"
"NetworkError: 404 Not Found - http://localhost:3005/demo/foo/bar/b.js"
Error: Script error for: foo/bar/a.js http://requirejs.org/docs/errors.html#scripterror
Error: Script error for: foo/bar/b.js http://requirejs.org/docs/errors.html#scripterror
Why doesn't this work?
I've read some obscure posts in the requirejs forum saying this is 'working as intended' because 'imports are names, they are not relative paths'. ...and that you should resolve this issue using the 'map' function.
...
Right! Well, I won't go in to how obvious this behavior is, or how vastly unhelpful threads like https://groups.google.com/forum/#!searchin/requirejs/relative/requirejs/Zmh7EV5fR2M/4OM-ss5g3DEJ are; let's just get to the point.
How are you supposed to make this work?
Obviously if you import an arbitrary module using bower, and it lives in say, js/lib/obscure.js/dist/obscure.js you need to setup your config:
require.config({
paths: {
obscure: 'lib/obscure.js/dist/obscure'
}
});
...but this seems to mean that all 'amd importable' modules end up being massive amalgamations of one simple file with all the modules in it.
Using baseUrl is not a solution, because, as above, you expect to have multiple isolated 'islands' of javascript which are installed as modules, which 1) need to refer to each other, but 2) also need to be able to refer to their own internal, relative modules.
Seems extremely weird.
Once again, how are you supposed to make this work in the non-trivial case?
Edit:
Surely you say, you're doing it wrong and just not telling us all the things you're doing. Well, see for yourself. An exact copy of this not working is now here on github: https://github.com/shadowmint/requirejs-example
Relative imports do work.
The problem with your code is that you list your module names together with the .js extension. You should never specify a module name with the .js extension. If you do put the extension, you're essentially telling RequireJS "I already know that the module I want is at the end of the path I'm giving you; don't mess with this path" so your RequireJS configuration won't affect how the path you put in your dependencies is resolved.

test not running on karma/jasmine/require.js 'There is no timestamp for *lib*!' error

I change the code, extend some functionality and add new unittest for that. Now, when I run my unit tests with karma (test framework - jasmine), it throw me an error
'There is no timestamp for /libs/angular-bootstrap/ui-bootstrap-tpls.js!'
Uncaught Error: Script error for: angular-bootstrap
http://requirejs.org/docs/errors.html#scripterror
at http://localhost:9876/base/node_modules/karma-requirejs/lib/require.js?1379984163000:138
What I'm doing wrong?
It was my mistake completely. when using karma-requirejs you have main-test.js file where configure how to require.js get the files. I add reference to angular-bootstrap with mistake, that's why require.js couldn't find this file and throwing this mistake. So in my case this error means wrong file name provided.
It can be because it cannot access your source file. You should configure karma to serve scripts where require will look for them.
For example have the config in the karma conf
files:[{pattern: 'node_modules/**/*.js', included:false}]
The question is old, the OP already solved his problem by now, but I'll add my two cents:
From the error message (end of the first error line) we can conclude that you were including a paths (or deps) file in main-test.js with the .js extension.
In RequireJS, you need to call the file names without the extension, so your paths (or deps) would look more or less like this:
paths: {
'ui-bootstrap': 'libs/angular-bootstrap/ui-bootstrap-tpls' // <- without the extension
}

Is there a way to lazily set the path of a resource with RequireJS?

So, I have an app that is using requireJS. Quite happily. For the most part.
This app makes use of Socket.IO. Socket.IO is being provided by nodejs, and does not run on the same port as the main webserver.
To deal with this, in our main js file, we do something like this:
var hostname = window.location.hostname;
var socketIoPath = "http://" + hostname + ":3000/socket.io/socket.io";
requirejs.config({
baseUrl: "/",
paths: {
app : "scripts/appapp",
"socket.io" : socketIoPath
}
});
More complicated than this, but you get the gist.
Now, in interactive mode, this works swimingly.
The ugliness starts when we try to use r.js to compile this (technically we're using grunt to run r.js, but that's besides the point).
In the config for r.js, we set an empty path for socket.io (to avoid it failing to pull in), and we set our main file as the mainConfigFile.
The compiler yells about this, saying:
Running "requirejs:dist" (requirejs) task
>> Error: Error: The config in mainConfigFile /…/client.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.
>> at Function.build.createConfig (/…/r.js:23636:23)
Now, near as I can figure, this is due to the fact that I'm using a variable to set the path for "socket.io". If i take this out, require runs great, but i can't run the raw from a server. If I leave it is, my debug server is happy, but the build breaks.
Is there a way that I can lazily assign the path of "socket.io" at runtime so that it doesn't have to go into the requirejs.config() methos at that point?
Edit: Did some extensive research on this. Here are the results.
Loading from CDN with RequireJS is possible with a build. However, if you're using the smaller Almond loader, it's not possible.
This leaves you with two options:
Use almond along with a local copy of the file in your build.
Use the full require.js loader and try to use a CDN.
Use a <script> tag just for that resource.
I say try for #2 because there are some caveats. You'll need to include require.js in your HTML with the data-main attribute for your built file. But if you do this, require and define will be global functions, allowing users to require any of your internal modules and mess around with them. If you're okay with this, you'll need to follow the "empty: scheme" in your build config (but not in your main config).
But the fact remains that you now have another HTTP request. If you only want one built file, which includes the require.js loader, you'll need to optimize for only one file.
Now, if you want to avoid users being able to require your modules, you'll have to do something like wrap:true in your build. But as far as I can tell, once your module comes down from CDN, if it's AMD, it's going to look for a global define function to register itself with, and that won't exist because it's now wrapped in a closure.
The lesson I took away from all this: inline your resources to your build. It makes sense. You reduce HTTP requests, minify it all and get gzip compression. You don't expose your modules to the world and everything is a lot simpler. If you cache your resources properly you won't even need to worry about it.
But since new versions of socket.io don't like AMD, here's how I did it. Make sure to include the socket.io <script> tag before requirejs. Then create a requirejs module named socket.io with the following contents:
define([], function () {
var io = window.io;
window.io = null;
return io;
});
Set the path like so: 'socket.io': 'core/socket.io' or wherever you want.
And require it as normal! The build works fine this way.
Original answer
Is it possible that you could make use of the path config fallbacks specified in the RequireJS API? Maybe you could save the file locally as a fallback so your build will work.
The socket.io GitHub repository specifies that you can serve the client with the files in the socket.io-client package's dist/ directory.

Categories

Resources