Open rktmatt opened 2 months ago
hey @rktmatt The thing is we do follow stripe recommandation. They do recommand to use async load for it. Thats what we do by using their js module as its them who handle it.
I would say that you would have no choice than waiting it to be available and handle use case for slow network. I general having a loading state would be a better alternative as you would not block the user interaction and load page for the end user
I have no problem with async loading of the script. My issue is that the module doesn't load the script at all when a page isn't using it.
The other issue is that the await doesn't await Stripe, but await the start of loading Stripe. Which makes the module not working when doing a simple : useClientStripe()
Also having no types out of the box is not very convenient.
Or am I using it wrong ?
We normally do have typing yes probably something wrong on your side. I would need a repo to see why you have an issue.
You right. In the doc we do have check on the if stripe
https://github.com/fuentesloic/nuxt-stripe?tab=readme-ov-file#example-1
If you want to update this behavior don't hesitate to update the code. But this should be enough for you I think to work with.
Thanks for your support. Here is a reproduction link : https://github.com/rktmatt/stripe-nuxt-repro
All in app.vue
Thanks I have a lot of works but try to look later this weekend
I modified the files for my own use and came up something like this. Also using latest versions of stripe and stripe-js.
Not sure if best approach but works for me.
useClientStripe.ts
import { loadStripe } from '@stripe/stripe-js'
import type { Stripe } from '@stripe/stripe-js'
import { onMounted, watch, computed } from 'vue'
export default function useClientStripe( onReadyCallback?: ( stripe: Stripe | null ) => void | Promise<void> ) {
const stripe = useState<Stripe | null>( 'stripe-client', () => null )
const ready = useState( 'stripe-client-ready', () => false )
const key = useRuntimeConfig().public.stripePublicKey
async function _loadStripe() {
if ( stripe.value ) {
return stripe.value
}
if ( !key ) console.warn( 'no key given for Stripe client service' )
const _stripe = await loadStripe( key )
stripe.value = _stripe
ready.value = true
return _stripe
}
onMounted( async () => {
if ( !ready.value ) {
await _loadStripe()
}
} )
watch( ready, async ( newReady ) => {
if ( newReady && onReadyCallback ) {
await onReadyCallback( stripe.value )
}
} )
return {
stripe,
ready: computed( () => ready.value ),
}
}
Can be used for example like this
const initCheckout = async ( stripe: Stripe | null ) => {
if ( !stripe ) {
throw new Error( 'Stripe is not available' )
}
if ( !checkoutSession.value ) {
throw new Error( 'Checkout session is not available' )
}
const fetchClientSecret = async () => {
return checkoutSession.value?.clientSecret || ''
}
const checkout = await stripe.initEmbeddedCheckout( {
fetchClientSecret,
} )
checkout.mount( '#checkout' )
}
useClientStripe( initCheckout )
OR
useClientStripe( async ( stripe ) => {
if ( !stripe ) {
throw new Error( 'Stripe is not available' )
}
if ( !checkoutSession.value ) {
throw new Error( 'Checkout session is not available' )
}
const fetchClientSecret = async () => {
return checkoutSession.value?.clientSecret || ''
}
const checkout = await stripe.initEmbeddedCheckout( {
fetchClientSecret,
} )
checkout.mount( '#checkout' )
} )
OR
const { stripe, ready } = useClientStripe()
watch(ready, (newReady) => {
if (newReady) {
// Stripe client is ready, you can use it now
console.log('Stripe client is ready:', stripe.value)
}
})
onMounted(() => {
if (ready.value) {
// Stripe client was already ready at mount
console.log('Stripe client is ready:', stripe.value)
}
})
Summary
I recently encountered issues using the
nuxt-stripe
package on a slow network. After some debugging, I discovered that theuseClientStripe()
composable returns a promise to load Stripe.js v3.Problem
The promise when awaited doesn't guarantee that Stripe is loaded. Example :
To work around this, I had to watch for the Stripe object and use it once it had loaded. Edit: this didn't work for submitting form. So I used @stripe/stripe-js as a plugin and stopped using this package
Stripe's Recommendation
Stripe's documentation advises that Stripe.js should be loaded on every page to enhance fraud detection:
Proposal
Would it be possible to add a configuration option to the
nuxt-stripe
package that allows Stripe.js to be injected on every page and available ? This would align with Stripe's best practices and improve user experience, especially on slower networks.Thank you for considering this enhancement!