Bundle size and tree-shaking
Vue Stripe is tree-shakeable. Your app's bundle gets only the components and composables you import, plus the code they share. Import the Payment Element and usePaymentIntent, and the Card Element, the Checkout components and the rest of the library stay out.
The whole library
11.8 kB
A Payment Element checkout
4.2 kB
useStripe alone
330 B
A Payment Element checkout is 36% of the library. The rest stays out of your bundle.
The site measures these numbers from the library's own build each time it is built, so they match the version shown. How the numbers are measured explains the method.
What a typical integration costs
An integration imports a few pieces together, and they share code: the provider plumbing and the element factory are counted once, however many pieces use them.
| Integration and its imports | Minified | Gzipped |
|---|---|---|
Payment Element checkout VueStripeProviderVueStripeElementsVueStripePaymentElementusePaymentIntent | 12.06 kB | 4.23 kB36% of the library |
Card Element payment VueStripeProviderVueStripeElementsVueStripeCardElementuseConfirmCardPayment | 10.87 kB | 3.97 kB34% of the library |
Embedded Checkout VueStripeProviderVueStripeEmbeddedCheckout | 6.15 kB | 2.52 kB21% of the library |
Redirect to Stripe Checkout useStripeCheckout | 492 B | 313 B3% of the library |
The first element and the ones after it
Every element component is a small definition (its element type, events and options) handed to one shared factory. That factory does the real work: it creates and mounts the Stripe element, wires its events, tracks loading and errors, and renders the slots. The first element you import brings the factory with it. Every element after it adds only its own definition.
The first elementVueStripePaymentElement on its own
2.21 kB
Each element after itits own definition, median of every element
61 B
- Element factory and provider plumbing, shared: 2.03 kB
- One element's own definition: 176 B for the Payment Element, 26 B to 257 B across all of them (61 B median)
How tree-shaking works here
Four things let a bundler leave out what you don't use.
- An ES module build. The package's
exportsmap sendsimporttodist/es/index.js, an ES module, and bundlers that don't readexportsfind the same file through themodulefield. Bundlers can only tree-shake ES modules. "sideEffects": ["*.css"]. This field in the package'spackage.jsontells bundlers that importing the library's JavaScript does nothing by itself, so code you don't reference can go. Only the stylesheet is listed, soimport '@vue-stripe/vue-stripe/style.css'is always kept./* @__PURE__ */on every definition. Each element component is the result of acreateStripeElement({ ... })call, and each method composable (useConfirmCardPaymentand the other confirmers) of a factory call too. A bundler can't tell on its own that such a call has no side effects, so it would keep every component. Each of these calls is marked/* @__PURE__ */, which tells the bundler it may drop the result when nothing uses it.- Named imports.
import { VueStripePaymentElement } from '@vue-stripe/vue-stripe'names exactly what you use. A namespace import (import * as VueStripe) tree-shakes just as well while you only read members by name, such asVueStripe.useStripe. Code that walks the whole namespace keeps every export.
// Correct: only the provider, the Elements wrapper and the Payment Element are bundled
import {
VueStripeProvider,
VueStripeElements,
VueStripePaymentElement
} from '@vue-stripe/vue-stripe'
// Wrong: the loop reads every export, so the whole library is bundled
import * as VueStripe from '@vue-stripe/vue-stripe'
for (const [name, component] of Object.entries(VueStripe)) app.component(name, component)The createVueStripe() plugin provides Stripe to the whole app and registers no components, so installing it adds only the plugin itself.
What these numbers leave out
- Vue. It is a peer dependency, so your app already has it and the numbers never count it. The same goes for
vue-demi, the small module that lets one build run on Vue 3 and Vue 2.7 by re-exporting your app's Vue. - Stripe.js. Stripe.js itself is never in your bundle. Stripe requires it to be loaded from
js.stripe.com, and the@stripe/stripe-jsloader adds that script tag at runtime (How Stripe.js is loaded explains when).@stripe/stripe-jsis a peer dependency you install next to Vue Stripe, and Vue Stripe imports only itspureloader. The table below gives that loader's own size. The UMD build is the exception: it includes the loader (see below). - The stylesheet. The element styles are a separate CSS file,
@vue-stripe/vue-stripe/style.css, which your app imports once. It is measured on its own below.
| Not in the import sizes | Size | Gzipped |
|---|---|---|
Stylesheet, @vue-stripe/vue-stripe/style.cssImported once by your app | 6.92 kB | 1.06 kB |
@stripe/stripe-js 10.1.0 loader, minified The pure entry; a peer dependency in your app, not part of Vue Stripe | 3.31 kB | 1.52 kB |
CommonJS build, dist/cjs/index.cjsEvery export; does not tree-shake | 48.06 kB | 11.89 kB |
UMD build, dist/umd/index.js Every export and the @stripe/stripe-js loader, for a script tag; does not tree-shake | 50.88 kB | 13.18 kB |
CommonJS and UMD builds
The package ships two more builds, and neither of them tree-shakes. Each is one file with every export in it.
- CommonJS (
dist/cjs/index.cjs) is whatrequire('@vue-stripe/vue-stripe')loads: Node, test runners and tools that don't read ES modules. On a server its size doesn't matter. In a browser bundle it would, so check that your bundler takes the ES build. Any bundler that readsexportsormoduledoes. - UMD (
dist/umd/index.js) is for a<script>tag, loaded from unpkg or jsDelivr. It defines aVueStripeglobal with every export, because no bundler runs to leave anything out. It also includes the@stripe/stripe-jspureloader, which publishes no file for a<script>tag, so the page needs only Vue and vue-demi before it (Without a bundler). Stripe.js itself still loads fromjs.stripe.com.
Their sizes are in the table above.
Check the size in your own app
The numbers here are for Vue Stripe alone. Your bundler shows what it costs in your app, next to everything else:
- Vite prints each output file with its gzipped size at the end of
vite build. For a breakdown by module, add rollup-plugin-visualizer, which draws a treemap of the build. - Nuxt:
npx nuxi analyzebuilds the app and opens the same kind of treemap. - Vue CLI (webpack):
vue-cli-service build --reportwritesdist/report.html.
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
plugins: [vue(), visualizer({ gzipSize: true, open: true })]
})In the report, look for @vue-stripe/vue-stripe: only the exports you use, and the code they share, should be there.
The size budget in CI
The library has a size budget, and CI enforces it. packages/vue-stripe/.size-limit.json sets a limit, minified and gzipped, for the whole ES build, the whole UMD build (with the @stripe/stripe-js loader in it) and three single imports. size-limit checks them on every pull request and again before each release is published, and a change that goes over a limit fails. CI also comments each pull request with the size change against its base branch. To check locally, run pnpm size in the repository.
| Check | Limit | Measured | Headroom |
|---|---|---|---|
| ESM bundle (dist/es/index.js) | 11.79 kB | 11.77 kB | 23 B |
| UMD bundle (dist/umd/index.js), with the @stripe/stripe-js loader | 13.38 kB | 13.36 kB | 22 B |
| Tree-shaken: import { VueStripeCardElement } | 2.10 kB | 2.08 kB | 16 B |
| Tree-shaken: import { useStripe } | 340 B | 330 B | 10 B |
| Tree-shaken: import { useConfirmCardPayment } | 640 B | 626 B | 14 B |
How the numbers are measured
When the site is built, it bundles each export from the library's ES build with Rolldown, the bundler in Vite 8 and the one size-limit uses. Each measurement is an import { ... } from '@vue-stripe/vue-stripe', tree-shaken and minified, with Vue and @stripe/stripe-js left external, then gzipped at the highest level. The few bytes of the importing module itself are taken off, as size-limit does, so the figures match the CI budgets to the byte.
So these are the sizes Vue Stripe adds to an app built with Vite 8, which bundles with Rolldown too. Vite 5 to 7 bundle with Rollup and minify with esbuild; measured that way, the same imports keep the same code and come out within 4% of these figures.
Every export
Each export below is imported on its own, with the shared code it needs. Exports share that code, so the sizes of two exports add up to more than the two cost together. The groups follow the API reference, smallest first.
Providers and plugin
| Export | Minified | Gzipped |
|---|---|---|
create | 2.02 kB | 1.01 kB |
Vue | 3.80 kB | 1.59 kB |
Vue | 3.50 kB | 1.61 kB |
Element components
| Export | Minified | Gzipped |
|---|---|---|
Vue Adds 26 B after another element | 4.71 kB | 2.04 kB |
Vue Adds 27 B after another element | 4.72 kB | 2.04 kB |
Vue Adds 36 B after another element | 4.79 kB | 2.06 kB |
Vue Adds 48 B after another element | 4.76 kB | 2.07 kB |
Vue Adds 43 B after another element | 4.83 kB | 2.07 kB |
Vue Adds 44 B after another element | 4.84 kB | 2.08 kB |
Vue Adds 57 B after another element | 4.80 kB | 2.08 kB |
Vue Adds 56 B after another element | 4.78 kB | 2.08 kB |
Vue Adds 58 B after another element | 4.80 kB | 2.08 kB |
Vue Adds 61 B after another element | 4.82 kB | 2.08 kB |
Vue Adds 62 B after another element | 4.82 kB | 2.08 kB |
Vue Adds 54 B after another element | 4.83 kB | 2.08 kB |
Vue Adds 64 B after another element | 4.82 kB | 2.08 kB |
Vue Adds 53 B after another element | 4.90 kB | 2.09 kB |
Vue Adds 62 B after another element | 4.85 kB | 2.09 kB |
Vue Adds 76 B after another element | 4.84 kB | 2.10 kB |
Vue Adds 77 B after another element | 4.96 kB | 2.10 kB |
Vue Adds 62 B after another element | 4.91 kB | 2.11 kB |
Vue Adds 62 B after another element | 4.97 kB | 2.13 kB |
Vue Adds 122 B after another element | 5.15 kB | 2.20 kB |
Vue Adds 176 B after another element | 5.18 kB | 2.21 kB |
Vue Adds 257 B after another element | 5.59 kB | 2.34 kB |
Checkout and pricing table
| Export | Minified | Gzipped |
|---|---|---|
Vue | 1.83 kB | 912 B |
Vue | 2.97 kB | 1.43 kB |
Vue | 3.65 kB | 1.58 kB |
Vue Another name for VueStripeCheckoutElementsProvider | 3.65 kB | 1.58 kB |
Vue | 3.49 kB | 1.61 kB |
Vue | 3.76 kB | 1.63 kB |
Vue | 4.99 kB | 2.13 kB |
Disclosures
| Export | Minified | Gzipped |
|---|---|---|
Vue | 3.21 kB | 1.54 kB |
Vue | 3.23 kB | 1.55 kB |
Vue | 3.23 kB | 1.55 kB |
Composables
| Export | Minified | Gzipped |
|---|---|---|
use | 492 B | 313 B |
use Another name for useStripeCheckout | 492 B | 313 B |
use | 534 B | 330 B |
use | 882 B | 433 B |
use Another name for useStripeElements | 882 B | 433 B |
use | 1.11 kB | 567 B |
use | 1.23 kB | 608 B |
use | 1.10 kB | 620 B |
use | 1.10 kB | 623 B |
use | 1.13 kB | 629 B |
use | 1.14 kB | 634 B |
use | 1.12 kB | 634 B |
use | 1.12 kB | 635 B |
use | 1.48 kB | 656 B |
use | 1.42 kB | 695 B |
use | 1.52 kB | 736 B |
use | 1.74 kB | 757 B |
use | 1.98 kB | 777 B |
use | 1.96 kB | 778 B |
use | 2.28 kB | 884 B |
use | 1.85 kB | 914 B |
Method confirmers
Utilities and errors
| Export | Minified | Gzipped |
|---|---|---|
stripe | 85 B | 69 B |
Vue | 138 B | 107 B |
Vue | 138 B | 108 B |
Vue | 138 B | 109 B |
load | 453 B | 299 B |
