Meteor packages decoupled - meteor

Two part question.
1- I managed to create a package with meteor but I had to explicitly assign to the output, now if the package is not available I'll get an error.
How to check if the package is available or enabled and if so use it in code or template.
2- let's say I have 2 packages, projects and tasks, each of them can work separately from the other.
I want to create a projects if project package is available.
I want to create a tasks if task package is available.
I want to assign tasks to projects if these both packages are available.
How to achieve such flexibility with decoupled packages with meteor.

The Package object (on the global scope) list all the installed packages for an application.
You could test the presence of one of your package by doing something like this:
//will return an Object if package is loaded or undefined
if(Package['package:name']) {
//...
}

Related

How to wait for collection to be set in meteor package development?

I am writing my first meteor package. I started writing an app and thought it would be nice, to make one of the main functionalities available for others as open source.
I know in meteor you can make a variable globally accessible by adding an export in the package.js, but how could I do something like the following, assuming my export variable is called "MyPackage"(pseudo code):
.on(AppDefinedMyPackage, function(){})
in the moment this part of the app's code is run(outside of the package, of course):
MyPackage = new Meteor.Collection('test');

What's a safe way to define Meteor server methods for use only in tests?

I want the methods to be available only for tests, and not in application code. For example, a method to delete any user. I don't want this capability in production code. But it's helpful in test code.
How would I add provide such a method in a test context while keeping it out of production code?
Here's one possible solution:
Let's assume you create a package called test-helpers. In it, you create a function called removeAllUsers in the TestHelpers namespace.
Now in another package that needs TestHelpers.removeAllUsers, you can just do this:
Package.onTest(function(api) {
api.use('TestHelpers', 'server');
});
Because we only included the package in onTest, it won't exist in your production code. Furthermore, we created a server-only function (not a method), so even if it did get exposed in production, it couldn't be called from a client.

How to get Meteor Package information within the app?

Is it possible to get a list of all available packages and their configuration within a running MeteorJS app.
I don't mean the CLI command meteor list but something that could let me check if certain packages are available or not and change the programs behaviour accordingly.
Yes.
Using code from the meteorhacks SSR package as an example, you can see that it does this to check for the existence of the Jade package:
if(Package['mquandalle:jade-compiler']) {
Compilers.jade = Package['mquandalle:jade-compiler'].JadeCompiler;
}
The caveat is that the other package has to be added first.

What does api.imply do?

From the Meteor docs:
Give users of this package access to another package (by passing in the string packagename) or a collection of packages (by passing in an array of strings [packagename1, packagename2]).
I have no idea what it means.
From this question I know that imply can be employed with use.
What does api.imply do?
What's exactly the difference between api.use and api.imply?
api.use gives a package access to other packages exported symbols.
For example you need to api.use("random") (see how it's done in the accounts-base package) if you want to use the Random symbol in a package code (see how the random package.js is api.exporting Random).
However, meteor adding accounts-base wouldn't give your whole application access to its used packages (random in this case). If your app needs random, you'd still need to meteor add it.
api.imply on the other hand, gives the whole application access to that package exported symbols.
For example, see how accounts-google is api.implying accounts-base.
accounts-base is responsible for exporting the Accounts symbol, when you meteor add accounts-google, not only does accounts-base is also added in your application dependencies, but accounts-base symbols are also made available in your app, specifically because it was implied.
accounts-base is both using Accounts in its own code (api.use) and exporting its dependencies symbols to the whole app (api.imply).
api.imply can be used to make "shadow packages" that are just pulling in some other packages.
For example, at some point MDG renamed the showdown package to markdown, they could just have stated to meteor remove showdown && meteor add markdown, but it would have required some actions on end users.
What they did instead is keeping the showdown package and just make it implying the new markdown package.
If you have something in your app that consumes api from package:name and you install just package package:dependant which has a package:name as a dependency, but you don't use imply here, your api from package:name will not work in the app. It will work only in package:dependant package. You need use imply if you want to use something from package:name outside your package:dependant
I don't know if this is clear ;)

If I use api.imply in package.js do I have to use api.use for the same package?

When construction meteor packages you can add files like this:
api.use('fourseven:scss#0.9.4', ['client', 'server']);
You can also tell meteor to give the package user access to other packages like this:
api.imply('fourseven:scss#0.9.4', ['client', 'server']);
In the documentation it's not clear if implying a package also makes it available. For instance, I'm not sure if it is redundant to do this:
api.use('fourseven:scss#0.9.4', ['client', 'server']);
api.imply('fourseven:scss#0.9.4', ['client', 'server']);
I've just tested this use case with a couple packages of mine and I can assert that implying a package doesn't make it available automatically in the package source.
So it means that
api.use("foo:bar#x.y.z");
api.imply("foo:bar#x.y.z");
is NOT redundant if you intend to use and reference foo:bar in the current package source.
You can think of api.imply as an api.use for the app context that has no impact on the current package context.
I've heard that some time in the future they plan to integrate a package-like API for the app context, which is going to be useful to address load order among other things.

Resources