Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added require implementation. Closes #3

also added function / date serialization when nested
  • Loading branch information...
commit dce91aaaf0298942ffdb1146f87da1405591e827 1 parent 446b116
@tj tj authored
View
41 examples/require.js
@@ -0,0 +1,41 @@
+
+// $ npm install express jade
+
+/**
+ * Module dependencies.
+ */
+
+var express = require('express')
+ , expose = require('../')
+ , app = express.createServer()
+ , url = require('url');
+
+app.set('views', __dirname + '/views');
+app.set('view engine', 'jade');
+app.set('title', 'Example');
+app.set('default language', 'en');
+app.set('boot', new Date);
+
+// tell express-expose that we want to
+// use the commonjs module system, and
+// not namespacing
+app.exposeRequire();
+
+// we can expose arrays as modules if we wish
+app.expose([function(){ return 'yay'; }], 'array');
+
+// or regular objects, the functions are always
+// serialized appropriately
+app.expose(app.settings, 'settings');
+app.expose({ add: function(a, b){ return a + b; }}, 'utils');
+
+// by default the module name be the basename, so
+// "color" in this case, however we explicitly pass "utils/color"
+app.exposeModule(__dirname + '/color', 'utils/color');
+
+app.get('/', function(req, res){
+ res.render('index', { layout: false });
+});
+
+app.listen(3000);
+console.log('listening on port 3000');
View
6 examples/views/index.jade
@@ -4,5 +4,7 @@ html
script!= javascript
body
h1= settings.title
- script!= languages
- script!= foot
+ - if (locals.languages)
+ script!= languages
+ - if (locals.foot)
+ script!= foot
View
79 lib/express-expose.js
@@ -88,6 +88,10 @@ HTTPSServer.prototype.expose = function(obj, namespace, name){
// buffer self-calling function
} else if ('function' == typeof obj) {
this.expose(';(' + obj + ')();', name);
+ // buffer module object
+ } else if (this._require) {
+ obj = 'module.exports = ' + string(obj);
+ this.expose(renderRegister(namespace, obj), name);
// buffer object
} else {
this.expose(renderNamespace(namespace), name);
@@ -99,6 +103,23 @@ HTTPSServer.prototype.expose = function(obj, namespace, name){
};
/**
+ * Expose the common-js module system to the client-side.
+ *
+ * @return {HTTPServer} for chaining
+ * @api public
+ */
+
+res.exposeRequire =
+HTTPServer.prototype.exposeRequire =
+HTTPSServer.prototype.exposeRequire = function(){
+ if (this._require) return this;
+ this._require = true;
+ var js = fs.readFileSync(__dirname + '/require.js', 'ascii');
+ this.expose(js);
+ return this;
+};
+
+/**
* Expose the module at `path`, with optional `namespace`, defaulting
* to the basename, for example `utils/color.js` would expose `colors.dark()`
* etc to the client-side.
@@ -117,13 +138,19 @@ HTTPSServer.prototype.exposeModule = function(path, namespace, name){
, js = fs.readFileSync(path, 'utf8')
, namespace = namespace || basename(path, extname(path));
- js = namespace
- + ' = (function(exports){\n'
- + js.replace(/^/gm, ' ')
- + '\n\n return exports;\n})({});';
+ if (this._require) {
+ this.expose(renderRegister(namespace, js), name);
+ } else {
+ js = namespace
+ + ' = (function(exports){\n'
+ + js.replace(/^/gm, ' ')
+ + '\n\n return exports;\n})({});';
+
+ this.expose(renderNamespace(namespace));
+ this.expose(js, name);
+ }
- this.expose(renderNamespace(namespace));
- return this.expose(js, name);
+ return this;
};
/**
@@ -144,19 +171,19 @@ HTTPSServer.prototype.exposed = function(name){
};
/**
- * Render the given `obj` against `namespace`.
+ * Render a client-side module registration with the given
+ * `mod` name, and `js` contents.
*
- * @param {Object} obj
- * @param {String} namespace
+ * @param {String} mod
+ * @param {String} js
* @return {String}
* @api private
*/
-function renderObject(obj, namespace) {
- return Object.keys(obj).map(function(key){
- var val = obj[key];
- return namespace + '["' + key + '"] = ' + string(val) + ';';
- }).join('\n');
+function renderRegister(mod, js) {
+ return 'require.register("'
+ + mod + '", function(module, exports, require){\n'
+ + js + '\n});';
}
/**
@@ -188,6 +215,22 @@ function renderNamespace(str){
}
/**
+ * Render `obj` with the given `namespace`.
+ *
+ * @param {Object} obj
+ * @param {String} namespace
+ * @return {String}
+ * @api private
+ */
+
+function renderObject(obj, namespace) {
+ return Object.keys(obj).map(function(key){
+ var val = obj[key];
+ return namespace + '["' + key + '"] = ' + string(val) + ';';
+ }).join('\n');
+}
+
+/**
* Return a string representation of `obj`.
*
* @param {Mixed} obj
@@ -198,6 +241,14 @@ function renderNamespace(str){
function string(obj) {
if ('function' == typeof obj) {
return obj.toString();
+ } else if (obj instanceof Date) {
+ return 'new Date("' + obj + '")';
+ } else if (Array.isArray(obj)) {
+ return '[' + obj.map(string).join(', ') + ']';
+ } else if ('[object Object]' == Object.prototype.toString.call(obj)) {
+ return '{' + Object.keys(obj).map(function(key){
+ return '"' + key + '":' + string(obj[key]);
+ }).join(', ') + '}';
} else {
return JSON.stringify(obj);
}
View
43 lib/require.js
@@ -0,0 +1,43 @@
+function require(p){
+ var path = require.resolve(p)
+ , mod = require.modules[path];
+ if (!mod) throw new Error('failed to require "' + p + '"');
+ if (!mod.exports) {
+ mod.exports = {};
+ mod.call(mod.exports, mod, mod.exports, require.relative(path));
+ }
+ return mod.exports;
+}
+
+require.modules = {};
+
+require.resolve = function (path){
+ var orig = path
+ , reg = path + '.js'
+ , index = path + '/index.js';
+ return require.modules[reg] && reg
+ || require.modules[index] && index
+ || orig;
+};
+
+require.register = function (path, fn){
+ require.modules[path] = fn;
+};
+
+require.relative = function (parent) {
+ return function(p){
+ if ('.' != p[0]) return require(p);
+
+ var path = parent.split('/')
+ , segs = p.split('/');
+ path.pop();
+
+ for (var i = 0; i < segs.length; i++) {
+ var seg = segs[i];
+ if ('..' == seg) path.pop();
+ else if ('.' != seg) path.push(seg);
+ }
+
+ return require(path.join('/'));
+ };
+};
View
18 test/express-expose.test.js
@@ -195,5 +195,23 @@ module.exports = {
scope.express.one.should.equal(1);
scope.express.two.should.equal(2);
});
+ },
+
+ 'test app.exposeRequire()': function(){
+ var app = express.createServer();
+
+ app.set('title', 'something');
+ app.exposeRequire();
+ app.expose(app.settings, 'settings');
+ app.exposeModule(__dirname + '/fixtures/color');
+ app.exposeModule(__dirname + '/fixtures/color', 'express/utils/color');
+
+ var js = app.exposed()
+ , scope = {};
+
+ vm.runInNewContext(js, scope);
+ scope.require('settings').title.should.equal('something');
+ scope.require('express/utils/color').light('ffffff').should.be.true;
+ scope.require('color').light('ffffff').should.be.true;
}
};
Please sign in to comment.
Something went wrong with that request. Please try again.