Trying to do some demoscene stuff in my limited spare time.
That is all.
A lightweight inversion of control container for Javascript.
Home Page: http://royjacobs.github.com/intravenous/
Trying to do some demoscene stuff in my limited spare time.
That is all.
Hi!
I really love this DI-framework, it's very similar to how I work with Java and constructor injection.
I have one issue though. When I work with third party modules (or node modules in general) such as express or fs, I would like to inject them the same way as my own modules. But I can't.
Imagine this:
var express = require('express');
module.exports = express;
This module would be loaded by Intravenous without any problems, except that the export needs to be a function. For express this works, since express is a function. But this means, when injecting express into my other modules, I would get the result of calling express(). Might work for express, but doesn't for many other modules.
Could we add support for this somehow? I was thinking something like this:
var express = require('express');
module.exports = express;
module.exports.$external = true;
... or maybe at an even higher level:
var intravenous = require('intravenous');
var express = require('express');
var container = intravenous.create();
container.external('express', express);
What do you think?
It's hard to debug through
How to store a class instead an instance?
If used inside a web worker (shared or dedicated), it throws the following error: ReferenceError: global is not defined
This happens because on worker there is no window object.
The workaround is to put a self.global = {}
before the import, but it would be awesome to get this fixed.
Thanks
The Problem statement
If I want to retrieve an instance of MyCustomClass, I have to first register it with a key name. For that I will have to require this and all the other modules on startup. That means one file will have to require all the modules first and then initialize the application.
This seems in efficient and quite a headache to maintain that one file which contains all the required modules.
RATHER: How about requiring them in modules that actually need them instead
var Dep1 = require('./dep1');
var Dep2 = require('./dep2');
function MyCustomClass () {}
MyCustomClass.$inject = [Dep1, Dep2]; //Instead of using key name
So the main idea is to be able to query on the Class name rather than the key name. What do you think?
It returns an error when trying to register Es6 classes.
class User{
}
var container = intravenous.create();
container.register("User",User)
var instance = container.get("User');
Hello,
Could you add a license file, or package json with license or add license information to your README?
That would help us immensely with our automated license checking.
Best Regards
E.g. consider you authorize requests and have user instance which describes a current user during the request. It would be nice to have an option to store it in container and reuse in other services during a request.
The idea is taken from CDI in Java.
But it is really nice to have or at least I think it is good idea to make it possible to extend intravenous with functionality like this.
I have some strange behavior (maybe its ok, but strange) (all examples in CoffeeScript):
first - create class Foo
module.exports = class Foo
# intravenous injection
@$inject = ['Helper']
constructor: (Helper, options) ->
next, register two classes - Helper
and Foo
container.register 'Helper', Helper, 'singleton'
container.register 'Foo', Foo
and now use somewhere Foo
factory
module.exports = class Bar
# intravenous injection
@$inject = ['FooFactory']
constructor: (FooFactory, options) ->
@_foo_instance_ = FooFactory.get()
If Helper
used in Foo
only - it will be re-created on every Bar
call (and it may be correct - its singleton in factory context, but how about perRequest
?).
Instead, if we are call use Helper
in non-factory classes to - it will be created once only and re-created on Bar
calls (and its looks more correctly - its singleton as registered).
May be I`m miss something, but its looks strange. And actually I cant decide what kind of behavior will be correctly. Just appoint in docs?
I'm curious whether you think it is a bad idea to inject based on function parameter names instead of using func.$inject.
Specifically, are there any pitfalls you can see for server side node.js code that doesn't need to be minified? Is this something you will add to the library?
I've edited the node example to register myClass
as a singleton
. It does create the object only once, however it calls dispose on it the same amount of times it was created!
myDependency constructed
myClass constructed
dependency: [object Object]
nonExistentDependency: null
extraParameter: hello
Calling dispose method for service myClass
Disposing myClass!
Calling dispose method for service myClass
Disposing myClass!
Calling dispose method for service myClass
Disposing myClass!
Calling dispose method for service myDependency
Disposing myDependency!
The code used for instantiating:
var instance = container.get("myClass", "hello");
var anotherInstance = container.get("myClass", "world");
var andAnotherInstance = container.get("myClass", "intravenous");
How can I define constructor parameters when registering. Say I have a class like below.
module.exports = function ModuleContainer(
moduleName
){
'use strict';
var self = this;
this.moduleName = moduleName
/* more code */
};
When registering, how can I register two dependencies like so to pass different values to the contructor argument "moduleName". i.e.
container.register('passportModule', require('./ModuleContainer'), 'passport'); //moduleName is passed 'passport'
container.register('jwtModule', require('./ModuleContainer'), 'jasonwebtoken'); //moduleName is passed 'jasonwebtoken'
So basically I want constructor injection and to define the values of the constructor parameters when registering similar to how Unity handles this in C#
npm install intravenous
creates a directory with only the package.json in it. Can you fix? I've download the file but it's weird. An NPM module would be very helpful.
Thanks!
Alright, I've been trying to figure a way around this, but I it's not coming as easily as I'd hoped.
We use mongoose as an ODM on our node project. Mongoose's models cannot be used as normal javascript classes. Instead, they have functions that generate classes for you. Here's what we currently do with manual dependency passing:
# Post.coffee
makePost = (db) ->
PostSchema = new Schema
title: String
PostSchema.statics.findAll = (cb) -> # go get all posts
PostSchema.methods.titleLength = -> @title.length
# Post is a constructor. Instances have a (new Post()).titleLength() method. Post.findAll() is a function
Post = db.model "Post", PostSchema
return Post
makePost.$inject = ["db"]
In short, that top-level wrapper isn't a constructor. I need to get that returned Post back out, not this
.
How can we do this? Are there workarounds?
Perhaps there's a way we can detect whether it is a constructor or a normal function and support both, or simply check if the value returned from the function is an `instanceof`` the function, and if not, treat it as a normal return value instead.
Perhaps you should always respect the return value of the function? (I'm not really sure how you're getting back to this
when I return something else, but maybe you're doing something fancy)
Here's a test for it that fails.
describe("containing a function registration", function() {
beforeEach(function() {
this.a = function() {
return function() {
return "a"
}
}
this.container.register("a", this.a)
})
it("should return the original function", function() {
a = this.container.get("a")
expect(a()).toBe("a")
})
})
Suppose I want to register more then one binding for a Type and use different binding depending on "parameter or type" is it possible.
So for eg. I have 3 classes which Heirarchy as follows AdsRequestProcessor -inherits->TrackerRequestProcessor -inherits->RequestProcessor.
And there different classes all of which have dependency on RequestProcessor. and I want to inject AdsRequestProcessor in one and TrackerRequestProcessor in other, so a parameter or class name or any thing else while registering this dependencies will be helpful .
Some thing along the lines of NInject's contextual binding.
Hello,
We run into issues with intravenous which are fixed in master branch. Though, the fixes are not available on npm.
Could you please release a latest npm module.
Thank you,
Roman
Hi,
singletons dont appear to work. I'm using 0.1.4-beta.
From what I can tell the instance
value is cached rather than the returnValue
. I replaced this line
container.lifecycles[reg.lifecycle].set(new cacheItem(reg, instance));
with
container.lifecycles[reg.lifecycle].set(new cacheItem(reg, returnValue || instance));
and it started working for me. You are doing the same thing at the end of the function
return returnValue || instance;
If that is true of what it returns it should be true of what it caches yes?
Hi Ron,
I have no issue working with intravenous in the 'regular' pass a function way.
Assuming i'm using the following to create a namespace and abstraction.
module.exports = function() {
function initialize(dependency 1, depedency2) {...}
function runInternal() { // will use the dependencies internally }
return {
run : runInternal
}
}();
what would be the best way to use intravenous? how would I register it?
-- Dan
How about creating an extends
method that creates an instance of base class and then attaches it to the prototype property of the child class?
Note: Need to make sure the base class is never a singleton, else all the child classes will have the same methods.
When I think of a factory in JavaScript, I think of a function, not an object with a .get()
method. This becomes particularly inconvenient when trying to pass factories around.
For example, when moving to Intravenous, my code went from
function Foo(barFactory) {
this.doSomething = function () {
return processSomeBars(barFactory);
};
}
to
function Foo(barFactory) {
this.doSomething = function () {
return processSomeBars(barFactory.get.bind(barFactory));
};
}
I think the solution would be to just make factories into functions. They can still have .get
, .use
, .dispose
, and the like, but calling the factory as a function should have the same result as calling .get
.
There is a small typo inside the following example in Intravenous documentation:
var myClass = function(logger, someGlobalData) {
/* use logger here */
};
myClass.$inject = ["logger", "someGlobalData";
container.register("myClass", myClass);
Should be:
myClass.$inject = ["logger", "someGlobalData"];
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.