2

This is how I import all collection declarations with methods, fixtures and publications now:

import './news/collection.js';
import './news/methods.js';

if (Meteor.isServer) {
    import './news/server/fixtures.js';
    import './news/server/publications.js';
}

If you add some new collection, you have to write it again:

import './comments/collection.js';
import './comments/methods.js';

if (Meteor.isServer) {
    import './comments/server/fixtures.js';
    import './comments/server/publications.js';
}

When you have tons of collections you have to write it again and again. Eventually for the sake of DRY you would like to write something like this:

let collections = ['news', 'comments', ... 'everything'];

for (let collection of collections) {
  import `./${collection}/collection.js`;
  import `./${collection}/methods.js`;
  if (Meteor.isServer) {
    import `./${collection}/server/fixtures.js`;
    import `./${collection}/server/publications.js`;
  }
}

Now The Unexpected token, expected { error throws.

I searched Meteor documentation and can't belive it: is it really no way to import something by dynamic path with Meteor?

ivanzolotov
  • 594
  • 1
  • 4
  • 10

4 Answers4

3

dynamic imports are now supported after yesterday's release of meteor 1.5

I just wrote an article about how to do this and, more importantly, when and why to do this.

https://code.zeroasterisk.com/2017/05/meteor-1-5-bundle-optimization/

TL;DR: import('./my_component') returns a promise, which resolves when the client has it.

before: normal import part of clientside bundle

import PickDates from './PickDates';

after: dynamic import no longer a part of clientside bundle

import Loader from 'react-loader';

// generic loading component to show while transfering section of code
const LoadingComponent = () => <span className="text-muted"><i className="fa fa-refresh" /></span>;
// new version of the component, now: loading --> rendered
const PickDates = Loader({
  // this does the dynamic import, and returns a promise
  loader: () => import('./PickDates'),
  // this is our generic loading display (optional)
  LoadingComponent,
  // this is a delay before we decide to show our LoadingComponent (optional)
  delay: 200,
});
zeroasterisk
  • 2,199
  • 1
  • 23
  • 28
1

Dynamic imports are not supported. There are many people who would like to do this (myself included), but it's not available yet, either in Meteor or elsewhere, as importing is an ES6 feature

Mikkel
  • 7,693
  • 3
  • 17
  • 31
1

es6 does not support dynamic imports (see Importing modules using ES6 syntax and dynamic path)

however, you can use dynamic importing using CommonJS style requiring in Meteor

so something like this should work:

let collections = ['news', 'comments', ... 'everything'];

for (let collection of collections) {
  require(`./${collection}/collection.js`);
  require(`./${collection}/methods.js`);
  if (Meteor.isServer) {
    require(`./${collection}/server/fixtures.js`);
    require(`./${collection}/server/publications.js`);
  }
}
Community
  • 1
  • 1
srtucker22
  • 256
  • 3
  • 11
1

Dynamic imports are not supported.

However this looks like an anti-pattern. One of the benefits of manually loading your modules (as opposed to the old style meteor 'eager loading') is that it because it is explicit, it is easy to see where your imported code is coming from.

It is also important to minimize your imports by not bulk importing everything so that you can see the dependencies in your code.

i.e. if I change this module's api, I can search for the other modules that import it and update the

Do all your modules need to access to all collections, and their methods, fixtures, publications?

Most of the time rather than using Meteor.isServer you should move this code into a /server directory. When code is shared you can use require as documented here

There are other patterns (i.e. code splitting) that will benefit from dynamic loading, but I think you would be better of looking at minimizing your imports.

JeremyK
  • 3,240
  • 1
  • 11
  • 24
  • Got it. Thank you, Jeremy. I'm aware of require syntax and tried exactly the same code srtucker22 offered below. In that case I get very strange Cannot find module './news/collection.js' error. – ivanzolotov Nov 29 '16 at 06:41
  • This is either path problem (maybe require acts not as import and resolves path in a different way especially if require calls from the import chain) or syntax problem with required files. I mean, don't I have to make some special export declaration or something to make it work properly? – ivanzolotov Nov 29 '16 at 06:47
  • Well, your `import` statements are being converted into `require` statements. All ES6 code is transpiled by the ecmascript package (using babel) into commonjs, so there shouldn't be any problem loading with `require` a module that is written using es6 `export` statements. – JeremyK Nov 29 '16 at 09:59
  • Did your original `import './news/collection.js';` and `import './news/methods.js';` statements work as expected? I highly recommend you stick to this explicit importing of the modules you need in each file. – JeremyK Nov 29 '16 at 10:02
  • Original imports works perfect. And you've sold me the idea to stay with my original "hardcoded" imports. – ivanzolotov Nov 29 '16 at 14:51
  • The only thing... I'm just curious why require-way doesn't work for my. Have to mention, I don't use 'export' statements inside original modules. I suspect now I do everything wrong. So I have to get more solid understanding of how modules work both in Meteor and ES6. – ivanzolotov Nov 29 '16 at 14:56
  • 1
    You may want to look at [http://stackoverflow.com/a/29722646/4039693](http://stackoverflow.com/a/29722646/4039693) for more ideas on how to organize your imports. Creating an index.js file will allow you to remove some of the boilerplate, while remaining explicit in what you import. – JeremyK Nov 29 '16 at 21:39