npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

flagmint-vuejs-feature-flags

v1.3.9

Published

A Vue.js SDK for managing feature flags in Flagmint applications, supporting both Vue 2 and Vue 3.

Readme

Flagmint Vue Feature Flags SDK

A lightweight and powerful feature flag SDK for Vue 2 and Vue 3 applications.

Supports:

✅ Client-side flag evaluation
✅ Segment targeting and rollout strategies
✅ WebSocket or HTTP long-polling
✅ Offline caching and preview mode
✅ Vue 2 and Vue 3 plugin, composables, and helpers ✅ Cross-Iframe & Multi-Tab Socket Optimization (Leader Election)

🔧 Installation

npm install flagmint-vuejs-feature-flags

🚀 Quick Start

Vue 2

// main.js
import Vue from 'vue';
import { createFlagmintPlugin } from 'flagmint-vuejs-feature-flags';

Vue.use(createFlagmintPlugin({
  apiKey: 'your-api-key',
  context: { user_id: 'abc123', country: 'NG' },
  transportMode: 'auto',
  autoRefresh: true,
  previewMode: false,
  // Optional Cross-Iframe Optimization Parameters:
  syncCrossIframes: true,
  syncNamespace: 'wsd_app_prod'

}));

new Vue({ render: h => h(App) }).$mount('#app');

Vue 3

// main.ts
import { createApp } from 'vue';
import App from './App.vue';
import { createFlagmintPlugin } from 'flagmint-vuejs-feature-flags';

const app = createApp(App);

app.use(createFlagmintPlugin({
  apiKey: 'your-api-key',
  context: { user_id: 'abc123' },
  transportMode: 'auto',
  previewMode: false,
   // Optional Cross-Iframe Optimization Parameters:
  syncCrossIframes: true,
  syncNamespace: 'wsd_app_prod'
}));

app.mount('#app');

⚙️ API Overview

FlagClientOptions

interface FlagClientOptions {
  apiKey: string;
  context?: Record<string, any>;
  autoRefresh?: boolean;
  refreshIntervalMs?: number;
  persistContext?: boolean;
  env?: string; // production | staging
  enableOfflineCache?: boolean;
  cacheTTL?: number;
  transportMode?: 'auto' | 'websocket' | 'long-polling';
  previewMode?: boolean;
  onError?: (err: Error) => void;

  // Framework Extension Parameters
  deferInitialization?: boolean;
  syncCrossIframes?: boolean; // Collapses multiple nested iframes/tabs down to 1 open socket
  syncNamespace?: string;     // Unique isolation scope descriptor to prevent account data bleed
}

🎯 Using Flags

Cross-Iframe & Multi-Tab Connection Sharing

When embedding your Vue application multiple times on a single webpage using nested iframe configurations (or when a user leaves your app open across multiple simultaneous browser windows), initializing separate WebSockets or SSE streams per view causes significant connection overhead.

Setting syncCrossIframes: true leverages a reactive browser mesh network strategy via the BroadcastChannel API and Page Visibility API to solve this issue seamlessly.

🔒 Security Notice: Always match your syncNamespace parameter configuration with your underlying profile or customer session parameters (e.g. syncNamespace: currentSiteId). This isolates the messaging context and prevents separate client scopes from accidentally reading or blending flag variants in multi-tenant environments.


### ✅ Recommended (Reactive Flags)

Subscribe to flag updates so your component re-renders automatically on every WebSocket push:

```ts
// Vue 3 Composition API
import { useFlagmint } from 'flagmint-vuejs-feature-flags';

const { getFlag, isReady } = useFlagmint();
const darkMode = computed(() => getFlag('dark-mode', false));
// Vue 2 (via mixin)
export default {
  mixins: [useFlagsMixin],
  mounted() {
    console.log(this.flags['dark-mode']);
    console.log(this.getFlag('dark-mode', false));
  }
}

⚠️ Non-reactive (snapshot only, won't update on push)

const enabled = this.$flagmint.getFlag('dark-mode', false);

Use this only when you genuinely need a one-time read (e.g. inside a non-reactive utility function). For anything rendered in a template, use the reactive pattern above.


⏳ Await Initialization

$flagmintReady is a reactive boolean ref, not a Promise — watch it rather than awaiting it:

// Vue 2
this.$watch('$flagmintReady', (ready) => {
  if (ready) { /* client is ready */ }
});
// Vue 3
import { useFlagmintReady } from 'flagmint-vuejs-feature-flags';
const isReady = useFlagmintReady(); // Ref<boolean>
watch(isReady, (ready) => {
  if (ready) { /* client is ready */ }
});

If you need a one-time async wait (e.g. before an onMounted block runs), call the injected init() function instead — it returns a Promise that resolves once the client is ready:

const client = await this.$flagmintInit(); // Vue 2

🔌 Vue 2 Helpers

$flagmint access

export default {
  async mounted() {
    const client = await this.$flagmintInit();
    const enabled = client.getFlag('dark-mode', false);
  }
}

✅ Vue 2 Mixin

import { useFlagsMixin } from 'flagmint-vuejs-feature-flags/vue2/mixin/useFlagsMixin';

export default {
  mixins: [useFlagsMixin],
  mounted() {
    console.log(this.flags['dark-mode']);
    console.log(this.getFlag('dark-mode', false));
  }
}

🔌 Vue 3 Helpers

Option A: Composition API (Recommended)

import { useFlagmint } from 'flagmint-vuejs-feature-flags';

export default {
  setup() {
    const { getFlag, isReady } = useFlagmint();
    const feature = computed(() => getFlag('chat-enabled', false));
    return { feature };
  }
}

Option B: Injected

import { inject } from 'vue';

export default {
  setup() {
    const client = inject('__flagmint__');
    const feature = client?.getFlag('chat-enabled');
    return { feature };
  }
}

💡 Debugging Broadcast Channels in DevTools

To verify that multiple frames are collapsing down to a single socket on your local device environment:

  • Open Chrome/Edge DevTools (F12) and head to the Application tab.
  • In the left panel section menu, find Background Services and click on Broadcast Channels.
  • Reload your project page setup. You will see your namespace registration signature.
  • Click on your project Network panel tab. Confirm that switching windows or updating your cloud variables updates all views concurrently while creating exactly one websocket initialization record track.

🧩 Feature Component

In Vue templates, use the <BoolFeatureGate> component: is for boolean flags only, and string/number/JSON flags should be read via getFlag() directly and branched on with v-if.

<template>
  <BoolFeatureGate featureKeys="['dark-mode']">
    <div>Dark mode is enabled!</div>
  </BoolFeatureGate>
</template>

<script setup lang="ts">
import { BoolFeatureGate } from 'flagmint-vuejs-feature-flags/vue3/Feature';
</script>

feature-keys accepts a single string or an array of strings. If multiple keys are provided, all must be enabled.

⚠️ Important: Never call client.destroy() from within a component or composable. destroy() tears down the shared WebSocket connection for the entire application. If you're building a custom integration around FlagClient, only ever call client.subscribe() and its returned unsubscribe function for component-level cleanup.


🧪 Preview Mode (No Network)

Enable previewMode: true in FlagClientOptions to evaluate flags locally only:

  • No API key needed
  • Useful for SDK testing, Storybook, or static environments
createFlagmintPlugin({
  previewMode: true,
  context: { user_id: 'test' }
});

You can then load flags directly:

flagClient.setFlags([flag1, flag2], segmentsById);

⚠️ A console warning appears in development when previewMode is active.


🧠 Evaluation Logic

  • Operators: eq, neq, in, nin, gt, lt, exists, not_exists

  • Segment references and rule groups

  • Rollout strategies:

    • percentage — user hashes to percentile
    • variant — weighted multi-variant assignment

🔁 Realtime Updates

Using transportMode: 'websocket' or 'auto', flags update live when changed.

Fallback to polling if WebSocket fails.


📦 Versioning & Releases

This project follows Semantic Versioning. Releases are automated via GitHub Actions:

  • Changes to sdk/, package.json, rollup.config.js, or tsconfig.json on the main branch trigger the release workflow
  • The workflow extracts the version from package.json, builds the package, and publishes to npm
  • Git tags and GitHub releases are automatically created

To release a new version:

  1. Update the version in package.json
  2. Update CHANGELOG.md with your changes
  3. Push to main branch
  4. The workflow handles the rest

See CHANGELOG.md for version history and release notes.


🤝 Contributing

Contributions are welcome! Here's how to get started:

  1. Clone the repository
  2. Install dependencies: npm install
  3. Run tests: npm test
  4. Build the project: npm run build
  5. Create a feature branch: git checkout -b feature/your-feature
  6. Make your changes and commit
  7. Push to your fork and create a Pull Request

Development Tips:

  • The SDK supports both Vue 2 and Vue 3 — test changes against both versions
  • Keep bundle size in mind when adding dependencies
  • Run tests before submitting PRs
  • Never call client.destroy() from a component, mixin, or composable — only the plugin/app-level teardown should own that call

🗂 Roadmap

  • [x] Segment evaluation
  • [x] Rollout strategies
  • [x] Preview/local-only mode
  • [x] Composables and mixins
  • [x] WebSocket + fallback
  • [x] Feature component
  • [ ] SSR / Nuxt support
  • [ ] Variant analytics
  • [ ] Remote override via devtools

🐛 Troubleshooting

Flags not loading

  • Ensure apiKey is valid and environment has network access
  • Check browser console for errors
  • Verify context is properly set with required attributes
  • If using previewMode: true, ensure you've called flagClient.setFlags()

WebSocket connection fails

  • The SDK automatically falls back to long-polling
  • Check network connectivity and CORS settings
  • Verify the API server supports WebSocket connections
  • Check browser console for connection errors

Component re-renders not happening on flag updates

  • Make sure you're using the reactive pattern (useFlagmint() composable or useFlagsMixin) rather than calling client.getFlag() directly in a computed. The client's internal flag state is not a Vue reactive object — only the subscribe()-backed wrappers re-render correctly
  • If you unmounted and remounted a <BoolFeatureGate> and updates stopped working app-wide, confirm nothing in your codebase calls client.destroy() outside of app-level teardown

Stale flags in offline cache

  • Clear localStorage or set enableOfflineCache: false
  • Adjust cacheTTL to control cache duration (in milliseconds)
  • Use previewMode: true for testing without network

Performance issues

  • Limit the number of flags in targeting rules
  • Use the subscribe()-backed reactive pattern (via composable or mixin) instead of polling getFlag() in a loop
  • Consider lazy-loading flags for large applications

TypeScript issues

  • Ensure tsconfig.json includes sdk/ in include paths
  • Check that node_modules types are installed: npm install

📜 License

BSD 3-Clause License