Application Structure

i have some confusion regarding the application structure guide. As far as i understand from the guide that, anything under import folder will be lazy loaded or you can say will load when called via import. and ouside of import folder will be loaded as soon as application starts running.

when i’m installing FlowRouter, my app need to have home ( / ) router.
My question is

  1. what do i need to write in my main.js file and what exactly is entry point meaning.
    will I import my route file and all layout, templates in main.js file?
  2. do imports/startup/ directory files will be executed automatically after app starts to run? or do i need to enclose it within Meteor.startup function.

I’ll break down how the Guide’s todos reference app is handling this, as an example.

When the todos app starts up client/main.js is one of the eagerly loaded files (since it’s not under the imports directory). This means its contents are evaluated right away:

import '/imports/startup/client';

This import statement then loads the defined imports/startup/client/index.js file (since only the directory was specified in the import statement). The index.js file then includes an import statement to load the routes.js file from the same directory:

import './routes.js';

The routes.js file defines your FlowRouter routes, but also imports any templates referenced by the route config (such as your layouts, top level pages, etc.).

No they aren’t executed automatically - in the case of the todos app for example, you’re telling your app to load the startup files by referencing them when your app starts up, via the eagerly loaded client/main.js and server/main.js files.

3 Likes

so i need to actually import all my templates and their js files and layouts files in the routes.js file. am I right?

1 Like

No, not all of them. Just the ones that FlowRouter needs to know about to initialize properly. For example, in imports/startup/client/routes.js, the app-body.js layout is imported since it’s needed by the defined FlowRouter config directly. app-body.js itself imports the imports/ui/components/loading.js component; this file doesn’t need to be imported in the routes.js file directly.

1 Like

I can no longer find any documentation on the default eager load order based on file names and structure. This used to be in Meteor docs, but was removed. In fact, it is still referenced in the docs in modules package with a redirect to this section of the Meteor Guide.

I think some of this info needs to be added back to this section of the guide as 1) not everyone will or wants to adopt 100% import structure, and 2) there are still some special directories such as /public, /private, and mobile /resources, etc.

Here is original file in github.

If others agree I’ll make a pull request.

6 Likes

Yeah that’s a good point, looks like that information just disappeared! Let’s add it as the last section in the application structure article!

Thanks for noticing.

1 Like

Only noticed as I was trying to find some info for one of our developers. :grinning:

Are the index.js files really necessary when all they contain are import statements that could instead be written in client/main.js and server/main.js?

i.e. could these be moved out of imports/startup/client/index.js

import './useraccounts-configuration.js';
import './routes.js';

into client/main.js?

They could be, but if you’re then referencing routes.js and useraccounts-configuration.js in the same directory like your example shows, that means they’re in /client (outside of the imports directory), and will be eagerly loaded. If you wanted to update /client/main.js with something like:

import '/imports/startup/client/useraccounts-configuration.js';
import '/imports/startup/client/routes.js';

then no problem at all. Or any directory within imports really, like:

import '/imports/config/useraccounts-configuration.js';
import '/imports/config/routes.js';

The Guide/todos app are just suggesting a structure, and recommend keeping the contents of the default eagerly loaded files (like /client/main.js and /server/main.js) to a minimum, to help better control load order.

1 Like

Oh this is interesting, I didn’t know you can do

import '/imports/...'

That would’ve made my life a bit easier since I don’t have to count how far up I have to go to load the import.

2 Likes

I am having a hard time determining an approach for finding where to import from, currently referring to the todo app for most cases and just copy/pasting.

For example how does one determine that Accounts should be imported from meteor/accounts-base and that AccountsTemplate should be imported from meteor/useraccounts:core. How does one know that Template is in meteor/templating? Or… if Npm is used, where do we import Npm from?

How does one import packages from FS? For example, a module uses both FS.Collection and FS.FileSystem… what do those import statements look like? Is it one import? Two imports?

It would be very useful to outline this in the guide.

As a side note, I just started with meteor only shortly after the guide was released – kudos on bringing this to the community… I was eagerly awaiting the update for 1.3! It’s been an excellent resource, and it’s great to have a sample app to pair it with. Great job, and thank you! :slight_smile:

1 Like

We added that information to the docs for 1.3! Check them it again if you haven’t looked in a while.

1 Like

Yes, I now see the import statments in the docs, this is great – thanks. In the case of Npm.require I do not see this though…

What about atmosphere packages, like FS? If both FS.Collection and FS.FilesSystem are used, am I correct to assume that the import statement should be import { FS } from 'meteor/cfs:base-package'? I assume this since api.export('FS') is found in packages/base-package/package.js.

UPDATE:

  1. To prevent lint errors for Npm.require() I have set /* global Npm */
  2. import { FS } from 'cfs:base-package' seems to work without errors

Is there a reason why in the todos app an absolute path is used for import statements in client/main.js and server/main.js – but everwhere else it is a relative path? Can absolute paths be used anywhere?

Hey guys, nice work with 1.3, it’s a lot of little things that are going to make the overall developer experience a lot smoother. I’m reading through the guide now and had a couple of questions about this section, namely:

###1. Relative import paths

I found relative paths in the examples that have more than one ‘finding the parent level’, i.e. ../../ hard to follow. In past experience with React projects I’ve also found these tedious to maintain and at certain times difficult to reason about.

I can see a benefit in using relative paths because I’m assuming in future we will be able to move everything from imports/ into the project’s base directory (as one example). At that point we’d have to update a lot of individual files though if we’re using absolute paths, which would be a pain for version control.

I have used Broccoli in the past, which allows you to set a root directory for import statements in the brocfile (basically a project settings.js). So I’m wondering whether a similar option would be possible for Meteor: for now set the base import folder to /imports. Then from your routes.js you could just import '/ui/template/pages/xyz.html', and when the hypothetical Meteor 1.4 comes out and forces everyone to switch to the new imports pattern (making /imports redundant), we could just kill the that directory and change the import root in one line of code.

###2. Clarity about what to import

I found this sentence in particular unclear:

The imports/startup/client/routes.js configures all of the routes and then imports all other code that is required on the client, forming the main entry point for the rest of the client application

My intuition tells me that importing “all other code that is required on the client” is not actually what you’re suggesting. In any case I had to read the section three times to figure out what you really mean. I’m still not sure why importing anything close to ‘all’ code in the router would be advantageous, and what really needs to be imported.

My understanding is that after the (eagerly loaded) startup, the router – for all intents and purposes – forms the ‘root node’ of the app, from which other files are, at least in principle, lazily loaded. So it makes sense for the router to know about other layouts and pages that are directly accessible via routes. Is that the extent for files that should be imported here, or have I missed something?

1 Like

Your imports can be from /imports/... there’s no need for ../../../imports from what I can tell, I use

import { Foo } from '/imports/bar'

Right now, you can already import using absolute paths, so your path becomes '/imports/ui/template/pages/xyz.html', which I think is not so bad because it’s just one more /imports in there.

There’s an open issue about this, I think it definitely could be a loooot clearer.

Hi Sashko, thanks for your response. What you’re saying here is true. As I wrote in my previous answer though, this is a poor solution for version control, especially assuming the /import directory might well disappear in future once lazy-loading becomes the norm (maybe that’s a false assumption, please correct me if I’m wrong):

Our project currently needs to be maintained across ios and web branches (to name a couple), each with varying levels of feature modernity, even different meteor versions, etc. In any case, it would be ideal if we could just import /ui/layout/etc... and then if the base import directory changes, version control only has to deal with a one line change in one file, not thousands across multiple files - does it make sense that the potential for merge conflicts (and difficulty sharing files across versions) is much greater in the second case?

In any case it seems like writing import '/imports/...' with every absolute path import goes against D.R.Y. and is basically unnecessary noise - just for my understanding, is there ever a time where an absolute path wouldn’t start with that?

I couldn’t see discussion of ‘importing all client code’ on that link, which was the main thing I found problematic.

Looking over the section again, there are a few other references to client/main.js // imports all client code etc., I think that wording is confusing. I’m assuming the intention is that main.js should import the starting points / features that in turn import all other code, but the way it’s written makes it seem like you should import every piece of code in your app directly in main.js.

Referring to the import paths, I also noticed there are a bunch of import '../imports/etc'. I don’t have a lot of experience in this realm, but I’m wondering why that’d be considered better practice than import '/imports/etc'. To me the second one is a lot clearer and conciser (as I said above, without ‘/imports’ would be even better, in my opinion)

Hi!

Having trouble understanding how to use modules with ‘package-only’ type application structure.

I’m working on an app with the following structure:

/app
  /packages
    /foo
    /bar

I was following this structure to create flexibility, because I want to isolate features into packages (allows me to plug and play features by importing a package)

The problem I’m having is when trying to import/export between the packages foo and bar. Let’s say I have an exported function called baz() that is implemented in the ‘bar’ package, and I wanted to import that in the ‘foo’ package - I’m not entirely sure where to do this, or if I should abandon the package-structure totally and switch to modules.