How to load stripe.js only for the pages where it's used?

I only need the client to have access to stripe.js on one page but if I use the popular mrgalaxy:stripe package then this will include a call to stripe.js in the head of every route. This really isn’t ideal because it slows page load times.

Kadira’s package solved this by asychronously loading things but now, with 1.3.1, this package is no longer working.

What I want to do, to keep things clean, is npm install stripe for the server side functions and then be able to include stripe.js only on those routes that require it. Should be simple, no? Maybe I’m missing something really obvious - lots of people must be using Stripe in their app - but I’m not seeing it and would appreciate some advice.

Have you looked at imports with Meteor 1.3? Should be able to put that in an imports folder and then:

import '/imports/stripe.js'

where it’s needed.

Meteor Guide - ES2015 Modules

It’s an idea, I see what you’re thinking, but then doesn’t that kind of break package management?

Package management is changing beyond 1.3 and going to this import model.

For instance, you can still import meteor packages like:

import { Meteor } from 'meteor/meteor'; import { Roles } from 'meteor/alanning:roles';

and npm modules like:

import moment from 'moment';

Yeah, I guess what I really want to be able to do is import stripe from 'stripe' on the server (we do this now, works fine) and then have import Stripe from 'stripe-client' on the client. That way we get the benefit of using Npm and don’t have random copies of stripe.js laying around. But when I looked I didn’t see any reference to installing stripe.js via Npm (because most people don’t need to do this) and only lots of things telling me to include it in my head which I can do but then, meh, it ends up on every page.

For third party stuff that doesn’t have an npm wrapper, I just throw it in /imports/thirdparty/whatever and that seems to work fine. Those files are ignored until explicitly imported.

We tried loading stripe.js from /imports… but it won’t work. It throws a rather well worded error:

It looks like Stripe.js is not being loaded from https://js.stripe.com. Stripe does not support serving Stripe.js from your own domain.

Which is a shame. So you were right, this is a good way to selectively load js code, but not for Stripe.

Looks like the only option here is to selectively edit the head (or better yet the footer) for each route.

Maybe this package would be helpful? Sorry, I don’t have any experience with the Stripe API. Good luck!

The whole problem with that package is it loads stripe.js for each route and blocks the page each time, it’s a horror if you have a slow connection, I linked to an issue about this above. Thanks for your help anyway though!

shouldn’t it be cached after the first load?

Also, just generally, I want to move over to using Npm as much as possible but this seems harder than you’d think for Stripe, which is surprising given how popular it is.

You’d think, but this doesn’t seem to be the case: https://github.com/tyler-johnson/stripe-meteor/issues/41

I suspect, given they don’t like you hosting it locally, Stripe also don’t want this file cached or force very short expiry times, and this is the reason why it keeps being loaded.

That won’t work on the client because you need to include it from their website

Solving my own issue, in the end we used npm to load the api on the server and $.getScript() on the client.

Server:

meteor npm install stripe --save

Then use

var Stripe = require('stripe')(Meteor.settings.private.STRIPE_LIVE_SECRET_KEY);

to load the library in the file where you want to use their api

Client:

Template.my_billing_template.onRendered(function() {
  $.getScript('https://js.stripe.com/v2/', function(err) {
    // Handle errors
    // Set a key to allow the client to talk to Stripe
    Stripe.setPublishableKey(Meteor.settings.public.STRIPE_LIVE_PUBLIC_KEY);
    this.state.set('loading', false);
  });
});

Like this the browser only tries to load stripe.js when it needs it and you aren’t forced into also loading checkout.js.

2 Likes

The reason I think this issue matters is because the response headers when calling Stripe to get this file include: Cache-Control:public, max-age=300. So yeah, it’s cached, but not much.

Essentially, for everyone using the most popular Stripe package on Atmosphere, each time a user returns to their site (after more than 5 minutes) they first have to wait for Stripe to serve both stripe.js and checkout.js before being given any content. A lot of our users are in low bandwidth areas so for them this was horrific but even from London I would occasionally see a white page for a few seconds.