Worst time to start a new app?

Yesterday I began writing a package, went to use/learn React, and found that the Meteor React tutorial is outdated in at least two ways, too. Quite the bummer.

2 Likes

I think what people want is DDP, Tracker, Accounts and a few parts of meteor core as part, but in the context of a generic node.js application. The build system leaves more to be desired (e.g., requiring files at runtime). The NPM community offers far packages over Atmosphere. I’m losing confidence in using Atmosphere packages (especially the ones that I’ve used that depend on blaze). (Yes, I am aware of meteorhacks:npm, NPM support has come a long way for Meteor). After thorough research, and weighing my options, the meteor-webpack-react starter project seems to provide the best option moving forward… and I feel like I’m re-writing 99% of my app because of it. Oh well, such is life.

Given everything that has been happing, here’s how I’m going to proceed:

  • Use React only. Remove Blaze 100% from my project.
  • Prefer NPM modules over Atmosphere packages.
  • Use Meteor exclusively for it’s reactivity support, DDP, and other core pieces.

I know MDG wants to keep Meteor as simple as possible, but at the same time, that limits what you can do with it. Some might argue simplicity may have been lost when swapping Blaze for React. However, my Blaze app isn’t that complex and I’m hitting unacceptable initial page load time limits. I needed webpack yesterday. And we know that’s not coming in 1.3 (officially-- but lots of community support for it). The JavaScript landscape has been changing rapidly for awhile, and while I’m amazed by MDG’s contributions, keeping us is always going to be a challenge for MDG and for us.

6 Likes

We gave this a lot of thought, and are writing the guide with Blaze for a few reasons:

  1. It’s good to have a record of how a normal Meteor app is built today, because this is the kind of app we will need to pave a transition path for, and not everyone will be able to switch to React immediately.
  2. There are a lot of community packages that are hard to do without, in particular autoform and useraccounts and extensions to those. We’ll need to work with those authors as part of the transition to React, and the Guide is a great way of cataloguing what those packages are that we can’t do without.
  3. There are tons of people using Blaze today, including Galaxy and Developer Subscription customers that we’re officially supporting. We’re going to need a good transition, and we’re betting it will be good enough that building your app in Blaze even today can be a fine choice.

Having said that, like 85% of the guide has nothing to do with Blaze. That’s kind of the point - Meteor is so much more than a UI rendering framework, and most of the difficult content is around the other stuff: app structure, routing, security, data loading, methods, generic UI best practices, etc.

9 Likes

I agree, it’s a pretty iffy time to join Meteor. However, just make peace with the fact that this is a cutting edge framework. If you want a something that’s more stable, and has years of stability behind it, Meteor is not the framework for you. I had to make peace with that and just buckle up for the ride.

I do think the guides should just switch over to React pronto - people will be pissed to learn all that Blaze and then when they want to start something real be met with “Oh by the way, use React, Blaze is dying in the future.”

3 Likes

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.