Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use in single component instead of globally #12

Closed
hansy opened this issue Apr 5, 2018 · 30 comments
Closed

Use in single component instead of globally #12

hansy opened this issue Apr 5, 2018 · 30 comments

Comments

@hansy
Copy link

hansy commented Apr 5, 2018

This might seem like a dumb question, but is there a way to import and use this in one component instead of registering the plugin globally?

@jofftiquez
Copy link
Member

jofftiquez commented Apr 6, 2018

Hello @hansy have you tried overriding the global options by setting it up on the component level? Like:

this.$checkout.open({
  // insert here
  key: 'your-publishable-key',
  image: 'https://cdn.meme.am/images/100x100/15882140.jpg',
  locale: 'auto',
  currency: 'PHP',
  billingAddress: true,
  panelLabel: 'Subscribe {{amount}}'
  // insert here
  name: 'Shut up and take my money!',
  currency: 'USD',
  amount: 99999,
  token: (token) => {
  } 
});```

@hansy
Copy link
Author

hansy commented Apr 11, 2018

Ah perhaps I didn't articulate my question aptly. I was wondering if there was a way to initiate (import) the plugin within a component instead of registering the plugin to Vue globally.

So ideally something like:

// component.vue

<template>
  <p>This is a component</p>
</template>

<script>
import VueStripeCheckout from 'vue-stripe-checkout';
export default {
  created() {
    let checkout = VueStripeCheckout.$checkout.open({
      // options go here
    });
  },
};
</script>

I'm still new to Vue, so perhaps the above scenario is the same as registering via Vue.use(VueStripeCheckout, options) on Vue initialization. I only need a handful of my components to have access to the plugin. Does that make sense?

@jofftiquez
Copy link
Member

@hansy hello! Good day. Sorry I did not understand you at first. I can do such implementation, however I don't see the point of doing it like that. May I know your reason why you want it to import that way? 😃

@hansy
Copy link
Author

hansy commented Apr 11, 2018

I'd like to isolate certain functionality to a few select components. In this case, I'd only like a few (or even just one) of my components to have Stripe checkout functionality. I noticed that the external Stripe JS libraries also load in my non-checkout components, which doesn't seem necessary. Ideally, I only want the Stripe stuff to load with the relevant components.

@jofftiquez
Copy link
Member

@hansy Alright I get it now. I can consider this, however, maybe I can work on these this weekend. Let me see what I can do. :)

@williamchong
Copy link

@jofftiquez Having it loaded by component might improve site first-load/js startup time in our case, since I can control the timing and lazy load it when needed

@jofftiquez
Copy link
Member

@williamchong007 that's a very good input. I will expedite this issue as soon as I'm done with my work this week. I am really sorry guys it is taking this long to solve this. I appreciate all of your inputs. Thanks! <3

@jofftiquez
Copy link
Member

jofftiquez commented May 15, 2018

@hansy I was tinkering some stuff while looking for solution for this. I figured that the main issue here is to NOT load the stripe checkout script immediately or where it is not needed, like what @williamchong007 said, right? However, once you've already loaded the script it will stay in the memory even if you remove the script tag.

I was working on a solution where it will only load the script once you invoked the this.$checkout.open() function. Then, remove the script while also removing the StipedCheckout instance from the window (delete window.StripeCheckout), once the stripe checkout dialog has been closed. By this, it will completely remove the stripe in the document, but not in the memory.

So the stripe checkout script won't be loaded immediately unless otherwise needed.

Any thoughts?

@jofftiquez
Copy link
Member

jofftiquez commented May 15, 2018

Wrong commit reference. Please see this.

@hansy
Copy link
Author

hansy commented May 17, 2018

Admittedly I'm not 100% sure what the best course of action is, but this might work. I'll check it out and report back if I run into any additional issues. Thanks so much for your work!

@jofftiquez
Copy link
Member

@hansy I think so too. Yes, please, any feedback will be very helpful. Thank you so much.

@williamchong
Copy link

williamchong commented May 18, 2018

@jofftiquez probably should let user to choose whether they want to

  1. lazy load the script or not
  2. delete the script after close or not

and delete the script probably is a bad idea anyway, since users often trigger the pop up many times, and operation on DOM probably cost more than just leaving the script alone

@williamchong
Copy link

@jofftiquez also when this issue is first opened, everyone is probaly expecting a syntax like

import stripe from 'vue-stripe-checkout'
....
components: stripe
...
this.$refs.stripe.open();

than using the global Vue object?

@jofftiquez
Copy link
Member

@jofftiquez also when this issue is first opened, everyone is probaly expecting a syntax like

import stripe from 'vue-stripe-checkout'
....
components: stripe
...
this.$refs.stripe.open();
than using the global Vue object?

You're right! However, after few replies the problem regarding the loading of the script came up, so I thought we could just solve the script problem rather than making it a NOT GLOBAL component.

How is this this.$refs.stripe.open(); better that loading it global if the main problem is the loading of the script in the first place?

What do you think? I don't know what's right anymore hahaha. :p

@williamchong
Copy link

williamchong commented May 18, 2018

@jofftiquez if it is in a component, bundler like webpack can pack this library only in the page that needs it, such that visitors that does not go into that particular page wont run this library at all

@jofftiquez
Copy link
Member

@williamchong007 I will look at that. Thanks!

@jofftiquez
Copy link
Member

Re-opening because the solution for this causes the dialog to appear extra late. I will find a better solution for this.

@jofftiquez jofftiquez reopened this Jul 17, 2018
@findmind
Copy link

I am be very interested in this, too. It's quite ugly having so many requests just on the landing page, far away from the actual payment process. Are there any news on this front? Or is there some general way to isolate such behaviour to single components?

I'd appreciate any help, thanks so much!

@drosendo
Copy link

I confirm, Ideally only load scripts when needed (component based). I dont need it loading everywhere i go to... :)
Any ETA?

Great work btw!

@drosendo
Copy link

FYI,

Not being possible, at least I limited the .js files being loaded to just 1 on the pages I dont need it...

used:

var parts = location.pathname.split('/');
if (parts[parts.length - 1] == 'checkout') { //Only on page wth this name last will load
  Vue.use(VueStripeCheckout, stripe_options);
}

Cheers,

@jofftiquez
Copy link
Member

Hello all! I'm glad you're liking this plugin. I'm sorry I've been really busy lately, I will work on this very soon. I'll let you all know. Thank you.

@jofftiquez
Copy link
Member

Hi all! I'm glad to tell you that I have converted this plugin from mixin to a single component. Which means the problem of unnecessary loading of Stripe Js has been solved.

You can also now do the following:

Create multiple checkout components with their own configurations.

I hove that this finally solves the problem, if not, kindly reopen and we'll see what we can improve further.

@manuelmejiaio
Copy link

I don't see any solution here and the issue is closed :(

@jofftiquez
Copy link
Member

jofftiquez commented Feb 8, 2019

@mejiamanuel57 kindly refer to:

Hi all! I'm glad to tell you that I have converted this plugin from mixin to a single component. Which means the problem of unnecessary loading of Stripe Js has been solved.

You can also now do the following:

Create multiple checkout components with their own configurations.

I hove that this finally solves the problem, if not, kindly reopen and we'll see what we can improve further.

@manuelmejiaio
Copy link

Hi @jofftiquez , please give us an example of how to use it as a component (Local Registration), I'm trying to do this:

<script>
import stripe from 'vue-stripe-checkout'
export default {
  components: {
    stripe 
  }
.......
}
</script>

But it's not working, even the README.md is making reference to a Global Registration.

@jofftiquez
Copy link
Member

@mejiamanuel57 would mind checking this?

@manuelmejiaio
Copy link

manuelmejiaio commented Feb 8, 2019

Sorry @jofftiquez, I don't see clearly how to register vue-stripe-checkout as a single component (Local Registration) on that issue.

The intention is to render vue-stripe-checkout ONLY in the component where I'm executing the payments because a global registration will harm the loading performance of my Single Page Application.

@jofftiquez
Copy link
Member

@mejiamanuel57 Right. I will reopen this and will do further investigations. However, I can't promise that I will be able to do it very soon. I have to apologize :(. I am very busy right now with I hope you understand.

@jofftiquez jofftiquez reopened this Feb 8, 2019
@Skasi
Copy link

Skasi commented Apr 3, 2019

Turning this plugin into a component is quite simple. You just need to export the component part and make sure nothing else is out of place (eg. replace !key with true). Note that this is just a quick working example - code is not cleaned up completely.

(Note: Original code copied from https://github.com/jofftiquez/vue-stripe-checkout/blob/master/src/index.js)

export default {
  name: 'stripe-checkout',
  render: h => h('div', { style: { display: 'none' } }),
  props: {
    publishableKey: {
      type: String,
      required: true,
    },
    image: {
      type: String,
      default: null,
    },
    name: {
      type: String,
      default: null,
    },
    description: {
      type: String,
      default: null,
    },
    amount: {
      type: Number,
      default: 0,
    },
    locale: {
      type: String,
      default: 'en',
    },
    zipCode: {
      type: Boolean,
      default: false,
    },
    billingAddress: {
      type: Boolean,
      default: false,
    },
    currency: {
      type: String,
      default: 'USD',
    },
    panelLabel: {
      type: String,
      default: 'Pay with Card',
    },
    shippingAddress: {
      type: Boolean,
      default: false,
    },
    email: {
      type: String,
      default: null,
    },
    allowRememberMe: {
      type: Boolean,
      default: true,
    },
    autoOpenModal: {
      type: Boolean,
      default: false,
    },
  },
  mounted() {
    if (document.querySelector('script#_stripe-checkout-script')) {
      return this.setCheckout()
    }
    const script = document.createElement('script')
    script.id = '_stripe-checkout-script'
    script.src = 'https://checkout.stripe.com/checkout.js'
    script.onload = this.setCheckout
    document.querySelector('head').append(script)
  },
  // NOTE: Should this be enabled for dynamic keys?
  // Cause if it gets updated very quickly, I
  // would imagine bad things would happen
  // updated() {
  //  this.setCheckout()
  // },
  beforeDestroy() {
    const stripeApp = document.querySelector('iframe.stripe_checkout_app')
    if (stripeApp) stripeApp.remove()
  },
  data: () => ({
    checkout: null,
    doneEmitted: false
  }),
  computed: {
    key() {
      return this.publishableKey || key
    }
  },
  methods: {
    setCheckout() {
      const stripeApp = document.querySelector(
        'iframe.stripe_checkout_app'
      )
      if (stripeApp) stripeApp.remove()
      this.checkout = StripeCheckout.configure({ key: this.key })
      if (this.autoOpenModal) this.open()
    },
    open() {
      if (!this.key) {
        return Promise.reject(
          new Error('Public key is required for VueStripeCheckout')
        )
      }
      return new Promise((resolve, _reject) => {
        const options = {
          key: this.key,
          image: this.image,
          name: this.name,
          description: this.description,
          amount: this.amount,
          locale: this.locale,
          zipCode: this.zipCode,
          currency: this.currency,
          panelLabel: this.panelLabel,
          email: this.email,
          billingAddress: this.billingAddress,
          allowRememberMe: this.allowRememberMe,
          token: (token, args) => {
            this.$emit('done', {token, args})
            resolve({token, args})
            this.doneEmitted = true
          },
          opened: () => { this.$emit('opened') },
          closed: () => {
            if (!this.doneEmitted) {
              this.$emit('canceled')
            }
            this.$emit('closed')
            this.doneEmitted = false
          },
        }
        if (this.shippingAddress)
          Object.assign(options, {
            shippingAddress: true,
            billingAddress: true,
          })
        this.checkout.open(options)
      })
    }
  }
}

@jofftiquez
Copy link
Member

Hello all, I merged the version 3 branch and made some fixes. Please upgrade and try the new version. Closing this now. Please create a new issue if there's any. Thank you.

IMPORTANT - there are breaking changes in the implementation, please read the documentation carefully.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants