Viewing a meteor site from mobile very unreliable


#1

I’m not even sure where to start. I have a relatively simple meteor app (http://www.vertexshaderart.com). It’s using iron router for routes. The main route / seems like a pretty normal situation. Show the 8 newest posts. Show the 8 most liked posts sort: {likes: -1}.

When I try to view on my phone it only works about 1 out 5 times, maybe less. The site shows up, the main template is clearly rendered and at least one child template but the templates waiting for data never show up. They have {{#if Template.subscriptionsReady}} wrappers. I’m guessing the subscriptions never complete on mobile for some reason. In fact the entire 10+ minutes I’ve been typing and editing this response I’ve had my phone sitting beside my computer trying to load the page. It’s been sitting there loading for > 10 mins, the data spinner in the iOS status bar spinning constantly.

But when I try to debug it it always works (or at least so far). It works fine in the iPhone Simulator. It works fine if I connect directly to my dev machine over WiFi. Like I said it works fine 1 or of 5 times or so on mobile. I’ve tried connecting to a debugger USB and then remote debug Safari but it always seems to work when I do that.

You might think it’s a bad mobile connection but every other site I view seems to work just fine. Slashdot, Ars, Hackernews, Facebook’s website (not app), Reddit. Etc.

Any idea how I can debug this? Or is this a known issue?

Just for the hell of it here’s my code

Router.route('/', {
  template: 'front',
});
<template name="front">
  <header>

    <div>
        <div class="buttons">
            {{> userinfosignin}}
        </div>
        {{> logo}}
    </div>
  </header>
  <div class="container">
     <div class="gallery">
         {{> artselection sort="newest" limit="8"}}
         {{> artselection sort="popular" limit="8"}}
     </div>
  </div>

<template name="artselection">
   <div class="sortcriteria">
       <div class="title">
           <div>{{sort}}:</div><div class="right"> <a href="/gallery/1/?sort={{sort}}">see all</a></div>
       </div>
       <div class="artgrid">
           {{#if Template.subscriptionsReady}}
             {{#each art}}
               {{> artpiece}}
             {{/each}}
           {{/if}}
       </div>
   </div>
</template>

<template name="artpiece">

<div class="artpiece">
    <a href="/art/{{_id}}">
      <img class="thumbnail" src="{{screenshotLink.url}}" />
    </a>
    <div class="galleryinfo">
        <div class="galleryname">
            <a href="/art/{{_id}}">&ldquo;{{name}}&rdquo;</a>
            <a href="/user/{{username}}">by: {{username}}</a>
        </div>
        <div>
            <a href="/art/{{_id}}">
              <span class="views">{{views}}</span><span class="likes">{{likes}}</span>
            </a>
        </div>
    </div>
</div>
</template>

I can see all of that gets rendered except the part inside the {{if Template.subscriptionsReady}}

Here’s the code for that template

  // in a client section
  Template.artselection.onCreated(function() {
    var instance = this;
    instance.autorun(function() {
      var sort = getSortingType(instance.data.sort);
      instance.subscribe('artSelection', sort, parseInt(instance.data.limit));
    });
  });

  Template.artselection.helpers({
    art: function() {
      var instance = Template.instance();
      var sortField = getSortingType(instance.data.sort);
      var sort = {};
      sort[sortField] = -1;
      var options = {
        sort: sort,
        limit: parseInt(instance.data.limit),
      };
      return Art.find({}, options);
    },
  });

  // in a sever section
  Meteor.publish("artSelection", function(sortField, limit) {
    var find = {
      private: {$ne: true},
    };
    var sort = {};
    sort[sortField] = -1;
    var options = {
      fields: {settings: false},
      sort: sort,
      limit: limit,
    };
    return Art.find(find, options);
  });

  function getSortingType(sort) {
    switch (sort) {
      case "mostviewed":
        return "views";
      case "newest":
        return "modifiedAt";
      case "popular":
      default:
        return "likes";
    }
  }


Note: Art is a collection that’s pretty much the same as Posts in any tutorial. The data is small. Just _id, username, owner, title, createdAt, modifiedAt, likes, views, hasSound. That’s about it and one field settings which is a string which is at most 2-3k but I’m excluding that field in the publish method. In fact, checking the frames in the Chrome debugger when viewing on desktop it looks like only about 12k of data is sent down over the websocket before the front page is completely rendered. In other words, this isn’t an issue of sending lots of data.

I’m on Meteor 1.2.1.


#2

Update

I figured out the issue is actually Chrome’s Data Saver feature. I made the bad assumption that since both are WebKit under the hood that remote debugging on Safari would help me find the issue but Chrome is doing fancy networking behind the scenes of it’s embedded WebKit view. Turning off the data saver feature and it started working.

According to Google you can disable the data saver feature on the server side by adding the header

Cache-Control: no-transform 

So for now I’ll try adding that header to my site. Otherwise I’m pretty sure google wants it to just work so I’ve filed a bug


#3

Thanks for figuring out what was going on here! Could you also open an issue on the Meteor repository, so we can keep track of this and maybe see what we can do about it from our side?

As a workaround, forcing SSL should definitely disable the use of Chrome’s Data Saver feature.


#4

filed…