Requirejs + text plugin + sugar syntax + almond.js - requirejs

I'm using the sugar syntax to load templates into my views:
...
var template = require('text!templates/toolbar/toolbar.html')
Everything works fine, but when I run the r.js optimizer I get the error
TypeError: Object function () {
//A version of a require function that passes a moduleName
//value for items that may need to
//look up paths relative to the moduleName
return req.apply(undef, aps.call(arguments, 0).concat([relName, forceSync]));
} has no method 'toUrl'

Related

Gulp + Browserify + TypeScript To Browser

My problem is the following:
I use gulp+browserify to compile my TypeScript to JavaScript that you can use on normal HTML pages, the problem is that my class is never available on the browser:
VM633:1 Uncaught ReferenceError: Test is not defined
at <anonymous>:1:13
This is my TypeScript File:
class Test {
public test(): void {
console.log("aa");
}
}
This is my gulpfile
var gulp = require("gulp");
var browserify = require("browserify");
var source = require('vinyl-source-stream');
var tsify = require("tsify");
gulp.task("default", function () {
return browserify({
//basedir: '.',
debug: true,
entries: ['app/Resources/typescript/Test.ts'],
cache: {},
packageCache: {}
})
.plugin(tsify)
.bundle()
.pipe(source('bundle.js'))
.pipe(gulp.dest("web/bundles/framework/js"));
});
The file compiles without problem, and is included in my index.html (the compiled js file).
But when i try:
var t = new Test();
I get the following error:
VM633:1 Uncaught ReferenceError: Test is not defined
at <anonymous>:1:13
I can't resolve it, I have read a lot and I haven't found anything clear, I tried all and nothing worked.
There are a few things missing here:
If you want your class to be accessible outside of your module, you have to export it:
export class Test {
// ...
}
Browserify creates functions on top of the classes you define. So it won't be accessible globally (which is a good thing). Normally you would import it in another file and use it:
// in any TS file that wants to use `Test` class. Make sure this is included in the gulp entries as well
import {Test} from "test";
var t = new Test();
console.log(t);
Or if really want it to be accessible globally, you can attach it to window object:
// In Test.ts file:
(window as any).Test = Test; // This can be useful when debuging. But don't do this in production code.

Obfuscate RequireJS module name [duplicate]

This question already has an answer here:
Replace module ids with fake names
(1 answer)
Closed 7 years ago.
My project layout is:
-bin\
-out.closeure.js // (compiled from out.js using the closure compiler)
-out.js // this is the requirejs output file, no minification done)
-src\
-lib\
-library.js
-main.js
-somefile.js
Now when I use RequireJS to combine my project to a single file, is there a way to mangle the names of the module? For example in main.js instead of:
require(['somefile'], function(SomeFile){
//blah
});
I'll have
require(['a6fa7'], function(SomeFile){
//blah
});
Since I am using closure compiler to obfuscated everything, the only thing not being mangled is the module names, and I want to mangle that as well.
I looked at the https://github.com/stevensacks/grunt-requirejs-obfuscate plugin but it's not working and I'm not sure if that plugin does what I want.
Edit1: I encourage to use instead AMDclean, there may be no reason to keep the footprint amd produce on an optimized build. If you want to keep it, the following way is the workaround i made:
Use the onBuildWrite and onBuildRead as the documentation states:
onBuildWrite A function that will be called for every write to an optimized bundle of modules. This allows transforms of the content before serialization.
"replaceModuleNames": [],
//executed on every file read
onBuildRead: function(moduleName, path, contents){
this["replaceModuleNames"].push({
"name": moduleName,
"with": makeid()
});
//Always return a value.
return contents;
},
onBuildWrite: function (moduleName, path, contents) {
console.log("moduleName: " + moduleName + " ,path: " + path + " ,contents: ... ");
var text = contents;
RegExp.escape = function(text) {
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
};
this["replaceModuleNames"].forEach(function(element){
var regE = new RegExp('(?:define\\(|require\\().*(?:"|\')('+RegExp.escape(element["name"])+')(?:"|\')');
text = text.replace(regE, function(a, b){
return a.replace(b, element["with"]);
});
console.log("moduleName: "+moduleName+ " replaceWith: " + element["with"] + " result: " + text);
});
//Always return a value.
return text;
}
Place it on the build.js, you have to implement makeid method,
i tested it but it might fail, so dont rely on it for production
Edit2: text.replace(element["name"], element["with"]); may cause inconsistent code, replaced with regexp groups, i am not experienced with regex so its open to improvements.

Jasmine spies only detect calls on methods called on Node.js exports object

I'm trying to spy on dependencies in a Node.js module from within a Jasmine spec, and I'm encountering some weird behaviour.
Jasmine spies on a method that resides in an object exposed by the exports object in the module. When I call the spied-on method in the module using
exports.umap()
the spy detects it. But when I call it in the module using a variable name I assigned to the same method
var umap = exports.umap
umap()
the spy doesn't detect it.
This seems weird to me given that var umap refers to the same method as exports.umap. Anyone have any ideas why this is? Code below.
(The whole reason I'm doing this is that I want to stub my module's dependencies without the need to design the module as a class and use dependency injection.)
// mapper.js
exports.umap = require('underscore').map;
var umap = exports.umap;
function map () {
return exports.umap([1,2,3], function(el) {console.log(el);return el * 2});
// umap() goes unnoticed by the spy
// return umap([1,2,3], function(el) {console.log(el);return el * 2});
}
exports.map = map;
.
// mapper_spec.js
var mapper = require ('../../lib/mapper');
var map = mapper.map;
describe('mapper', function() {
describe('map', function() {
it('calls umap', function() {
var mapped;
spyOn(mapper, 'umap').and.callThrough();
mapped = mapper.map();
expect(mapper.umap).toHaveBeenCalled();
expect(mapped).toEqual([2,4,6]);
});
});
});
UPDATE
I'm still curious about this issue, however https://www.npmjs.org/package/proxyquire made my whole "spying-on-things-attached-to-export-object" strategy moot.

Combining files using requirejs and grunt

I am trying to combine files using the grunt plugin for requirejs:
https://www.npmjs.org/package/grunt-contrib-requirejs
Here is the configuration:
requirejs:
compile:
options:
#appDir: './'
baseUrl: "client"
mainConfigFile: "client/test1.js"
name: "test1"
out: "build/test.js"
onModuleBundleComplete: (data) ->
outputFile = data.path
fs.writeFileSync(outputFile, amdclean.clean(
'filePath': outputFile
))
wrap:
start: ""
end: ""
Here are the input and output javascript
Input:
test1.js
var x = console;
require(['test2'], function() {
return console.log('Hello');
});
test2.js
x.log('this is test2');
test.js
var test2, test1;
x.log("this is test2"), null, test2 = undefined;
var x;
x = console, function () {
return console.log("Hello")
}(), test1 = undefined;
The program works fine when loaded in browser with requirejs. But after the build is done, it does not work. This is because the definition x=console is provided before the code in test2.js is loaded when the modules are loaded using requirejs.
However, after the build, the definition x=console appears after the code from test2.js is loaded - which creates an error - because test2.js makes a call to x which is a global variable between the two js files.
I need to ensure requirejs builds the project into a single .js file while ensuring that no amd code is present (require/define) and the code is executed in the EXACT same order as with requirejs loaded in the browser.
I think you may need a better understanding of the Asynchronous Module Definition (AMD) API specification. In either case I've modified your code a little bit to better adhere to AMD's syntax and I've created a a third file to define x like this:
test1.js
// Require the 'test2' module (which is passing x; which is equal to console)
require(['test2'], function(x){
x.log('this is test1');
});
test2.js
// Define the 'test2' module which depends on the 'x' module
define(['x'], function(x){
x.log('this is test2');
return x; // Return x; which is equal to console
});
x.js
// Define the 'x' module which has no dependencies
define(function(){
console.log('this is x');
return console; // Return console
});

NodeJS Functions/Module Include Scope

I'm developing an application with node.js and socket.io. I have built a small-scale project with some variables and functions inside a connection-specific block. These functions have access to the variables declared within that block without the need to pass the values in specifically.
This works fine, and is acceptable for a project of this size. However, as I was trying to clean the code up a bit, I looked into factoring those functions out into their own file and found modules declared by using exports.functionname as described here: http://nodejs.org/docs/v0.3.2/api/modules.html
However, these functions do not have access to the variables within the same block as they normally do when being require()'d in instead of actually being declared in the file.
Is there some way to make functions in an external file behave as if they were declared locally in nodejs?
There isn't without hacking the module system, which is exactly what I did. https://github.com/Benvie/Node.js-Ultra-REPL/blob/master/lib/ScopedModule.js
I can't say I recommend it for production. Basically the issue is more with JavaScript itself. Node wraps modules in a function so they have their own private scope. The only way to share in that scope is to be executed inside that function which wouldn't really work for a module (modular...) system. The only other scope is global which also isn't desirable.
The trick I used to get around it is in changing that wrapper function to have dynamic properties based on an externally defined set of module imports so that from inside the module wrapper all those parameters look like they're magically defined but aren't global.
Node's module wrapper looks like this:
(function (exports, module, require, __filename, __dirname){
/**module**/
})
Where mine simply adds more parameters and ensures they're resolved before executing the module wrapper.
I have it read a file named ".deps.json" in a given folder before loading a module.
An example one would be like this
[{
"providers": [ "./utility/",
"./settings/" ],
"receivers": [ "*" ]
}]
So it will load the modules in those subfolders and then expose each one as a parameter in the wrapper, named based on the filename.
The usual and clean way would be to define a function in your module, that takes the required variables as parameters:
// extracted_file.js
exports.handler = function(param1, param2) {
return param1 + param2;
}
// caller file
var extractedHandler = require('./extracted_file').handle;
var localVar1 = 1300,
localVar2 = 37;
console.log(extractedHandler(localVar1, localVar2));
You can change function scope using toString() and the dreaded eval.
If your functions were in say lib.js as follows:-
var lib = {}
lib.foo = function() { console.log(var1) }
lib.bar = function() { console.log(var2) }
module.exports = lib
In main.js you could have this:-
var var1 = 1
var var2 = 2
var ob1 = require('./lib')
ob1.foo()
ob1.bar()
When you run it the ob1.foo() line gives a ReferenceError, var1 is not defined. This is because the scope of foo() comes from lib.js and not your main js file, and var1 is invisible to it. ob1.foo is a reference to a function with lib.js scope. You need to make a new reference with main.js scope.
To do this convert each function to string and eval it. That will create a new function with the same code but with main.js scope. Here's one way using a setMainScope method which loops through all the functions changing their scope to main.js.
var var1 = 1
var var2 = 2
var ob1 = {}
ob1.setMainScope = function(ob2) {
for(var prop in ob2) {
if( !ob2.hasOwnProperty(prop) ) {continue}
if( typeof ob2[prop] !== 'function' ) {continue}
this[prop] = eval( "(" + ob2[prop].toString() + ")" )
}
}
ob1.setMainScope( require('./lib') )
ob1.foo() // 1
ob1.bar() // 2
Now it all works nicely except eval was used. The scope of foo() and bar() is now main.js and so they 'see' var1 and var2.

Resources