简体   繁体   中英

Sharing Meteor functions between server, client, and all files without declaring them global?

Say that I've got functions that I want to re-use between multiple files on BOTH server and client. I could just make them global, place them into a common code folder, but that's no good.

/lib/master_file.js

add = function(num1, num2){
  return num1 + num2;
};

subtract = function(num1, num2){
  return num1 - num2
};

/client/client_file1.js

add(4,4);
subtract(10,3);

/server/server_file1.js

add(9,1);

/server/file2.js

subtract(8,2);

--POSSIBLE SOLUTIONS--

I can create a global object and attach the functions as values of the global object.

/lib/master_file_v2.js

var add = function(num1, num2){
  return num1 + num2;
};

var subtract = function(num1, num2){
  return num1 - num2
};

global = {

  add: function(num1, num2){
    return add(num1, num2);
  },
  subtract: function(num1, num2){
    return subtract(num1, num2);
  }

};

Then I would have to call the functions like so.

/client/client_file1.js

var add = global.add;
var subtract = global.subtract;
add(4,4);
subtract(10,3);

/server/server_file1.js

var add = global.add;
add(9,1);

/server/server_file2.js

var subtract = global.subtract;
subtract(8,2);

Is there a way to not call the functions like this? I would prefer to directly call them by their names but without declaring them as global.

/client/client_file1.js

add(4,4);
subtract(10,3);

/server/server_file1.js

add(9,1);

/server/server_file2.js*

subtract(8,2);

modules

On the server side I believe I can use module.exports but modules isn't available on the client side, so that doesn't work. I could use a modules library for the client side but I think it might break with Meteor's unique code-sharing between the client and server in /lib if I were to declare modules there?

Meteor.methods

Calling them is pretty wordy and when defined in /lib they get run on both the client and server, which isn't always what you want...

If you want a piece of code not to be seen, you can't push it to the client. So you'll have put it in a method . That's the only meteor-native way. You can nicen up the Meteor.call api with something like this:

lib/

methodCaller = function methodCaller (methodName) {
  return function (/*arguments...[, callback]*/) {
    var callback = arguments.slice(-1)
    Meteor.apply(methodName, arguments, methodCallback)
  }
}

Meteor.methods({
  test: function (n) {
    return n*2
  }
})

test = methodCaller('test')

anywhere

test(1, function (err, result) {
  console.log(result)
})

If you are afraid of cluttering, just use a closure or as you proposed, a simple object. You don't have to define a local-scope variable to use a function stored in an object. You can just use it like this:

anywhere

globals.add()

Now I think globals is to generic a name. That just moves the cluttering problem to a different place. In your example you could for an example define a mathUtils object instead.

I don't use closures very often. There are some cases where it can bring a big benefit. once is a good example of this:

once = function (func) {
  var hasBeenTriggered = false
  return function (/*arguments*/) {
    if(hasBeenTriggered) return
    hasBeenTriggered = true
    return func.apply(null, arguments)
  }
}

This might not look like most closures, but it is one. Here hiding hasBeenTriggered is essential for the integrity of the function. Try not to hide unnecessarily. Having lots of hidden functions makes it harder to write good tests.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM