I'd like to use a NodeJS library in my Polymer/AngularJS applications. To do so, I aim to run Browserify on the NodeJS module I wish to use and then reference it in a Polymer web component and also in an AngularJS controller. As far as I can tell, Browserify merely adds require() to the global namespace and so there should not have any naming conflicts.
Is there anything I'm missing or will these technologies work together?
Browserify works fine with Polymer. I normally expose modules using browserify's --standalone flag then integrate as a Polymer elements behavior.
I find out a way to use Polymer with webpack polymer-ext
If you want ues browserify with polymer, maybe you should try the same way.
As another, not so sophisticated approach that doesn't use standalone or behaviours but is maybe a bit more flexible, I've gone with defining a global variable APP. Then defining a get function that returns one of the global required modules.
eg
// in main index.html file before elements.html imported define global namespace
<script>
var APP = {};
</script>
Make a test module
// services/test.js
module.exports = {
test: function(){
console.log('imt the test function');
}
}
Then in main js file.
// main js file
(function(APP) {
var globalModules = {
test: require('./services/test')
}
APP.get = function(moduleName){
return globalModules[moduleName];
}
})(APP);
Then this can be used inside Polymer elements when required like
APP.get('test').test();
Not sure what the standpoint would be on whether this would be the "proper" way to do it but it works for what I was trying to achieve and may help someone.
Related
I have a self contained JavaScript function in one file, and some Mocha BDD tests in another file that reference it using [nodejs] require(). So in my function under test I export using module.exports. That's all well and good, in the IDE/build.
Now my function under test is actually an external virtual endpoint, which when deployed into a cloud instance, runs standalone inside a JSVM sandbox (Otto) which has no support for exports or modules, and is ES5 based (it does however embed a version of the Underscore library). If I leave the nodejs module definition in there when I deploy to cloud, it kicks off an error at runtime (as Otto doesn't recognise modules). So I want to remove it, and use some vanilla JS mechanism for the linkage back to the Mocha tests and test runner.
So my question is, if I can't use nodejs or requirejs modules, how can I link my Mocha tests in one file to a JS function in another? I had a play with placing a function closure (which most module implementations use) in the file under test, and Otto is happy with this, as its vanilla JS, but any variable with global scope in the file is still not visible from my test file, so there is no linkage.
Any thoughts?
From a quick look at the Otto docs, it looks like Otto only wants whole files and (as you've said) doesn't recogise commonjs modules from node.
If you've got many files I would recommend bundling them into a single file with webpack/browserify/etc, which is how most people convert modules for use in the browser, which similarily doesn't recognise commonjs modules without tooling.
Alternatively, you could convert all the module.exports to simple var declarations, concatenate the files together and hope you don't have a naming collision.
I don't see anything in the docs about having access to a window or global object to hang globals onto, which limits your options
One of my colleague came up with a suggestion to use closure in the file under test which gets deployed into the cloud instance, if you are running under Nodejs, and conditionally do the export. I added the small anonymous closure below to do this, and Otto doesn't complain.
(function () {
if (typeof module != 'undefined') {
module.exports = pdp_virtual_endpoint;
}
}());
Not sure why I didn't think about this earlier :)
I am trying to port a library from grunt/requirejs to webpack and stumbled upon a problem, that might be a game-breaker for this endeavor.
The library I try to port has a function, that loads and evaluates multiple modules - based on their filenames that we get from a config file - into our app. The code looks like this (coffee):
loadModules = (arrayOfFilePaths) ->
new Promise (resolve) ->
require arrayOfFilePaths, (ms...) ->
for module in ms
module ModuleAPI
resolve()
The require here needs to be called on runtime and behave like it did with requireJS. Webpack seems to only care about what happens in the "build-process".
Is this something that webpack fundamentally doesn't care about? If so, can I still use requireJS with it? What is a good solution to load assets dynamically during runtime?
edit: loadModule can load modules, that are not present on the build-time of this library. They will be provided by the app, that implements my library.
So I found that my requirement to have some files loaded on runtime, that are only available on "app-compile-time" and not on "library-compile-time" is not easily possible with webpack.
I will change the mechanism, so that my library doesn't require the files anymore, but needs to be passed the required modules. Somewhat tells me, this is gonna be the better API anyways.
edit to clarify:
Basically, instead of:
// in my library
load = (path_to_file) ->
(require path_to_file).do_something()
// in my app (using the 'compiled' libary)
cool_library.load("file_that_exists_in_my_app")
I do this:
// in my library
load = (module) ->
module.do_something()
// in my app (using the 'compiled' libary)
module = require("file_that_exists_in_my_app")
cool_library.load(module)
The first code worked in require.js but not in webpack.
In hindsight i feel its pretty wrong to have a 3rd-party-library load files at runtime anyway.
There is concept named context (http://webpack.github.io/docs/context.html), it allows to make dynamic requires.
Also there is a possibility to define code split points: http://webpack.github.io/docs/code-splitting.html
function loadInContext(filename) {
return new Promise(function(resolve){
require(['./'+filename], resolve);
})
}
function loadModules(namesInContext){
return Promise.all(namesInContext.map(loadInContext));
}
And use it like following:
loadModules(arrayOfFiles).then(function(){
modules.forEach(function(module){
module(moduleAPI);
})
});
But likely it is not what you need - you will have a lot of chunks instead of one bundle with all required modules, and likely it would not be optimal..
It is better to define module requires in you config file, and include it to your build:
// modulesConfig.js
module.exports = [
require(...),
....
]
// run.js
require('modulesConfig').forEach(function(module){
module(moduleAPI);
})
You can also try using a library such as this: https://github.com/Venryx/webpack-runtime-require
Disclaimer: I'm its developer. I wrote it because I was also frustrated with the inability to freely access module contents at runtime. (in my case, for testing from the console)
I know I can install underscore using npm but that's not what I can do in my work environment. I need to be able to download the Underscore.js library and then make it "browserify-compatible".
So let's assume Underscore.js looks something like this:
(function() {
var root = this;
// Rest of the code
}.call(this));
I downloaded that file on my hard drive and saved it as under.js.
My file that requires underscore looks like this:
var underscore = require("./under");
console.log(underscore);
And then I run browserify from the cli.
I have an HTML page called test.html and basically all it does is load the generated bundle.js.
However, the console.log(underscore) line fails - says that underscore is undefined.
What have I tried?
Obviously I added module.exports to the first line - right before the function definition in under.js, and that's how I got the error mentioned above. I also tried the method from this answer , still got the same error.
So, how would I use Browserify to load libraries such as Underscore.js or Backbone without using npm-installed modules?
That's because browserify does not add variables to the global scope. The version you download is identical to the version that you install via NPM.
You need to explicitly attach it to the window to export it to the top level scope.
If you create a file called "expose_underscore.js" and put this in it:
var _ = require('./under');
window._ = _;
Will do it, followed by: browserify expose_underscore.js > bundle.js and then add bundle.js as a <script> tag you will be able to do the following in your console:
HOWEVER, you shouldn't do this if you're using browserify. The point behind it (and Node's version of commonJS) is that you explicitly require it everywhere you need it. So every file you have that needs underscore should import it to a local variable.
Don't worry -- you will still only have one copy loaded.
I typically add my vendor libs like Underscore as script tags. Underscore will attach itself to the global scope, so then you don't need to require it anywhere to use it.
If you do want to use it in a Browserified fashion, verify that you have the correct path in your require statement (browserify requires are relative paths) and move the module.exports statement to the end of the file.
I'm trying to build some unit tests for an old JS file/module that is out of my control.
The JS module is built using the following pattern...
var myModule = {
myMethod:function() {
}
};
I am then trying to build a DOH test harness to test this. I tried the following...
require([
"doh/runner",
"../../myModules/myModule.js"
], function(doh) {
console.log(doh);
console.log(myModule);
});
The file seems to be getting picked up fine but I can't reference anything in it. "console.log(myModule);" just returns undefined.
Anyone know how I can correctly include an external non dojo module JS file in a DOH test harness?
Thanks
Other than you shouldn’t be using DOH because it is deprecated (use Intern), there is no reason that you shouldn’t see myModule there. You are using a script address and not a module ID, which isn’t right, and you are using a relative path with a require call, which is also not right, but if either of these things were preventing the loader from finding and loading the script you are trying to load it should be throwing an error that you could see in the console. The only other possibility is you have somehow managed to build a built layer into this myModule script, in which case the entire script ends up wrapped in a closure and so using var foo will no longer define a global variable foo.
You need to declare myModule in the function callback to your require statement:
require([
"doh/runner",
"../../myModules/myModule"
], function(doh, myModule) { // <-- include myModule
console.log(doh);
console.log(myModule);
});
Just be sure that myModule.js returns your module.
So I am just getting started with Yeoman. I just setup a basic project and I am not sure where to put my scripts. Should I just put stuff in the provided app.js? Or should I make my own files and add them to some build script somewhere or require them somewhere? Any advice is appreciated.
I also don't understand the purpose of this in the app.js file:
define([], function() {
return 'Hello from Yeoman!';
});
Okay, so you opted to use RequireJS for your project. RequireJS allows you to break your code down in modules - not only improving the tidiness of your code (reducing spaghetti code), but also de-cluttering the global namespace.
If you look in your main.js file, you'll notice the following:
require(['app'], function(app) {
//use app here
console.log(app);
});
What this does is include app.js into your main javascript file and runs it.
Now, where i think you're getting confused, is with the new syntax RequireJS introduces - but essentially each file forms a closure and has its own scope.
Imagine the following:
If you weren't using RequireJs to separate your files, and all the code was in one single file. It would look like this:
function app () {
return 'Hello from Yeoman!';
}
console.log(app());
You can write whatever you want inside app.js as long as it's wrapped with the required RequireJS syntax:
define([], function() {
//Start writing your code here
});
And that'll be included in main.js and compiled down into one file for production.
The docs for Yeoman are a little sparse at the moment, so i'd recommend you head over to the RequireJS site and read through their documentation if you're keen on writing modular JavaScript.
You can always choose not to include RequireJS when initialising a new Yeoman project if you don't want/need this functionality.
Hope that helps :)