0.0.1 • Published 8 months ago

@flagpole/vue v0.0.1

Weekly downloads
-
License
MIT
Repository
github
Last release
8 months ago

Flagpole Vue SDK

Vue.js SDK for the Flagpole feature flag management system. Provides real-time feature flag updates, A/B testing capabilities, and seamless integration with Vue 3 applications.

Installation

npm install @flagpole/client-vue socket.io-client
# or
yarn add @flagpole/client-vue socket.io-client

Quick Start

1. Setup with Plugin (Recommended)

// main.ts
import { createApp } from "vue";
import { createFlagpole } from "@flagpole/client-vue";
import App from "./App.vue";

const app = createApp(App);

app.use(
  createFlagpole({
    apiKey: "your-api-key-here",
    environments: ["development"], // Optional
  })
);

app.mount("#app");

2. Use in Components

<template>
  <div>
    <!-- Using directive -->
    <div v-feature-flag="'newFeature'">
      <h2>New Feature Content</h2>
    </div>

    <!-- Using composable -->
    <div v-if="isPremiumEnabled">
      <PremiumContent />
    </div>

    <!-- Loading and error states -->
    <div v-if="isLoading">Loading flags...</div>
    <div v-if="error">Error: {{ error.message }}</div>
  </div>
</template>

<script setup lang="ts">
import { useFeatureFlag, useFeatureFlags } from "@flagpole/client-vue";

// Individual flag
const isPremiumEnabled = useFeatureFlag("premiumFeature");

// All flags with state
const { flags, isLoading, error } = useFeatureFlags();
</script>

Features

Vue 3 Composition API - Built for modern Vue development
Real-time Updates - WebSocket integration for instant flag changes
TypeScript Support - Full type safety and IntelliSense
Multiple Usage Patterns - Composables, directives, and global methods
Vue Router Integration - Route guards based on feature flags
Environment Filtering - Show flags only for specific environments
Error Handling - Comprehensive error states and fallbacks
SSR Compatible - Works with Nuxt.js and other SSR frameworks

API Reference

Setup Methods

Plugin Installation

import { createFlagpole } from '@flagpole/client-vue';

app.use(createFlagpole({
  apiKey: string;
  environments?: string[]; // ['development', 'staging', 'production']
}));

Provider Component

<FeatureFlagProvider api-key="your-key" :environments="['dev']">
  <YourApp />
</FeatureFlagProvider>

Composables

useFeatureFlags()

const {
  flags, // ComputedRef<Record<string, FeatureFlag>>
  isLoading, // ComputedRef<boolean>
  error, // ComputedRef<Error | null>
  isFeatureEnabled, // (flagName: string) => boolean
} = useFeatureFlags();

useFeatureFlag(flagName)

const isEnabled = useFeatureFlag("flagName"); // ComputedRef<boolean>

Directive

<!-- Show when flag is enabled -->
<div v-feature-flag="'flagName'">Content</div>

<!-- Show when flag is disabled -->
<div v-feature-flag:not="'maintenanceMode'">Content</div>

Global Methods (Plugin Only)

// Template
$isFeatureEnabled("flagName");

// Script
this.$isFeatureEnabled("flagName");

Usage Examples

Conditional Rendering

<template>
  <div>
    <!-- Method 1: Directive -->
    <div v-feature-flag="'newDashboard'">
      <NewDashboard />
    </div>

    <!-- Method 2: Composable -->
    <div v-if="isBetaEnabled">
      <BetaFeature />
    </div>

    <!-- Method 3: Complex conditions -->
    <div v-if="showAdvancedFeatures">
      <AdvancedPanel />
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed } from "vue";
import { useFeatureFlag } from "@flagpole/client-vue";

const isBetaEnabled = useFeatureFlag("betaFeatures");
const isPremiumUser = useFeatureFlag("premiumAccess");

const showAdvancedFeatures = computed(
  () => isBetaEnabled.value && isPremiumUser.value
);
</script>

Route Protection

// router/index.ts
import { createRouter } from "vue-router";

function featureFlagGuard(flagName: string, redirectTo: string = "/") {
  return (to, from, next) => {
    const app = to.matched[0]?.instances?.default?.$parent?.$root;
    const isEnabled = app?.$isFeatureEnabled?.(flagName);

    isEnabled ? next() : next(redirectTo);
  };
}

const routes = [
  {
    path: "/beta",
    component: BetaFeature,
    beforeEnter: featureFlagGuard("betaAccess", "/coming-soon"),
  },
];

A/B Testing

<template>
  <component :is="checkoutVariant" />
</template>

<script setup lang="ts">
import { computed } from "vue";
import { useFeatureFlags } from "@flagpole/client-vue";

const { flags } = useFeatureFlags();

const checkoutVariant = computed(() => {
  const experiment = flags.value["checkoutExperiment"];
  const variant = experiment?.conditions?.variant || "control";

  return {
    control: CheckoutV1,
    variantA: CheckoutV2,
    variantB: CheckoutV3,
  }[variant];
});
</script>

Custom Composable

// composables/useNavigation.ts
import { computed } from "vue";
import { useFeatureFlag } from "@flagpole/client-vue";

export function useNavigation() {
  const hasNewNav = useFeatureFlag("newNavigation");
  const hasAdmin = useFeatureFlag("adminPanel");

  const menuItems = computed(() => {
    const items = [{ label: "Home", path: "/" }];

    if (hasNewNav.value) {
      items.push({ label: "Dashboard", path: "/dashboard" });
    }

    if (hasAdmin.value) {
      items.push({ label: "Admin", path: "/admin" });
    }

    return items;
  });

  return { menuItems };
}

Configuration

Environment Variables

// .env
VITE_FLAGPOLE_API_KEY = fp_live_your_api_key_here;
VITE_ENVIRONMENT = development;

// main.ts
app.use(
  createFlagpole({
    apiKey: import.meta.env.VITE_FLAGPOLE_API_KEY,
    environments: [import.meta.env.VITE_ENVIRONMENT],
  })
);

TypeScript Configuration

// types/flags.ts
export interface AppFeatureFlags {
  newDashboard: boolean;
  premiumFeatures: boolean;
  betaAccess: boolean;
}

// Custom typed composable
export function useTypedFeatureFlag<K extends keyof AppFeatureFlags>(
  flagKey: K
): ComputedRef<boolean> {
  return useFeatureFlag(flagKey);
}

Testing

// tests/FeatureComponent.test.ts
import { mount } from "@vue/test-utils";
import { createFlagpole } from "@flagpole/client-vue";

const mockFlagpole = createFlagpole({
  apiKey: "test-key",
});

describe("FeatureComponent", () => {
  it("shows feature when flag is enabled", () => {
    const wrapper = mount(FeatureComponent, {
      global: {
        plugins: [mockFlagpole],
      },
    });

    // Test enabled state
  });
});

SSR Support (Nuxt.js)

// plugins/flagpole.client.ts
import { createFlagpole } from "@flagpole/client-vue";

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.use(
    createFlagpole({
      apiKey: useRuntimeConfig().public.flagpoleApiKey,
      environments: [useRuntimeConfig().public.environment],
    })
  );
});

Requirements

  • Vue.js 3.3+
  • Node.js 16+
  • Modern browser with WebSocket support

Migration Guide

From Vue 2

This SDK is built for Vue 3. For Vue 2 support, please use the legacy version or consider upgrading to Vue 3.

From Other Flag Libraries

Replace your existing feature flag calls with Flagpole composables:

// Before (other library)
const isEnabled = useFlag("feature-name");

// After (Flagpole)
const isEnabled = useFeatureFlag("feature-name");

Contributing

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Commit changes: git commit -m 'Add amazing feature'
  4. Push to branch: git push origin feature/amazing-feature
  5. Open a Pull Request

Support

License

MIT © Flagpole


Made with ❤️ for the Vue.js community