MeteorJS is a new open source framework build on Node.js. It's developed for concurrent browsing experience for web apps that are being simultaneously used by number of people. Building concurrent web apps like live chats, Google docs etc. can be achieved in a friction of time.
By default, Meteor uses build-in MongoDB for data storing which is quite easy to adapt. In Meteor's official examples, Handlebars is used for templating system but also alternative approaches such as AngularJS are supported. Meteor uses its own package manager, Smart Packages, providing support for favourite JS add-on's like jQuery.
If you feel like getting more familiar with Meteor, I suggest reading an excellent blog post by Andrew Scala about Meteor Fundamentals and Best Practices.
Running shell commands with Meteor
I got a nice idea for an app to learn the basics of Meteor. The web app simulates the usage of terminal by having a command line as input field and a div block for shell output. The app is considered only for testing purposes and to demonstrate the functionality of Meteor in practice.
If you're new to Meteor, download the SDK and create a new project. Replace the HTML and JS files with ones disclosed below and run the app.
<head> <title>MeteorJS terminal</title> </head> <body> {{> terminal}} </body> <template name="terminal"> <pre>{{ window }}</pre> <input id="command" type="text" value="{{ last_cmd }}" /> <input type="button" value="Run" /> </template>app.html
// A collection for stdouts var Replies = new Meteor.Collection('replies'); if(Meteor.is_client) { // Start listening changes in Replies Meteor.autosubscribe(function() { Meteor.subscribe('replies'); }); // Set an observer to be triggered when Replies.insert() is invoked Replies.find().observe({ 'added': function(item) { // Set the terminal reply to Session Session.set('stdout', item.message); } }); // Show the last command in input field Template.terminal.last_cmd = function() { return Session.get('last_cmd'); }; // Show the last shell reply in browser Template.terminal.window = function() { return Session.get('stdout'); }; // Add an event listener for Run-button Template.terminal.events = { 'click [type="button"]': function() { var cmd = $('#command').val(); Session.set('last_cmd', cmd); // Call the command method in server side Meteor.call('command', cmd); } }; } if(Meteor.is_server) { var exec; // Initialize the exec function Meteor.startup(function() { exec = __meteor_bootstrap__.require('child_process').exec; }); // Trigger the observer in Replies collection Meteor.publish('replies', function() { return Replies.find(); }); Meteor.methods({ 'command': function(line) { // Run the requested command in shell exec(line, function(error, stdout, stderr) { // Collection commands must be executed within a Fiber Fiber(function() { Replies.remove({}); Replies.insert({message: stdout ? stdout : stderr}); }).run(); }); } }); }app.js