Meteor shell and imports

Coming a bit late to the ecmascript party I am finally getting my head around splitting up my code base and using import (trying to get prepared for async loading in 1.5)

Maybe this is a simple question, but how do you guys manage the fact that when you connect to the server on your development environment with meteor shell that none of the imports have run for the shell process? Is there a magic file that automatically gets imported for the shell?

2 Likes

YMMV, but I usually just keep a few txt files with all of the imports I need, line by line. You can copy and paste multiline into the shell without a problem. Probably not the ideal solution, but I have a file with all of my collections and methods, and then I just add anything else I need to look at the issue.

1 Like

Yeah, I thought of that too, like /api/shell.js which is not getting imported but once in the shell one can simply type

import '/api/shell'

and voila, everything there. I was just wondering if there is some undocumented feature like this already, or a completely different method of accomplishing this.

Yeah, I wouldn’t mind seeing that also, as keeping up with those files can be a bit tedious.

Ok, still not sure if I am doing this right. I created an imports directory with the following structure

imports/startup/server/shell/index.js

where index.js imports all the definitions I want to have access to and does an

export default {
...
}

but when I start meteor shell in my project, any attempt to import anything from the imports folder fails

> import myDefaults from '/imports/startup/server/shell';
packages/modules-runtime.js:494
  throw error;
  ^
Error: Cannot find module '/imports/startup/server/shell'
    at Function.require.resolve (packages/modules-runtime.js:145:19)
    at Module.resolve (packages/modules-runtime.js:95:25)
    at Module.Mp.importSync (/Users/jmangold/.meteor/packages/modules/.0.8.1.g6zpto++os+web.browser+web.cordova/npm/node_modules/reify/lib/runtime.js:79:29)
    at repl:2:8
    at packages/shell-server/shell-server.js:444:27
    at /Users/jmangold/.meteor/packages/promise/.0.8.8.1n2mpy8++os+web.browser+web.cordova/npm/node_modules/meteor-promise/fiber_pool.js:32:39

what am I missing?

Found this thread, but still don’t understand what I am doing wrong

ok, re-reading the other thread and the github issue referenced therein, including

if(false) import '/imports/startup/server/shell';

in my server code it now lets me import from the meteor shell.

Now the original question remains: is there a more elegant or hidden method that would automatically require or import something into the scope of the shell?

1 Like

OK, I am still not sure I fully understand how this is supposed to work. In the past I was able to easily check a collection in the Web Console. Now that I import collections explicitly they are no longer available in the Web Console.

What is the pattern to get access to a collection when using explicit imports?

1 Like

Is this how it’s supposed to work? In the Web Console

Documents = require( '/imports/collections/Documents').default
Documents.findOne();

because that works

I never really figured out the answer to this, or if Meteor shell has some hidden feature (which I still believe would be a great idea). For now my work-around is

  1. create a file /imports/shell.js that gathers all desired objects (like collections) and defines them globally
// get everything needed in the shell
import { Items } from '/imports/collections/items';
// declare globals
global.Items = Items;
  1. list this import in server main so it can be manually imported in the shell (necessary, because the shell doesn’t seem to have a default import/source)
if ( false ) import '/imports/shell'

Now when dropping into the shell I can run import '/imports/shell' and have all the stuff I need at my fingertips

1 Like

I just make my collections global in development:

// file /imports/db/index.js

import { Users } from './users/collection';
import { Folders } from './folders/collection';
import { MediaCollection } from './media/collection';
import { Modules } from './modules/collection';
import { Pages } from './pages/collection';
import { Projects } from './projects/collection';
import { ProjectChildren } from './projects/children';
import { Sets } from './sets/collection';
export {
    Users,
    Projects,
    ProjectChildren,
    Pages,
    Modules,
    MediaCollection,
    DeletedMedia,
    Folders,
    DeletedFolders,
    Sets,
};

if (Meteor.isDevelopment) {
    global.Users = Users;
    global.Projects = Projects;
    global.ProjectChildren = ProjectChildren;
    global.Pages = Pages;
    global.Modules = Modules;
    global.MediaCollection = MediaCollection;
    global.Folders = Folders;
    global.Sets = Sets;
}

And in /imports/startup/server.js I have import '/imports/db'

Basically just so I can easily query from the shell

For everything else, I use require or import to load it up when needed

2 Likes

Thanks for sharing, that is slick. Doesn’t it open you up to issues on development where you might be using a global for a collection, and on production the code won’t work then?

Just realized that’s a non-issue. You just need to set Meteor.isDevelopment to false and can test before deploying …

Yeah absolutely it could cause bugs like that~
We also have pre-commit hooks that run eslint with an import check plugin, so won’t let you push code which doesn’t import stuff correctly