1.3 best practice package based architecture, and how does package.js fit into 1.3?

We have several meteor projects that share models / methods / helpers. In order to do this, we’ve adopted a package based architecture similar to the one described in this article:

http://experimentsinmeteor.com/package-based-architecture/

We would like to start sharing react components as well, and I’m curious how package.js fits into 1.3.

  1. Can we use Npm.depends to include npm libraries on the server AND the client? Ie can we get rid of the cosmos browserify craziness that we currently have setup in our package?
  2. If a project includes a package, and that package Npm.depends on React, can we “import React from ‘react’;” in the project?
  3. When a project compiles for production, will it only include those components / modules from the package that the project imported, or will it include all components/npm deps described in the package’s package.js file?

Basically, our ideal scenario is that we have a package that holds all of our common components, methods, helpers, etc. Each project can include the package, and import the components and pieces of functionality it needs. When the project is compiled for production, only the imported components/modules (and their dependencies ie anything they import) are included in the final compiled artifact.

@arunoda I remember seeing something about Mantra “modules” - will that tackle the type of problem described in the blog post above?

3 Likes

With Meteor 1.3, you won’t have to use Npm.depends OR cosmos:browserify. The module system in 1.3 is being implemented specifically to handle directly importing NPM packages into your Meteor project, both on the client and the server.

If you create a top level package.json file and install NPM modules, you will be able to import them anywhere in your application by using ES6 import statements. You will also be able to export variables as well using the ES6 syntax.

The problem you are looking to solve is quite common and quite simple. You have a couple of options. If your “common” package includes any Meteor code (subscriptions, models, Meteor methods, etc), then create a Meteor package that you share across your projects. The easiest way to do this is probably using a git submodule.

If you are dealing with pure React components that don’t directly rely on Meteor, but use a flux architecture like Redux, you can simply create an NPM package and share that across your projects directly. You can start on organization on NPM which costs $7/user and host as many private / public packages that you want and very easily publish them and pull them in to projects.

The second solution is better both short-term and long-term. NPM is a great package manager and is much easier to manage versioning and staying up to date by pulling a version of a package than by trying to keep git submodules in sync. I have always found submodules to be a bit of a pain in the ass.

This is a great blog post that explains how import / export works in ES6: http://www.2ality.com/2014/09/es6-modules-final.html. It’s worth a read if you’re not familiar with it and I know I can’t wait until Meteor 1.3 is published and we can start writing statically analyzable ES6 without globals.

1 Like

Awesome, thanks for the response!

We’ve started exploring the NPM route, and are still trying to figure out how to efficiently build the final artifact.

// the main.js file in our core/shared npm module, "core-ui"
import React from 'react';

import Actions from './actions';

import EndpointList from './components/endpoints.list';
import CodeHighlight from './components/code.highlight'; // uses highlight.js, heavy

export {
  Actions,
  EndpointList,
  CodeHighlight,
};

If any meteor project depends on “core-ui”, highlight.js will be pulled in, even if no files in that project import the CodeHighlight component above (which is what imports highlight.js).

What would be awesome is if the Meteor build step could somehow resolve/pull-in only the imported components to the final compiled artifact. I’m not sure if this is an NPM limitation.

For now, we can of course split that CodeHighlight component into a separate npm module, and include it in particular meteor projects. However, it would be awesome to have a central repository (npm module) that contains all of our shared components. Then, a meteor project can import the components it needs from the package, and only those components and their dependencies are included in the final compiled artifact.

Not sure if that’s possible - but would be nice.