11

I know how to write Meteor packages but I can't seem to figure out how to have all exports land in my app's namespace, as described in this presentation.

This particular package is specific to an app I'm building, and it exports only one method that can be regarded as a decorator on the app's singleton. I tried api.export('MyApp.myMethod') but that gives an error native: Bad exported symbol: MyApp.myMethod.

If I just api.export('myMethod'), then in the app code I have to call myMethod(), and that's not namespaced.

Does Meteor have a mechanism similar to Node's var http = require('http');? Or how can packages export symbols into a given namespace?

Community
  • 1
  • 1
Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404

3 Answers3

8

The api.export method is only supported for top-level variables right now. It doesn't work for nested variables, because "it turned out that using deep exports was very confusing", and what would you expect MyApp.myMethod to appear as in the global namespace if you also exported MyApp.myOtherMethod?

You should just export MyPackage, and then call MyPackage.myMethod(). A common approach is to do something like

MyPackage = { 
    myMethod: someSecretMethodName,
    myOtherMethod: otherMethodName
}

And then call api.export("MyPackage"). This means that the exported names of variables don't necessarily have to be what you called them. This is used a lot in the core meteor packages; you can also see an example at for MongoInternals in mongo_driver.js.

Andrew Mao
  • 35,740
  • 23
  • 143
  • 224
  • 1
    So essentially I can't have `MyApp.MyPackage.method()` because that would be a deep export? – Dan Dascalescu Mar 18 '14 at 01:12
  • @DanDascalescu you can have that as long as you export the top level `MyApp` variable, with nested `MyPackage` and `myMethod`. – Andrew Mao Mar 18 '14 at 01:23
  • 1
    But that means that the package would need to export `MyApp`, which is semantically dubious. `MyApp` would be the app's global namespace, and @sewdn's [presentation](http://meteor.redandivory.com/#/7/1) suggests that `MyPackage` should become a member of `MyApp`. – Dan Dascalescu Mar 18 '14 at 01:44
  • 2
    I think you maybe confusing yourself with the nomenclature. The package should export `MyPackage`, which will then become accessible in the namespace of your app, but it will not become a member of the app's namespace. – Andrew Mao Mar 18 '14 at 03:14
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/84403/discussion-between-pixelass-and-andrew-mao). –  Jul 27 '15 at 19:55
6

All properties that you register in your app namespace are made available for the packages that depend on (use) your app-package. So, when you want to register a package namespace in an app-namespace, you declare the dependency on the app-package within your package and you register all of the methods/objects you want to export in the app-namespace. An example:

file: packages/myapp/namespace.js

MyApp = {};

file: packages/myapp/package.js

Package.on_use(function (api, where) {
  api.add_files([
    "namespace.js"
  ], ['client', 'server']);
  api.export("MyApp", ['client', 'server']);
});

file: packages/myapp-module1/logic.js

packageSpecificMethod = function(){}
moduleOne = {};
//you can export an module-specific namespace by registering it in the app-namespace
MyApp.module1 = moduleOne;
//or you can (if you dont want package-namespaces) register you private methods in the app-namespace directly
MyApp.exportedMethod = packageSpecificMethod;

file: packages/myapp-module1/package.js

Package.on_use(function (api, where) {
  api.use([
    'myapp'
  ], ['client', 'server']);
  api.add_files([
    "logic.js"
  ], ['client', 'server']);
});
Sewdn
  • 76
  • 1
3

In your package, you should define all methods and symbols in the namespace you want them to have, and then export that namespace. So, if in your package you've got:

MyApp = {
   myMethod: ...
};

Then you export it with api.export('MyApp').

Unfortunately, there's no method similar to the one in Node you've mentioned, as all packages are loaded globally on startup.

Hubert OG
  • 19,314
  • 7
  • 45
  • 73
  • Sorry, I've messed up, you need to export `MyApp`, not `myMethod`. Edited the answer now. Also, make sure to add `myPackageCode.js` file using `api.add_files()`. – Hubert OG Mar 18 '14 at 06:10