Application Structure

Hi guys,

just letting you know that I stumbled upon a use-case where I need to FORCE a REAL RELOAD when using require() (without using the require-cache).

I have NOT found a solution how to achieve this in meteor and opened this topic [solved] How to force ``require-reload`` when using ``require``?.

Maybe anyone has an idea how to do this?

ā€œMeteor 1.3 Application Structure for Dummiesā€

Hi Guys,

I guess thatā€™s what best describe my doubts:

  1. The guide says: ā€œit is recommended that you write your application to use ES2015ā€¦ provide backwards compatibility with applications written for Meteor 1.2 and earlierā€. Does it means eager loading will eventually be deprecated? Should I hurry?
  2. The guide says ā€œYou may combine both eager loading and lazy loading using import in a single appā€. What happens to Atmosphere packages added by Meteor add <package> and go inside .Meteor folder, not imports? When do I need to import them on my code, when I donā€™t?
  3. If I declare importing one atmosphere package, what happens with the load order of the rest of the undeclared ones? Is it a declare all packages or none deal?
  4. Do I have to declare import on all NPM packages? If I choose to work with the eager loading path only, how would that works?
  5. The Guide mentions the ā€œLoad orderā€, but they are actually all loaded at the same time as all files are minified and gziped into one single .js, .css. html files, etcā€¦ Are there plans to actually splitting code and load on client only as needed?
  6. Is it mandatory to declare import { Meteor } from 'meteor/meteor' ? If so, where is the best possible place? What would one gain / loose by declaring it later in the application?
  7. import surely means a lot for larger projects with larger teams. I understand that this is because it helps modularizing the application and avoid crowding Global space into a messy thing. It also replaces the not so elegant lib folder and file naming schemes to assure code dependency order. But for smaller teams / projects, what other benefits can one expect? Improved app / load speed? Would the extra complexity pay off? Can we justify it?

I will let someone more experienced amswer your questions as Iā€™m also trying to grasp this, but using module imports is entirely optional at this time. You can still use the old way if you prefer. Touching on you last question, it may even be the preferred way for small projects, depending on your requirements.

Like you said, there is currently no lazy loading or code splitting, since everything is compiled to a single file. At least thatā€™s my understanding.

1 Like

@tmeasday not really ground breaking but where would you suggest to put some basic html files that arenā€™t really ui like a simple head.html containing the <head> head tag as it grows in an application? Directly inside the /client/head.html

edit: i assume my guess to be right looking at this commit:

Hello all,

It would be a really nice addition to make an alternative application structure recommendation for large projects suggesting package-esq structure. Like what is being done at https://github.com/TelescopeJS/Telescope

There are many articles out there with some very neat ideas,

Why?

  • Such structures go very well with Functional Programming paradigms
  • It especially plays well with React-Redux applications
  • The idea is to have each package do one thing, and one thing only
  • Each package is a complete mini-application in and of itself
  • It makes debugging large applications a breeze
  • The folders are very well organised
  • There is a very clean chain of dependencies, thus dependency management is very easy

I can take up writing this part if MDG is okay with it.

Best

Would this be Meteor packages or npm packages?

Understanding the best way to structure a large app with npm packages (modules) would definitely be worth publishing.

Both. There would be NPM packages as well as Meteor packages.

Have a look at < https://github.com/TelescopeJS/Telescope > for example. This is a very good way to structure a large app. Other large apps can be structured in a similar way.

More precisely, look at - https://gist.github.com/SachaG/f22e04bf91751435806d. Meteor packages can be managed like that.

And, NPM packages are installed globally in the usual way. See https://github.com/TelescopeJS/Telescope/blob/master/package.json for instance

You misunderstand. Iā€™m very familiar with that approach - and most Meteor devs involved in large app development probably are too. However, imagine a world with no atmosphere or Meteor package manager. How would we go about writing a package structured app where current ā€œlocalā€ packages are not Meteor packages, but npm modules.

So, more:

  • how to write npm modules
  • how to manage dependencies
  • how to have local (private) modules
  • etc.

Like it or not, the fact is that MDG are becoming more mainstream JS - and that means npm. I donā€™t expect the Meteor package manager to disappear overnight, but npm is clearly the way weā€™re being steered - and thatā€™s also the direction most ā€œtraditionalā€ Meteor devs are least comfortable with.

Iā€™d considered writing something for this myself, but Iā€™m currently too involved with project work to devote much time to it.

4 Likes

Hmmm, thatā€™s a good one. How would you about doing that? Do you have any example project that uses this kind of setup?

And therein lies the problem opportunity. :wink:

My idea was to develop the documentation while building the app. As I say - not enough hours in the day atm.

I tried looking into doing that myself, I had it to a point but then I realize it isnā€™t worth it unless the a submodule itself is packageable.

The main reason was we now have import and that allows us to pick and choose which parts we would want in the application to load given the scope (using eslint). In the older versions of Meteor everything was loaded and packages were the only good way of limiting scope, but that is no longer the case.

Other issues:

  • There is also no inherit version from parent so you would need to sync up manually.
  • You lose some of the IDE type checks because the eslint-meteor-import-resolver will only check that the package is valid, it will not follow down to read a file since it wonā€™t know how to resolve it.
  • because of the above, some refactoring tools are not available to you either.
  • Thereā€™s more boilerplate code

Iā€™ve had issues with this on Java land too. Where an application is broken down into separate projects and it ends up it a lot of plumbing code for small amounts of code like https://github.com/TelescopeJS/Telescope/tree/master/packages/nova-forms-tags. Things wouldā€™ve been easier to just lump most of it into one project.

When packaging I usually recommend it to be broken down by tiers (i.e. server-side, client-side, domain, services/messaging) in JEE you would do that because of their packaging structure (WAR, EAR, EJB, Web services) and refactor out reusable components that can be maintained outside the project as needed (i.e. someone from another project asked for it).

I tried to do it on Meteor, but when I did it it was more plumbing for little benefit. Meteor has well defined API starting points for client and server (i.e. put stuff into the client and server folder). The only annoying part about Meteor is anything outside those and imports are loaded in both so the only thing I would have in that common area is a gulpfile.js and JSON configuration files because the tools need it that way.

Anyway donā€™t let me detract you, you may have better experience.

1 Like

Iā€™d disagree, and my career experience has mostly been in being the lead software architect / tech on multi-million line applications with teams of as many as 80 engineers and a co-lead on one with over 200.

That structure was developed largely because modules werenā€™t built into the language yet. I could see having it discussed as an alternative, but Iā€™d rather see a much better article focused on getting the most out of modules for the mainstream large application.

In the Guideā€™s 1.3 Migration article the Recommendations: Modules section has a specific recommendation to convert local packages that were not created for the purpose of sharing code between applications from packages to modules within your app. In other words, the best reasons the local package organization arose have gone away. So local packages should go away in favor of the standard direction ECMAScript has chosen.

I believe that ES6 modules actually now offer a richer organization capability for large projects versus a single, usually big and flat, packages or node_modules directory. Building a full tree of all of my moduleā€™s dependencies on each other when they are in packages involves parsing every package.js and packages.json. With modules and a little organization, much of that tree can just appear in the directory structure. The interfaces are also better defined and more flexible in modules.

The only weakness Iā€™ve seen in the module approach is that it is a bit weak on privacy. But, at least you can easily see every fileā€™s dependencies. It would be trivial to write your own scanning mechanism to enforce whatever rules you choose about importing across certain directory boundaries. If I were writing a large product using multiple developers in Meteor today, Iā€™d consider something like requiring an explicit comment to an export, something like // public export, that is allowed to be imported by modules that are not within or under the current directory and then creating a little script that can scan for imports that violate that between running lint and running tests.

But that even illustrates my point about the flexibility of the module system for large projects. It defines my interfaces very nicely, gets rid of global hell, and enables me to easily make rules that fit my project in a manner that follows a standard that goes well beyond Meteor ā€“ ECMAScipt.

1 Like

Putting all of my imports/ui/ code into imports/ui/client has dramatically reduced my build times when working on my React components. Only a client refresh is done. Is there any reason not to do this? If not, perhaps it should be the recommended structure in the Meteor Guide.

Iā€™m surprised. Is there a reported issue on this? Changes in any file within an ā€œimportsā€ directory that is not explicitly imported into server code should not trigger a server rebuild as there are no server dependencies on the file.

Iā€™m starting a new project and finally decided to ditch Blaze/Coffeescript to try React and see how much better it is.

I noticed how long it took to get UI changes reflected (5 seconds or so) and noticed the server was rebuilding every time. I moved imports/ui to imports/client/ui, kinda the opposed of @jpillar but it really helped with build times! Now client changes just refresh the browser in a second or two.

If this isnā€™t considered a bug then the guide should really suggest a structure with a client folder under imports. Note that having imports under client does not change anything, the server will still rebuild for client changes.

2 Likes

I think this is probably a good recommendation to makeā€¦ perhaps we can just recommend imports/client instead of imports/ui until this is improved? What do you think @tmeasday?

1 Like

Yeah, this is a bummer. See: https://github.com/meteor/meteor/issues/7434

2 Likes

Regarding the client/server code separation, how would you structure your imports ? For instance, I want to create a token login module for my app. There is business logic that happens on the client side only and some on the server.

Client :

  • Read the query url to extract token from parameters (in startup.js ?)
  • Call the login method and handle the callback

Server :

  • Generate the token
  • Login handler

How do I structure my imports, so when I import my module api on the client side I only get the client api and the same for server? Also, I would have codes that would need to be run at startup.

Here is a startup from how it could be done but I need your opinion

/imports
  /token-login
    index.js
    token-login.js      # Defines the api object TokenLogin
    /client
      token-login.client.js    # Defines logic to call the login method 
      startup.js           # Code extracting the token form url
    /server
      token-login.server.js    # Defines the login method

Would it be better to have two different object like LoginTokenClient and LoginTokenServer ?

Thanks !!

That is a pretty reasonable approach. Youā€™re following the packages-only structure, expect within the /imports folder; and using the classic directory naming conventions in your feature.

The only consideration that I can think of is whether the classic directories should go up a level, and whether to put your feature in an /imports/features dir.

1 Like

How do you name additional functions within a ā€˜componentā€™, ā€˜moduleā€™ etc? Sometimes I may have plenty of them in external files within a folder located in the same place with the component or module, and name the folder ā€˜helpersā€™, though they are not typical Meteor template helpers, just additional functions that are extracted into separate files to keep the actual Meteor templates code/logic clear.

For example:

imports/
  ui/
    layouts/
      header/
        helpers/
          some-function-one.js
          some-additional-function-two.js
        header.less
        header.html
        header.js
        

Renaming the folder to ā€˜functionsā€™ seem to be not correct because sometimes I can store there constants and not functionsā€¦ :-/ While lib is also reserved keyword for foldersā€¦ And I donā€™t want that to load automatically before I specifically import that function to a helper etcā€¦ I wonder if there is a better approachā€¦