In an Dojo 1.7 AMD web app you can define also arbitrary data in the config object (http://dojotoolkit.org/reference-guide/loader/amd.html).
The configuration object can also be used to set arbitrary, application-specific configuration data. All properties of a configuration object are shallow copied to require.rawConfig
I looked to the requirejs config page (http://requirejs.org/docs/api.html#config), but I did not find a similar feature here. But I did not look into the source code.
Is there a possibility to store arbitrary infos in the requirejs config and get access to it?
Thanks alot in advance
Wolfgang
As far as I can see it is not supported.
You need to insert 1 line in the require.js source code to get this feature.
Here is an example:
require.config({
test: "one",
paths: {
'jquery': 'libs/jquery/1.7.1/jquery',
...
Along with the normal values you store your arbitrary information.
Then, you have to open the requirejs source code with a text editor.
Approximately in line 380 - 390 (depends on your version), function "makeRequire":
This function calls another called "mixin":
mixin(modRequire, {
nameToUrl: makeContextModuleFunc(context.nameToUrl, relModuleMap),
toUrl: makeContextModuleFunc(context.toUrl, relModuleMap),
defined: makeContextModuleFunc(context.requireDefined, relModuleMap),
specified: makeContextModuleFunc(context.requireSpecified, relModuleMap),
isBrowser: req.isBrowser,
rawConfig: config
});
After "isBrowser" write "rawConfig: config".
Now, in your amd module:
define(['require'], function (require){
alert (require.rawConfig.test);
...
Update:
This feature will be implimented in requirejs 1.1.
https://github.com/jrburke/requirejs/issues/182
Related
I have an aws amplify project which is using yarn workspaces.
My project has a lambda function and a layer. When the lambda function runs in aws it needs to import my library from the layer...
import MyLib from '/opt/nodejs/build/MyLib';
However when I run this function locally I want to import the library from my local file system
import MyLib from '/Users/sive/Documents/SWT/wake-book/amplify/backend/function/wakebookLayer/lib/nodejs/build/MyLib';
How can I tell typescript to compile an import from /opt/nodejs/build/MyLib to the location on my local file system.
I tried using path mapping in my tsconfig.json
"baseUrl": ".",
"paths": {
"/opt/nodejs/build/MyLib": ["./amplify/backend/function/wakebookLayer/lib/nodejs/build/MyLib.d.ts"]
},
This stops vscode complaining about an unknown import, so it is being 'linked' correctly (I can cmd click my import /opt/nodejs/build/MyLib path and I am taken to the full file system path.)
But the compiled js is still using the wrong path.
The compiled js file looks like this
const MyLib_1 = __importDefault(require("/opt/nodejs/build/MyLib"));
I would expect it to remap the import path and to look like this
const MyLib_1 = __importDefault(require("/Users/sive/Documents/SWT/wake-book/amplify/backend/function/wakebookLayer/lib/nodejs/build/MyLib"));
If I manually edit the output js to have the full file system path it works (I can run my project locally).
Have I misunderstood how path mapping is supposed to work?
Is there a way to get my desired behaviour?
Updated edit: I don't think this has anything to do with the fact that the path itself is long or complex. I'm having trouble getting mine to pass through correctly as well. I think the issue has to do more with how you're (and I'm) implementing the path mapping itself.
To test this theory, you could move one of those dependencies to a very simple, short path and see if that has any impact on the behavior at all.
Edit: I'm sorry, I just realized that you were trying to do this earlier and the problem seems to be related to the path itself... I'm not sure this will be helpful at all, but I'm going to leave it here for reference for now. I'm quite happy to try to address this with you over comments/edits.
What you are looking for is called "Path Mapping". There are a few ways this might be handled depending on your project. If you're deploying via SAM, this article from AWS describes one possible solution: https://aws.amazon.com/blogs/compute/working-with-aws-lambda-and-lambda-layers-in-aws-sam/
The important excerpt from that is here:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: sam app
Globals:
Function:
Timeout: 3
Runtime: nodejs8.10
Resources:
TempConversionFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: hello-world/
Handler: app.lambdaHandler
Events:
HelloWorld:
Type: Api
Properties:
Path: /{conversion}/{value}
Method: get
This change dropped out some comments and output parameters and
updated the function resource to TempConversionFunction. The primary
change is the Path: /{conversion}/{value} line. This enables you to
use path mapping for our conversion type and value.
I've also seen examples that leverage tsconfig, but this seems to be a separate solution. Again, here is a link to the documentation: https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
And the relevant excerpt:
Sometimes modules are not directly located under baseUrl. For
instance, an import to a module "jquery" would be translated at
runtime to "node_modules/jquery/dist/jquery.slim.min.js". Loaders use
a mapping configuration to map module names to files at run-time, see
RequireJs documentation and SystemJS documentation.
The TypeScript compiler supports the declaration of such mappings
using paths property in tsconfig.json files. Here is an example for
how to specify the paths property for jquery.
{
"compilerOptions": {
"baseUrl": ".", // This must be specified if "paths" is.
"paths": {
"jquery": ["node_modules/jquery/dist/jquery"] // This mapping is relative to "baseUrl"
}
}
}
Without knowing more about how you deploy your code, it's not possible for me to give more a more exact answer. But I hope this helps.
I should note, that your try/catch block does work, but it wouldn't be considered a best practice.
It's been a year and a half since this post was first answered, and there still doesn't seem to be a widely publicized solution to this issue.
So in case anyone stumbles upon this, here's what I came up with:
I have a JAVASCRIPT (.js, not a .ts file) in all my lambda function handler directories whose single responsibility is to import the layer, at run time, from the appropriate path (at either the '/opt/nodejs' path or the local path on my computer). It does so using a try/catch mechanism, which I know is a sort of anti-pattern, but it works well for this scenario.
try{
module.exports = require("/opt/nodejs/index")
} catch {
module.exports = require("../../layer/index"); // my local path
}
Then, in my handler code I import the layer with this code snippet:
import layer = require("../../layer"); // path to aforementioned file
This solution is leveraging an obscure typescript feature referred to as 'export = syntax'
https://www.typescriptlang.org/docs/handbook/modules.html#export--and-import--require
It only works if the file that imports the switching layer code is a javascript (.js) file. It doesn't work if it's a typescript (.ts) file. So you'll also have to configure your tsconfig.json file with "allowJs": true
I am using a library that (very selfishly, IMHO) assumes that the baseUrl will point to the company's CDN:
baseUrl: "[http protocol slash slash]cdn.wijmo.com/amd-js/"
At first I thought that I would just copy the contents of the above Url to my own folder (such as /scripts/wijmo/amd-js), but that doesn't work because the good folks at Wijmo hardcoded path references in their AMD define statements, such as this:
define(["./wijmo.widget"], function () { ... });
What the above means (if I understand things properly) is that if you have any other non-Wijmo AMD modules then you must either:
(a) place them under the amd-js path, perhaps in a sub-folder named "myScripts"
(b) use hard-coded RequireJS path references to your own AMDs, like this:
paths: {
"myAMD_1": "http://www.example.com/scripts/myScripts/myAMD_1",
"myAMD_2": "/scripts/myScripts/myAMD_2.js"
}
(a) works, but it means that the baseUrl cannot point to the Wijmo CDN because I don't have access to the Wijmo CDN site so I must move the files published under amd-js to my own server.
(b) sort of work, and here is my problem: If I use syntax myAMD_1 then all is well. But that doesn't let me test on my local development machine, which uses localhost. (I don't want to get into detecting which server I'm running on and customize the paths value... I want the path to remain the same before and after I publish to my http server.)
Now, according to the RequireJS documentation:
There may be times when you do want to reference a script directly and not conform to the "baseUrl + paths" rules for finding it. If a module ID has one of the following characteristics, the ID will not be passed through the "baseUrl + paths" configuration, and just be treated like a regular URL that is relative to the document:
* Ends in ".js".
* Starts with a "/".
* Contains an URL protocol, like "http:" or "https:".
When I try to end (terminate) my path reference with .js (as shown in AMD_2 above), RequireJS doesn't find my AMD and because it ends up looking for myAMD_2.js.js (notice the two .js suffixes). So it looks like RequireJS is no longer honoring what the docs say it employs as a path-resolution algorithm. With the .js suffix not working properly, I can't easily fix references to my own AMDs because I don't know for sure what server name or physical path structure they'll be published to--I really want to use relative paths.
Finally, I don't want to change Wijmo's AMD modules not only because they're are dozens of them, but also because I would need to re-apply my customizations each time they issue a Wijmo update.
So if my baseUrl has to point to a hard-coded Wijmo path then how can I use my own AMDs without placing them in a subfolder under the Wijmo path and without making any fixed-path or Url assumptions about where my own AMDs are published?
I can suggest a couple of approaches to consider here--both have some drawbacks, but can work.
The first approach is to provide a path for each and every Wijmo module that needs to be loaded. This will work, but you have touched on the obvious drawbacks of this approach in the description of the question: Wijmo has many modules that will need to be referenced, and maintaining the module list across updates in the future may be problematic.
If you can live with those drawbacks, here is what the RequireJS config would look like:
require.config({
paths: {
'wijmo.wijgrid': 'http://cdn.wijmo.com/amd-js/wijmo.wijgrid',
'wijmo.widget': 'http://cdn.wijmo.com/amd-js/wijmo.widget',
'wijmo.wijutil': 'http://cdn.wijmo.com/amd-js/wijmo.wijutil',
// ... List all relevant Wijmo modules here
}
});
require(['wijmo.wijgrid'], function() { /* ... */ });
The second approach is to initially configure the RequireJS baseUrl to load the Wijmo modules. Then once Wijmo modules have been loaded, re-configure RequireJS to be able to load your local app modules. The drawback of this approach is that all the Wijmo modules will need to be loaded up front, so you lose the ability to require Wijmo modules as needed within your own modules. This drawback will need to be balanced against the nastiness of listing out explicit paths for all the Wijmo modules as done in the first approach.
For example:
require.config({
baseUrl: 'http://cdn.wijmo.com/amd-js',
paths: {
// ... List minimal modules such as Jquery and Globalize as per Wijmo documentation
}
});
require(['wijmo.wijgrid'], function() {
require.config({
baseUrl: '.'
});
require(['main'], function() {
/* ... */
});
});
I have a web application that uses Require in order to load dependencies. I have a set of JS libraries that are included using the Require config.shim object.
Two such example libraries are:
require.config({
shim: {
"libs/leaflet": {
exports: "L"
}
"libs/leaflet-dvf": {
deps: ["libs/leaflet"],
exports: "L"
}
}
The second library, leaflet-dvf requires the first, leaflet. The second is a plugin to the first that depends on the global scope variable L that the first library defines.
When I run the application using Require normally, everything works fine. I can include either library from the shim, and everything works great. No problems.
The problem comes when I run this code through the Require r.js Optimizer. The Optimizer, when it builds the single optimized JS file, will incorrectly order the dependencies. In the built file, the leaflet-dvf code will come before the leaflet code. This causes a JS runtime error because the dependant plugin cannot find the L global scope variable that is required.
My build config looks like:
({
baseUrl: "../js",
paths: {
"requireLib": "../js/libs/require"
},
include: ["requireLib"],
name: "Main",
out: "bin/Main-built.js",
optimize: "none",
wrapShim: true
})
When I run the Optimizer, using Rhino, it builds my output file. In the Main-built.js file, the code for the plugin will come before the required library. This causes an L undefined error.
How do I get the Optimizer to respect the dependency order of my Shims, in order to properly order the library files in my Optimized JS file?
I had a similar problem a while back with knockout extensions and shim didn't work correctly. This is how we solved it.
Create a module called: leafletLib
define(["libs/leaflet","libs/leadleft-dvf"],function(leftlet,dvf){
return leaflet;
});
LeafletLib has the main library and all of the extensions. On modules that have leaflet or leaflet-dvf as a dependancy you call leafletLib. It is kind of hacky but it might work for you.
define(["leafletLib"],function(leafletLib){});
I have the following code in Visual Studio, in an MVC application;
/scripts/bin/models/ViewModel.ts
export class ViewModel {
// view model code
}
Now, I have downloaded requirejs, and set the build mode for typescript to AMD type, so that its output looks such as....
define(["require", "exports"], function(require, exports) {
And so on ...
So then I declare my app/config.js file like so;
require.config({
baseUrl: '/scripts/bin'
});
And I try to load this up, I have requirejs loaded into the scripts, and attempt to call it...
require(['models/ViewModel'], function (viewModel) {
console.log("test");
});
And I am simply told that it is an invalid call. No other details. The path that it shows is completely correct, too. Is there some kind of additional configuration required? The requirejs documentation is extremely vague about this.
SOLUTION
This turned out to have nothing to do with requirejs, but instead had to do with IIS.
By default, IIS has a rule known as hiddenSegments. It does not allow you to bring in any code from a folder with bin in the path. I simply renamed the folder from bin to something else, and it worked fine.
Using require.js with TypeScript is a combination of your .html, require.config, module exports and imports.
For a step-by-step guide on moving from CommonJs TypeScript to AMD and require.js, have a look here.
Have fun.
The TypeScript compiler doesn't have any knowledge of your require.config - so when you use paths relative to that baseUrl they look invalid to the compiler.
Until something is done to bridge that slight mismatch (i.e. make the compiler super-clever so it can look for require.config sections and use them to check paths) it is easier not to set a baseUrl and use the full path in your import statements:
import vm = require('./scripts/bin/models/ViewModel');
Are you sure that the require call is done with [] and not just
require('models/ViewModel', function (viewModel) { // this is an error
console.log("test");
});
See : http://requirejs.org/docs/errors.html#requireargs
A am relatively new to JamJS, and struggle to make it work properly.
I've got a very simple project based on Backbone and RequireJS, where I use JamJS to manage dependencies, namely: Backbone, _, Less, $, modernizr, underscore, bootstrap.
I tend to follow the method used by Backbone Boilerplate.
This is the code I use to get the Jam-compiled requireJS config file, together with my application-specific require config:
in html:
< script data-main="/assets/js/app/config" src="/assets/js/jam/compiled.min.js"> < /script>
'Compiled.min.js' is obviously the 600kb minified file generated by Jam.
The '/app/config' file is my Require.js configuration file where I'm planning to include all my project-specific code, not managed by the dependency manager.
Here's app/config.js:
require.config({
baseUrl:'/assets/js/',
deps: ['less','modernizer','bootstrap-jam','app/main'],
paths: {
'homeView': 'app/views/homeView'
// Use the underscore build of Lo-Dash to minimize incompatibilities.
,'lodash': '../jam/lodash/dist/lodash.underscore.min'
},
map: {
},
shim: {
}
});
(the files in deps are the ones I need on every page + my main.js - kind of a router.
The problem is that, in my homeView (which is initialized by main.js), I do this sort of thing:
define(['backbone'], function (Backbone) {
return Backbone.View.extend({
el:$('#homepageWrapper'),
initialize: function () {
this.$('#subTitle').text('This text is generated by homeView - the default Backbone View.');
}
})
});
As you can see I want Backbone to be available in this view. I assume that it's available through the compiled Jam code, however when I look in the Network panel in the Web Inspector, I see that this dependency is pulled in separately- this happens to any resource I try to use, not just Backbone.
I suspect that it might be something to do with the error I get as well, which I haven't been able to figure out. When using the compiled jam config, I get:
Uncaught Error: Module name "underscore" has not been loaded yet for
context: _. Use require([])
I'd really appreciate help with this
Thanks.