14

I followed the documentation to put the constants in the lib/constants.js file.

Question: How to access these constants in my client side html and js files?

Ankur Soni
  • 4,597
  • 4
  • 32
  • 63
David Mckee
  • 1,012
  • 1
  • 17
  • 35

2 Answers2

43

Variables in Meteor are file-scoped.
Normally a var myVar would go in the global Node context, however in Meteor it stays enclosed in the file (which makes it really useful to write more transparent code). What happens is that Meteor will wrap all files in an IIFE, scoping the variables in that function and thus effectively in the file.

To define a global variable, simply remove the var/let/const keyword and Meteor will take care to export it. You have to create functions through the same mechanism (myFunc = function myFunc() {} or myFunc = () => {}). This export will either be client-side if the code is in the client directory, or server-side if it is in the server directory, or both if it is in some other not-so-special directories.
Don't forget to follow these rules:

  1. HTML template files are always loaded before everything else
  2. Files beginning with main. are loaded last
  3. Files inside any lib/ directory are loaded next
  4. Files with deeper paths are loaded next
  5. Files are then loaded in alphabetical order of the entire path

Now you may run into an issue server-side if you try to access this global variable immediately, but Meteor hasn't yet instantiated it because it hasn't run over the file defining the variable. So you have to fight with files and folder names, or maybe try to trick Meteor.startup() (good luck with that). This means less readable, fragile location-dependant code. One of your colleague moves a file and your application breaks.
Or maybe you just don't want to have to go back to the documentation each time you add a file to run a five-step process to know where to place this file and how to name it.

There is two solutions to this problem as of Meteor 1.3:

1. ES6 modules

Meteor 1.3 (currently in beta) allows you to use modules in your application by using the modules package (meteor add modules or api.use('modules')).

Modules go a long way, here is a simple example taken directly from the link above:

File: a.js (loaded first with traditional load order rules):

import {bThing} from './b.js';
// bThing is now usable here

File: b.js (loaded second with traditional load order rules):

export const bThing = 'my constant';

Meteor 1.3 will take care of loading the b.js file before a.js since it's been explicitly told so.

2. Packages

The last option to declare global variables is to create a package.

meteor create --package global_constants

Each variable declared without the var keyword is exported to the whole package. It means that you can create your variables in their own files, finely grain the load order with api.addFiles, control if they should go to the client, the server, or both. It also allows you to api.use these variables in other packages.
This means clear, reusable code. Do you want to add a constant? Either do it in one of the already created file or create one and api.addFiles it.

You can read more about package management in the doc.

Here's a quote from "Structuring your application":

This [using packages] is the ultimate in code separation, modularity, and reusability. If you put the code for each feature in a separate package, the code for one feature won't be able to access the code for the other feature except through exports, making every dependency explicit. This also allows for the easiest independent testing of features. You can also publish the packages and use them in multiple apps with meteor add.


It's amazing to combine the two approaches with Meteor 1.3. Modules are way easier and lighter to write than packages since using them is one export line and as many imports as needed rather than the whole package creation procedure, but not as dumb-error-proof (forgot to write the import line at top of file) as packages.

A good bet would be to use modules first, then switch to a package as soon as they're tiring to write or if an error happened because of it (miswritten the import, ...).
Just make sure to avoid relying on traditional load order if you're doing anything bigger than a POC.

Kyll
  • 6,830
  • 6
  • 39
  • 56
  • Great answer! I voted up David's instead thou as adding a constants file within a /lib directory will load it before everything else anyway. – Will Parker Nov 10 '14 at 10:31
  • 4
    That's what I thought first too, but something went wrong when building the app. Even when I put my global variables in the (root)/lib folder, with or without a `Meteor.startup()` callback, Meteor said the application was having errors because `SOME_GLOBAL_VARIABLE` wasn't defined... Everything is okay when accessing it inside a publication for example (since that's triggered by clients), but calling it immediately in another file didn't work at all. So I did a package in the end! – Kyll Nov 10 '14 at 12:00
  • Was struggling with the same problem but found that once I removed the `var` keyword I would get undefined errors since I was using `"use strict";` at the top of my JavaScript files (which I think is essential). Having a look at this thread cleared a lot up for me https://github.com/meteor/meteor/issues/1380 – Precastic Jun 12 '15 at 11:00
13

You will need to make them global variables in order for other files to see them.

JavaScript

/lib/constants.js

THE_ANSWER = 42; // note the lack of var

/client/some-other-file.js

console.log(THE_ANSWER);

CoffeeScript

/lib/constants.coffee

@THE_ANSWER = 42

/client/some-other-file.coffee

console.log THE_ANSWER
Thai Tran
  • 9,353
  • 6
  • 39
  • 59
David Weldon
  • 59,944
  • 10
  • 136
  • 139
  • 1
    It's helpful to namespace your globals: https://medium.com/@sirchill3/meteor-managing-the-global-namespace-5a50080a05ea – rpisryan Jul 05 '15 at 07:50