Worst time to start a new app?

Donā€™t forget the testing area. The Velocity does not seem the way to go anymore.

2 Likes

Itā€™s definitely an awkward time to jump into a new app, no doubt.

However, if you look at the landscape in the next 6 months you can optimize for that. Hereā€™s my recommendations:

Use React

React isnā€™t the ā€˜bestā€™ framework but it has a huge mindshare and community to pool from. The next Blaze 2 will have a thin facade over React to put templates in separate files.

If you prefer Blaze 2, then youā€™re still going to have to learn React if you want to debug it. You might as well just dive in now. Remember, you can always move the JSX out later if you still dislike it. (Iā€™ve found that once you use React youā€™ll break it down into so many small pieces that having 2 files for every piece is a major pain).

React makes you think different. Way different. It follows the functional paradigm and helps you organize your code for the better (IMHO).

Use testing tools for the future

Velocity is on itā€™s way out. At best it will stay and be made less buggy. However, I doubt that.

  • End to End testing can be handles with ChimpJS, Capybara, or your favorite tool as they donā€™t need to know about Meteor itself (though Chimp has some killer Meteor integration for setup/teardown!)

  • Unit tests can be setup to use Karma outside of Meteor with a simple config that mimics Meteors load order. Iā€™ve used this with great success and it allows me to get millisecond test results with any JS testing tool (Jasmine, Mocha, Tape, etcā€¦). Simple Jasmine stubs allow you to test a lot of client and server code without needing to mock out all of Meteor.

  • Integration tests are the most tricky as they need to know about Meteor. Gagarin is the best option out now and works well. Little magic and little to break. Youā€™ll likely have only a few of these tests if you opt to cover most of the code with Unit and End-to-End tests.

Use a module pattern

ES6 modules are coming. You can use Webpack if you need the fast reloads or the power of configuration. However, many do not. You can mimick the modules so that when 1.3 comes out, a transition will only take a few mins or hours tops.

Think about your code as modules. Everything should be in a module namespace and the folder name should mimic this for ease of use. Doing it this way also mitigates load race conditions.

For example:

// client/helpers/form.js

const FormHelper = {
  validateNumber(str) {
    // ...
    return true;
  },

  validateEmail(str) {
    // ...
    return true;
  }
};
// expose globally pre-1.3
this.FormHelper = FormHelper;


// later in another file


const {validateNumber} = FormHelper;

validateNumber('1 555-222-0000');
// or
FormHelper.validateNumber('1 555-222-0000');

Soon you can find/replace the top of your files with 2 lines like this:

// client/helpers/calculator.js

const FormHelper = {
  validateNumber(str) {
    // ...
    return true;
  },

  validateEmail(str) {
    // ...
    return true;
  }
};
// export in a module
export default FormHelper;


// later in another file


import {validateNumber} from 'client/helpers/form';
import FormHelper from 'client/helpers/form';

validateNumber('1 555-222-0000');
// or
FormHelper.validateNumber('1 555-222-0000');
17 Likes

Can you share more on this and/or point to a sample repo? Sounds really attractive for plain jane unit testing.

1 Like

Where was that official unofficial announcement that React will replace Blaze going forward? People keep saying that but Iā€™ve assumed it was mostly speculation.

ROTFLMHAO!!! :laughing:

3 Likes

Sure. Iā€™m hoping to do a screencast on the whole workflow testing my http://react-ive.meteor.com/ project. However, as soon as I record it itā€™s going to be outdated in a few months with 1.3 :laughing: Perhaps iā€™ll use it as a second screencast for migrating to 1.3.

Anyhow, the basic gist is that you want to load all of your files with the same rough pattern that Meteor uses (in the files array). Itā€™s easiest to start with one single folder/file and make sure that works then work outwards until you get the hang of Karma and how itā€™s importing (so everything isnā€™t blowing up at once basically).

Additionally when you discover this process of things ā€˜blowing upā€™, youā€™ll slowly build up stubs that have empty functions (like Meteor.user). This is what the tests/karma/mocks.js file is doing. Adding just enough so that it doesnā€™t blow up. Then with jasmine I might do something like this:

spyOn(Meteor, 'user').and.returnValue({profile: {name: 'Adam'}});

so that in my unit tests the user is pre set and only has enough to make the unit tests pass.

Hereā€™s an older gist focused on React that has all the files in my tests/karma directory. Note, the package.json file for packages.

https://gist.github.com/AdamBrodzinski/aeb5b669a74259da8af8

Also hereā€™s the karma config for this. Note, you may not want to import all of the meteor files with karma like this because this is meant for unit testingā€¦ you may pull in things that you donā€™t want executed and at best those files would be integration tests. I tend to just manually add them in the config one at a time (or a folder) and all React components since theyā€™re easy to unit test.

// tests/karma/karma-config.js

module.exports = function(config) {
  config.set({
    basePath: '../../',
    frameworks: ['jasmine', 'jquery-2.1.0'],
    plugins: [
      'karma-babel-preprocessor',
      'karma-jquery',
      'karma-jasmine',
      'karma-mocha-reporter',
    ],
    autoWatch: true,
    reporters: ['mocha'],

    files: [
      'tests/karma/mocks.js',
      'tests/karma/node_modules/react/dist/react-with-addons.js',
      'tests/karma/spec_helper.js',

       // import lib code first
      'client/lib/*.js',
      'both/lib/*.js',

       // import a file before all else if manually if it fails
      'client/utils.js',

      // you could tech. load each folder manually here if you *have* to
      'client/alpha',
      'client/bravo',

      // otherwise load all js code #yolo
      'client/*.js',

      // import all tests in client dir, this allows you to have them in
      // client/components/widget/tests/widet_spec.js
      'client/**/*_spec.js',
    ],

    preprocessors: {
      '**/*.js': ['babel'],
      '**/*.jsx': ['babel'],
      '**/*_spec.js': ['babel']
    },

    babelPreprocessor: {
      options: {
        sourceMap: 'inline',

       // mimics features Meteor supports, poss. out of date now?
        whitelist: [
          "react",
          "flow",
          'es3.propertyLiterals',
          'es3.memberExpressionLiterals',
          'es6.arrowFunctions',
          'es6.templateLiterals',
          'es6.classes',
          'es6.blockScoping',
          "es6.properties.shorthand",
          "es6.properties.computed",
          "es6.parameters.rest",
          "es6.parameters.default",
          "es6.spread",
          "es6.destructuring",
          "es6.constants",
          "es7.objectRestSpread",
          'es7.trailingFunctionCommas',
        ]
      },
      // can't remember what this is for? perhaps unneeded lol
      filename: function (file) {
        return file.originalPath.replace(/\.js$/, '.es5.js');
      },
      sourceFileName: function (file) {
        return file.originalPath;
      }
    }
  });
};
4 Likes

@SkinnyGeek1010 This is awesome - thanks very much for sharing this!

1 Like

Itā€™s true, I got a bit ahead of myself there. There has been so much activity and good discussion that just staying on top of the Blaze thread could be a full time job, and when it comes to posting I am a fairly slow and deliberate writer. Iā€™m going to keep working on posting more, but I have to strike the right balance between that, in-person conversations with customers, and the day-to-day work of running MDG.

18 Likes

Iā€™ve tried to use this pattern in my app with something like this:

// in both/models/items.js

const Items = new Mongo.Collection("items");
// other things and methods
this.Items = Items;

then in a jsx:

// in client/components/Items/Items.jsx

const Items = this.Items;
const Component = React.createClass({
  // ...
});
this.Component = Component;

But when I try to access Items (e.g. Items.findOne()), it says Items is undefined. If I move models to /lib it works, but I canā€™t ā€œimportā€ react components because of the same problem (it says theyā€™re undefined). Is this a load order problem, or Iā€™m doing something wrong?

Iā€™m just learning meteor/js and I can live with the long rebuild time (of course a faster one will be good, but webpack:webpack seems a little complicated). My main concern is to use a pattern which will enable an easier migration to 1.3ā€™s module pattern.

Thanks!

@csiszi

Ah, yea I should have explained that better. If you have the ā€œimportā€ at the top of the file, then it has to be defined at the point that file is executed. You can wrap the entire file in a Meteor.startup function and that will solve it. Also you can ā€œimportā€ it inside of the component right before you use it (though this can be time consuming to migrate).

For example:

// in both/models/items.js

const Items = new Mongo.Collection("items");
...
this.Items = Items;

and in your component file:

// in client/components/Items/Items.jsx

const Items = this.Items;
const Component = React.createClass({
  getInitialState() {
    return {
      foo: Items.findOne();
    }
  }
});
this.Component = Component;

This way itā€™s not being called until after itā€™s defined. You could also do this:

// in client/components/Items/Items.jsx
Meteor.startup(function() {

const Items = Items;

const Component = React.createClass({
  getInitialState() {
    return {
      foo: Items.findOne();
    }
  }
});
Component = Component;

}); // end Meteor.startup

However, I would go a step further and organize your collections into their own modules. Models consume them but they are different things. You could make one collections file like this:
// in both/collections/index.js

const Items = new Mongo.Collection("items");
const Posts = new Mongo.Collection("posts");


this.Collections = {
  Items: Items,
  Posts: Posts,
};

Then in your files you can do this:

// in client/components/Items/Items.jsx
Meteor.startup(function() {

const {Items} = Collections;
// in 1.3 would be  import {items} from 'boths/collections';

const Component = React.createClass({
  getInitialState() {
    return {
      foo: Items.findOne();
    }
  }
});
Component = Component;

}); // end Meteor.startup

Or since this example is a module (not just a single export) we could do this without the wrapper like this:

// in client/components/Items/Items.jsx

const Component = React.createClass({
  getInitialState() {
    const {Items} = Collections; // now it's defined at call time
    return {
      foo: Items.findOne();
    }
  }
});
Component = Component;

Hope this helps! I need to write this up in a blog post soon :smile:

1 Like

Will you also consider a screen cast on migrating from Blaze 1 to React from the bottom up (not the top down)?

Iā€™m talking taking a list within a Blaze 1 template, and converting it over to React ā€“ all the while keeping any communication between the new React list and the Blaze 1 template.

2 Likes

Will you also consider a screen cast on migrating from Blaze 1 to React from the bottom up (not the top down)?

I prob. wonā€™t have to do this but this video explains how to do it really well!

https://www.youtube.com/watch?v=BF58ZJ1ZQxY

1 Like

What does the above mean?

Anyway. Iā€™ve seen this video, which is how I got the idea of starting from the bottom up. But what I and many others I think would like to see is this applied to Blaze 1.

Replacing a portion of a Blaze 1 Template with a React component (and this React component should be able to communicate with the Blaze 1 Template).

Something like this is badly needed for us in the Meteor community that have existing Blaze 1 applications that need migrating to React.

I first heard about Meteor about four weeks ago, on the coding blocks podcast (great podcast). They were singing its praises so I checked it out and was blown away once Iā€™d done the tutorial. This, I thought, is the perfect platform for getting all those ideas out of my head and into a prototype - so much quicker than the .net stack Iā€™m used to.

Then I was listening to Josh and Ben on the Crater podcast and realised that Blaze was on the way out, and also that the testing game was maybe a little weak and it definitely left me sad. I think the question marks over Blaze at the moment are a real concern to those of us coming to the framework now, which is a shame as the buzz is really growing over Meteor (based on my sample of one people obviouslyā€¦!).

Iā€™m watching this space with great interest.

5 Likes

You may have seen this by now, but figured Iā€™d post it just in case.

Basically, MDG is going to create some type of Blaze abstraction on top of React so that you get the power of React and itā€™s community but with a more Blaze like syntax. Iā€™m really interested to see what they come up with! Should be pretty cool.

Thanks for your perspective @tomRedox. Iā€™m glad I came to Meteor over a year ago, or else I would have second thoughts too. Everyone was on the same technical page and things were much more simple. It was nice to be able to focus on my business ideas and not the tech so much ā€“ it was great while it lasted. Ah, the good old daysā€¦ :slight_smile:

I agree with others, itā€™s a questionable time to come to Meteor with all the transition going on. In fact, itā€™s not just Blaze and Velocity MDG is kicking to the curb, theyā€™re going to be adding Facebookā€™s GraphQL. Also look for Flux and Redux to complement or replace tech within the Meteor stack too. Also, Webpack could possibly be replacing portions of the Meteor stack. Say goodbye to Atmosphere in favor of npm. There might be more but itā€™s hard to keep up.

MDG seems to be slowly replacing a lot of their tech stack in favor of Facebookā€™s stack at the moment.

I have no choice but to learn the Facebook stack to keep current as Iā€™m tied to Meteor due to a production application in use by many clients of mine.

3 Likes

Yea there is a lot going on in the JavaScript world. Itā€™s still really early and everyone is figuring out how to write thick clients on the web. JS tech was optimized for ā€œJS Sprinkesā€ 5 years ago.

Web apps are starting to become more like iOS/Android apps but our tooling and libraries for the past 6 years (or more) has been really poor at doing this (compared to .net, java, ios, android).

Backbone was the first paradigm shift for thick clients. React is another paradigm shift, making our UI declarative and using functional programming methodologies (the virtual dom is cool but is my least fav feature).

Also the language itself is starting to mature. We ā€œFINALLYā€ have modules in the language :smiley: Well almost, at least with Babel. JavaScript itself also does OO very poorly compared to Java/C#/Ruby/etcā€¦ However, it does do the functional paradigm really well and is getting more ā€˜functionalā€™ features in ES7/8

Anyway my point is, JavaScript is inherently going to be churning through libs and frameworks until we can figure out how to build web apps that donā€™t crumble. Though I hear you, I too could do with some JS stability :smile:

3 Likes

Any tips on using module pattern with different files sharing the same namespace?

If youā€™re using the ā€˜patternā€™ and not real modules you can do this, itā€™s basically checked to see if the module is defined and if it is, itā€™ll use it, otherwise Utils will fallback to an empty object :

this.Utils = this.Utils || {};
Utils.parseEmail = function() {
};

// somewhere else
this.Utils = this.Utils || {};
Utils.parsePhone = function() {
};

Generally this is code smell because you can prob. break up the module more. For instance, why not use sub modules like this (or even use two non-nested modules):

// somewhere
Utils.Email = {
  parseEmail() {}
};

// somewhere else
Utils.Phone = {
  parseNumber() {}
};