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 🙏

© 2024 – Pkg Stats / Ryan Hefner

dende

v0.1.4

Published

Next Server UI adapters

Downloads

2

Readme

Dende - Next Server Toolbox

Overview

Dende is a toolbox for fullstack Next solutions that make it easier to translate your backend to your frontend. Dende includes solutions for feature flagging, and Server Component prop translation. Dende is a typescript package.

Install

Yarn

yarn install dende

pnpm

pnpm add dende


Feature Flags - Setup

Defining Flags - Environment Variables

You can define your feature flags in your app's env files or your app host's environment variable definitions (if applicable). Use a "DENDE" prefix in your environment variable in order for to be properly calculated. For example:

# env.local
DENDE_SECRET_FEATURE=true
#env.staging
DENDE_SECRET_FEATURE=true
#env
DENDE_SECRET_FEATURE=false

In this example, we can use DENDE_SECRET_FEATURE to hide a component from production.

Defining Flags - dende.config.ts

You can define a config file at the root of your project called dende.config.ts. You can use it to define feature flag states using the following strategies:

Static Flags

Similar to environment variables, you can also create a static flags using a custom feature state map with dende.config.ts file. For example:

// dende.config.ts

import { createFeatureConfig } from "dende/config";

export default createFeatureConfig({
  secretFeature: false,
  publicFeature: true,
});

Async Flags - dende.config.ts

If you want more dynamic feature flags or you want to retrieve them from a 3rd party vendor, you can use our cachedResolver in dende.config.ts file. Our cachedResolver utilizes Next fetch to call user defined API's and cache the responses. Here's how to use it:

// dende.config.ts

import { createFeatureConfig, cachedResolver } from "dende/config";

export default createFeatureConfig({
  asyncSecretFeature: () => cachedResolver("/api/hello", { callback: () => true }),
  asyncPublicFeature: () => cachedResolver("/api/hello",
    { callback: () => true, tags: ['holidayFeature'] }),
});

Busting Resolver Cache

Since our cachedResolver use Next fetch, you're able to take control of the cache management. In the second paramater, tags are allowed to be used (part of the Next fetch API), which enable you to bust the cache for groups of feature states as needed. Here's how you can do this with Next API routes:

Create a route dedicated to clear the cache for a set up features using a certain tag:

// app/api/features/revalidate/route.ts

import { updateFeature } from 'dende/config';
import { NextResponse } from 'next/server';

export async function POST(request: Request) {
  const { searchParams } = new URL(request.url);
  const secret = searchParams.get('secret');
  const tag = searchParams.get('tag');

  // Define an env var secret to protect this route from the public
  if (secret !== process.env.FEATURES_SECRET) {
    return NextResponse.error();
  }

  updateFeature(tag);

  return NextResponse.json({}, { status: 200 });
}

A call to /api/features/revalidate?tag=holidayFeature will now bust the cached response made for calls the API endpoints defined in the cachedResolver URL param. So the subsequent call to that URL will request, receive and cache the latest feature state data from the third party.

Client Setup - with Next Server Components and React Context

In an async page or layout component, use calculateFeatures from dende/config to calculate the feature flag states.

Layout component (Recommended)

Calculating feature states makes the most sense at the layout level because feature states are typically meant to be global. Here's how it works with layout:

layout.tsx

import { PropsWithChildren } from 'react';
import { calculateFeatures } from 'dende/config';

export default async function Layout({ children }: PropsWithChildren) {
  const features = await calculateFeatures();

  return (
    <AppShell features={features}>
      <h1>Hello World</h1>
    </AppShell>
  )
}

AppShell.tsx (example layout wrapper)

'use client'

import { FeatureMap } from 'dende/config';

type Props = PropsWithChildren & { features: FeatureMap }

export default function AppShell({ features, children }: Props) {
  return (
    <FeatureProvider map={features}>
      {chidlren}
    </FeatureProvider>
  )
}

Page component

page.tsx

import { calculateFeatures } from 'dende/config';

export default async function Page() {
  const features = await calculateFeatures();

  return (
    <PageWrapper>
      <h1>Hello World</h1>
    </PageWrapper>
  )
}

PageWrapper.tsx

'use client'

import { FeatureMap } from 'dende/config';

type Props = PropsWithChildren & { features: FeatureMap }

export default function PageWrapper({ features, children }: Props) {
  return (
    <FeatureProvider map={features}>
      {children}
    </FeatureProvider>
  )
}

Components

You can use our FeatureToggle and FeatureSetToggle component to gate certain client components based on feature flag states.

FeatureToggle

  <FeatureToggle feature="publicFeature">
    <div>Hello World</div>
  </FeatureToggle>

The component will show bsaed on the feature flag state.

FeatureSetToggle

  <FeatureSetToggle features={["publicFeature", "secretFeature"]}>
    <div>Hello World</div>
  </FeatureSetToggle>

Hooks

You can use our useFeature and useFeatureSet hooks to gate more intricate component logic based on feature flag state.

useFeature

  const Component = () => {
    const activateFeature = useFeature('publicFeature');
    return (
      <div>
        <h1>Hello World</h1>
        {activateFeature ? (
          <h2>There's a new feature ready!</h2>
        ) : (
          <h2>There's old feature</h2>
        )}
      </div>
    )
  }

useFeatureSet

  const Component = () => {
    const activateFeature = useFeatureSet(['secretFeature', 'publicFeature']);
    return (
      <div>
        <h1>Hello World</h1>
        {activateFeature ? (
          <h2>Secret feature is ready!</h2>
        ) : (
          <h2>Secret feature is not ready yet</h2>
        )}
      </div>
    )
  }