Meteor - Misc

meteor

How can we support sticky session with IE8 or 9?

IE 8 and 9 do not send cookies with Ajax requests; so this breaks our load balancer, which we’ll be exploring in the next section. Fortunately, SockJS has a solution for that, but it is turned off by default with Meteor. To turn it on, you need to export the following environmental variable:

export USE_JSESSIONID=1

How can we run another TCP server inside Meteor?

if (Meteor.isServer) {
    var net = Npm.require('net');
    var server = net.createServer(function (client) {
        console.log('A client connected!');
    });

    server.listen(17231, function() {
        console.log('Server bound to 17231!');
    });
};

How can we parse inbound email from Sendgrid?

Use body-parser and Picker. It sounds like the incoming content from SendGrid doesn't have a application/json Content-Type, so bodyParser.json() can't parse it properly. Try adding a bodyParser.urlencoded() call as well, to try to parse a application/x-www-form-urlencoded Content-Type, to see if that helps. So something like:

var bodyParser = require('body-parser');

Picker.middleware(bodyParser.json());
Picker.middleware(bodyParser.urlencoded({ extended: false }));

Picker.route('/incoming/', function(params, req, res, next) {
  console.log("Body: " + JSON.stringify(req.body));
}

How can we bundle data files into the build?

If they are meant to be served statically, you need to put them into /public. If you access them from the app itself (programmatically), then I would recommend /private and opening them using the Assets object (docs.meteor.com/api/assets.html). It seems like I could put them in /private and then use Assets.absoluteFilePath to figure out the directory that they end up in

How can we use Meteor with Subversion?

svn propset svn:ignore -F .gitignore .

Notice the dot at the end. https://groups.google.com/forum/#!topic/meteor-talk/p4kJs5xUNJc

How can we use Meteor for the front-end development but with other back-end technologies?

This is probably very easy. With autoform, instead of using DDP message, we can use regular form. If we want to use DDP, there are DDP libraries for other language as well.

How can we serve our own HTTP request?

To server http requests over meteor you need a router. I would recommend ironRouter:

Router.map(function () {

this.route('serverFile', {
    path: '/pathonserver',

    action: function () {
      console.log(this.params); //Contains params

      this.response.writeHead(200, {'Content-Type': 'text/html'});
      this.response.end('hello from server');
    }
  });
});

How can we get the userID from the server side?

Use Meteor.userId() or if you are inside a DDP Method, use this.userId

How can we get the userID from inside a Fiber function?

http://stackoverflow.com/questions/14914885/how-to-get-current-user-in-custom-route

How can we develop an application with Meteor that must support the "offline" functionality?

Why should we architect our application as a collection of packages?

All functionality that should be reusable across different applications should be implemented as a package to achieve maximum portability. For structuring a single application, it's good practice to think of different features as components. This helps maintain a clean separation of concerns and is one of the cornerstone of scalability. A large codebase greatly benefits from being split across packages.

What are the relevant modules for uploading files?

tomi:upload-server - allows user to upload files to the local system and when use together with tomi:upload-jquery, it also enable full UI that also works well on mobile devices. CollectionFS - comes with various storage adaptors that allows you to store files in the local filesystem (cfs:filesystem), in a MongoDB using the GridFS filesystem (cfs:gridfs), or in a S3 bucket (cfs:s3).

When upload files to a cloud provider, you might not want to first upload to your server and then forward to the actual storage. The client can also upload directly to Google Cloud, Rackspace, or others. The 'edgee:slingshot' package implements the required functionality.

How can we upload file?

By taking advantage of the HTML5 native capabilities, you won't need Meteor-specific code in the client. Selecting a file will trigger the upload and hand the file's content to the server-side method.

<template name="upload">
  <h2>Upload a file</h2>
  <input type="file" id="file-upload"/>
</template>
<template name="file">
  {{#with file}}
    <h2>{{name}}</h2>
    <img src="{{base64}}" />
  {{/with}}
</template>

if (Meteor.isClient) {
  Template.upload.events({
    'change #file-upload': function (event, template) {
      var file = event.target.files[0];
      var name = event.target.files[0].name;
      var reader = new FileReader();
      reader.onload = function (file) {
        var result = reader.result;
        Meteor.call('saveFile', name, result);
      }
      reader.readAsDataURL(file);
    }
  });
}

Although the FileReader API allows multiple files to be uploaded at the same time, this code supports only a single file at a time. Notice that we are uploading the file via DDP. Otherwise, we may need to setup server-side routes. In the above code, we first assign the onload callback function, and then we invoke reader.readAsDataURL(file), which read the file's data and automatically encode it into Base64 and store it inside reader.result. When it finish reading the file, the onload callback is invoked. If you want, you can perform additional validations before calling the server method, such as validating the file in question is indeed an image:

if (! file.type.match('image.*')) {
  alert('Only image files are allowed!');
  return;
}
if (Meteor.isServer) {
  Meteor.methods({
    'saveFile': function(name,buffer) {
      FilesCollection.insert({
        name: name,
        base64: buffer
      })
    }
  });
}

The above code store the content of the uploaded file inside the database. This is usually not recommended. You should look at other Meteor packages for storing uploaded file to a cloud.

What is the purpose of the --packages-only option to the 'meteor update' command?

Get the latest of community packages, but not the Meteor's release. To get the latest of everything, remove this option from the 'meteor update' command.

When should we mark a package as debugOnly?

Some packages add functionality that is only useful in a development environment. In case they expose easy access to internal data or execute tests, they may even be dangerous to deploy to production. For this purpose packages can set a debugOnly flag that tells Meteor to exclude those packages from the build process when running with the --production flag.

What is the order that Meteor uses to load business logic file?

Meteor's load order is based on both naming convention and folder hierarchy. This load order is applicable only to the business logic of an application. The load order for packages is based on package dependency defined in the package's definition. As a rule of thumb, Meteor loads files in subdirectories before files in parent directories. Files in the root directory are loaded last. Within the same hierarchy level or directory, files are loaded in alphabetical order by filename. There are some exception to this rule:

  1. All files in folders named lib/ are loaded before all other folder contents. If multiple lib order exists, they're ordered by level (deepest first) as well as alphabetically. Therefore, client/lib/file1.js get loaded before client/scripts/view/file2.js even though the general rule suggests that file2.js should be loaded first due to the position in the hierarchy
  2. The client/compatibility/ directory is reserved for libraries that rely on variables declared with 'var' at the top level being exported as globals. Files in this directory are executed without being wrapped in a new variable scope. These files are executed before other client-side JavaScript files but after the contents from lib/
  3. All files that start with main.* are loaded after everything else: client/lib/validations.js comes before client/lib/main.helper.js
  4. Any content inside private/, test/, and public/ directories are not automatically loaded and won't be processed by the build process.

All files that start with main.* prefix are moved to the very end of the loading cycle. So even if main.helper.js is stored in lib/ it will only be loaded after all other files.

How does Meteor handle LESS or Stylus files with regard to the loading order?

To support using LESS or Stylus:

meteor add less
meteor add stylus

As a result of adding these packages, files with a .less or .sty extension are properly identified and processed by Meteor. Both preprocessors behave exactly the same in regard to the build process. Meteor concatenate all style files into one, following the standard load order. To gain more control over the load order, you can import individual files from a style file. If a file has the extension *.import.less or *.import.sty, then Meteor won't process it during the build unless these files are directly referenced from a style file.

What is a build stage?

This is basically a hook into the build process to process a particular type of file.

How can we add a custom build stage?

It is possible to extend Meteor's build stages. Changes to a file may trigger an action associate with the watcher configured for the specific file extension. Essentially adding a custom build stage requires using a package. In the package.js file, Package.registerBuildPlugin() is used to identify that a package extends the build process. The followings are required:

  1. name: is the indentifier for this build stage. A package may contain multiple build plugins as long as they have unique names
  2. use: reference Meteor Isopacks that this build stage may depend on as a string or array of strings
  3. source: contains an array of strings that defines which files are part of the plugin
  4. npmDependencies: is an object that holds npm package names and version that the plug-in may depend on.

In case you need to write your own build plugin, for example, supporting TypeScript to plain JavaScript, you need to replace the coffee-script-npm dependency with the ts-compiler module. Additionally, you need to adjust the name and source file accordingly:

Package.registerBuildPlugin({
  name: "compileCoffeeScript",
  use: [],
  source: [
    'plugin/compile-coffeescript.js'
  ],
  npmDependencies: {
    'coffee-script': '1.7.1',
    'source-map': '0.1.32'
  }
});

In the source files of a build plugin, you can use Plugin.registerSourceHandler() to define what actions to execute if files with a particular extension are changed. If the plugin is supposed to monitor files with a .ts extension, then it must be specified as a source handler. Using the compileStep, it is possible to either read or write to the currently processed files:

var typescript = Npm.require('ts-compile');

var handler = function(compileStep) {
  var fileContents = compileStep.read().toString('utf8');
  // transpiling logic, result stored inside jsCode
  compileStep.addJavaScript({
    path: outputPath,
    sourcePath: compileStep.inputPath,
    data: jsCode
  });
};

Plugin.registerSourceHandler('ts', handler); // The file extension is used without the first dot.

What is the result of the 'meteor build' command?

Meteor can create bundles of an application using the 'meteor build' command. The output is fully contained Node.js application in the form of a tarball. If needed, the build command can be changed to create a directory with the same contents as the tarball.

Why should always specify the location for the build file outside of the application folder?

When creating a build, it is better to put the build outside of the application folder because you could accidentally add it to the source code repository unless you explicitly add a rule to ignore this file. Second, if you decide to create a directory instead of a file or build another platform, the resulting files will be interpreted as additional source files when you use the 'meteor run' command and produce error messages. To specify the location for the archieved bundle:

meteor build /pathToArchivedBundle

The .tar.gz file contains the compiled Meteor application, which you can put on a server, extract and run. You'll notice that the entire directory structure has changed significantly from the original project's organization. Instead of the client, server, and public folders, you'll now see two main folders: programs and server. All relevant code is located in the programs folder, organized by platforms. In the server folder, all modules, packages and assets are stored. The contents from the assets and private folders are treated differently because they are moved into an assets directory inside the bundle. All other contents are moved to the app directory. The 'tests' folder is an exception because it isn't put into production bundles. All resources that are sent to the browser are stored in the web.browser folder.

Running 'meteor build' command implies using the --production option, so there are three important files: one each for HTML, CSS, and JavaScript. The static resources from the public directory are copied for the client platform and can be found in the app directory. You'll notice several other files are available that weren't there before such as main.js. These files are generated automatically and include the main components needed to run the project as a regular Node.js application.

What are the limitation with the 'meteor build' command?

Although the 'meteor build' command is simple to use, it does have some limitations in regard to portability. As long as you do not rely on platform-specific binary npm modules, you should not experience any problems moving your application from Mac OS X development system to a Ubuntu Linux server. In some advance cases that require truly portable Node.js applicatin, use 'demeteorizer'.

When running the 'meteor build' command, do we need to specify the platform for it to build?

No. If we've added those mobile platforms, the Meteor build process automatically be configured to include the required steps to produce mobile apps for either platform.

How can we deal with the 'using variables as keys' problem?

Building dynamic selectors is extremely common when creating a rich user interface. Imagine a user being able to search a collection of animals by a key (species, size, region, etc.) and a value from a text input. Your code could look something like:

var key = 'species';
var value = 'elephant';

var selector = {key: value};
Animals.find(selector);

But there is a subtle JavaScript gotcha that will prevent this find from returning the right results: Using a variable identifier as a key in an object literal will substitute the identifier and not the value.

selector is actually evaluated as {key: 'elephant'} and not {species: 'elephant'} as intended. In es5, the only way to fix this is to initialize selector as an empty object and then use bracket notation to set the key:

var key = 'species';
var value = 'elephant';

var selector = {};
selector[key] = value;
Animals.find(selector);

In es6, we can use computed property keys:

const key = 'species';
const value = 'elephant';

const selector = {[key]: value};
Animals.find(selector);

How can we deal with the 'subscriptions do not block' issue?

Many aspects of the framework seem like magic. So much so that it may cause you to forget how web browsers work. Take this simple example:

Meteor.subscribe('posts');
var post = Posts.findOne();

The idea that post will be undefined is the root cause of roughly one in twenty meteor questions on stackoverflow. subscribe works like a garden hose - you turn it on and, after a while, things come out the other end. Activating the subscription does not block execution of the browser, therefore an immediate find on the collection won't return any data.

subscribe does, however, have an optional callback which you can use like so:

Meteor.subscribe('posts', function() {
  console.log(Posts.find().count());
});

Alternatively, you can call ready on the subscription handle:

var handle = Meteor.subscribe('posts');

Tracker.autorun(function() {
  if (handle.ready())
    console.log(Posts.find().count());
});

In more complex apps, your subscription activation code and your data consumption code are often very separate, which reduces the value of the above techniques. Fortunately there are two common ways of tackling the problem:

  1. If you use iron router, you can wait on subscriptions, prior to rendering the dependent templates.
  2. You can use guards to check if the data exists within your template code.

I'd recommend using a combination of both approaches in your applications depending on your UI requirements. Waiting on a subscription will force a delay before rendering the page, whereas guards will progressively render data as it's received on the client.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License