Coder Social home page Coder Social logo

sergiodxa / flagged Goto Github PK

View Code? Open in Web Editor NEW
395.0 4.0 20.0 1.57 MB

Feature Flags for React made easy with hooks, HOC and Render Props

Home Page: https://github.com/sergiodxa/flagged

License: MIT License

TypeScript 83.42% HTML 2.16% JavaScript 14.42%
react hooks react-hooks higher-order-component hoc render-props render-prop typescript feature-flags

flagged's Introduction

Hi! I'm Sergio

Web Developer

Currently coding Daffy.org

Previously @prmkr, @platzi (YC W15), @vercel, and @able_co.

Organizer of @techtalks_pe.

Repos are my own.

flagged's People

Contributors

dependabot-preview[bot] avatar dependabot[bot] avatar jabberhams avatar sergiodxa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

flagged's Issues

<Feature> Component support camelCase names?

Looking at the code I don't see why the case of feature used in an object would change?
Are you able to highlight why
works: <FlagsProvider features={{ test_feature: true } || {}}>
and does not work: <FlagsProvider features={{ testFeature: true } || {}}>

Display a fallback when the feature is not enabled

Introduction:

Hello! Thank you for sharing your project, it's great! I just have a suggestion to display the fallback case from a function like 'render'.

Case:

The writing of a 'renderFallback' prop:
A function to execute in case the call to 'useFeature(name: string)' returns false inside the 'Feature' component.

E.g:

  • flagged/src/index.tsx
    export function Feature
 (...)
 const hasFeature = useFeature(name);
+ if (!hasFeature && typeof renderFallback === 'function') return renderFallback();
 if (typeof render === 'function') return render(hasFeature);
 return render;

Sugestion:

We would implement an optional renderFallback prop with null starting value here:

flagged/src/index.tsx

export function Feature({
  name,
  children,
  render = children,
+ renderFallback = null
}:{
  name: string;
  children?:
    | React.ReactNode
    | ((hasFeature: boolean | FeatureGroup) => JSX.Element);
  render?:
    | React.ReactNode
    | ((hasFeature: boolean | FeatureGroup) => JSX.Element);
+ renderFallback?:
+   | React.ReactNode
+   | (() => JSX.Element);
}) 

then return the renderFallback function value after validating hasFeature here:

  const hasFeature = useFeature(name);
+if (!hasFeature && typeof renderFallback === 'function') return renderFallback();
  if (typeof render === 'function') return render(hasFeature);
  return render;

flagged/example/src/index.js

+ {/* Render and Fallback Prop */}
+ <Feature name="v3" render={<V3Component />} renderFallback={<p>You are not in V3.</p>} />

Thanks for reading.

Support for more complex flags object

First of all, I like how simple the lib is also keeping it useful. 👍

My question is, do you have any plans to support more complex flags object?
I have an example.

I know I could use this example, but I don't need everything from that lib.

Let me know, I can open a PR for this.

Request to support feature disabled for Wrapper Component Feature

I'd like to have an option to use the Feature wrapper component for elements when a feature is disabled. That would help to easier build alternative route when features are not enabled.

Possible solution example might be:

<FlagsProvider features={{ myFlag: true }}>
    <Feature name="myFlag">
        // feature enabled render part
    </Feature>
    <Feature name="myFlag" disabled>
        // feature disabled render part
    </Feature>
</FlagsProvider>

Another idea could be a different Wrapper like NotFeature:

<FlagsProvider features={{ myFlag: true }}>
    <Feature name="myFlag">
        // feature enabled render part
    </Feature>
    <NotFeature name="myFlag">
        // feature disabled render part
    </NotFeature>
</FlagsProvider>

PS: I see that there is the option to go via the render attribute on Feature but the above requested solutions would pay in as convenience options.

Provider chaining support

Additional Context

Any plans to support provider chaining? I have a use case which some points of the application have additional features or change exiting ones.

I've tried to implement a wrapper around FlagsProvider using useFeatures but it throws an error if there's no provider declared. I've wrapped with a try catch but heard that it's not the best practice for hooks.

Example:

<FlagsProvider features={{ a: { enabled: true }, b: { enabled: true } }}>
  <FlagsProvider features={{ a: { enabled: false } }}>
    // .. here I'd receive a.enabled === false and b.enabled === true
  </FlagsProvider>  
</FlagsProvider>

I have three ideas:

  1. Export the context; or
  2. Remove throw error from useFeatures; or
  3. Implement chaining by default inside the library.

Let me know if this could be something useful for you and I can open a PR.

Undefined variable warning

Webstorm throws warnings about unfined variables: "Unresolved variable isEnabled"

const FEATURE_FLAGS = useFeatures();
if (FEATURE_FLAGS.FEATURE_SEND_USER_CODES?.isEnabled) {
    console.log('FEATURE_SEND_USER_CODES is enabled');
}

image

Is there any way to hide it?

I've added // noinspection JSUnresolvedVariable but that's a pain.

Error when using `useFeature` hook and feature is not defined

Current Behavior

When I have code that looks like this:

import { useFeature } from "flagged";

export function Header() {
	const hasV2 = useFeature("v2");

	return <header>{hasV2 ? <h1>My App v2</h1> : <h1>My App v1</h1>}</header>;
}

createRoot(document.getElementById("root")!).render(
	<FlagsProvider features={{ v3: true, moderate: false }}>
		<Header />
	</FlagsProvider>,
);

We get an exception thrown from this split method

Expected Behavior

Would love for it to essentially default to the flag being off if it can't find the flag in the provider and then do something like a console.warn to let me know that the flag is missing rather than throwing a 'cannot split on undefined' error message.

Suggested Solution(s)

Check if the flag doesn't exit
If the flag requested by the hook doesn't exist, treat it as if the flag were disabled and then throw a warning into the console

Your Environment

Software Version
Flagged ^2.0.8
React 17
Browser Chrome
npm/yarn npm

How to get the list of features on a Class Component?

Additional Context

Let's say I have a react js Class Component and want to get access to the list of features that were passed to <FlagsProvider />. How can I achieve that?
The useFeatures() hook gives me what I want but we can't use hooks in Class Components.

Let me know if it is clear.
Congrats on the library, very nice!

Is the package transpiled?

Additional Context

I've noticed that older browsers (e.g., previous version of the Edge browser with the Edge engine) get the following error Object doesn’t support property or method "fromEntries".

Example from README gives TypeScript error

Hi, thanks for all your work on this package :)

I might have found a documentation issue or perhaps a bug?

Copying this from the examples in the README:

<Feature name="v2">
  {(isEnabled: boolean) =>
    isEnabled ? <h1>My App v2</h1> : <h1>My App v1</h1>
  }
</Feature>;

Gives me this TypeScript warning:

Type '(isEnabled: boolean) => JSX.Element' is not assignable to type 'ReactNode | ((hasFeature: boolean | FeatureGroup) => Element)'.
  Type '(isEnabled: boolean) => JSX.Element' is not assignable to type '(hasFeature: boolean | FeatureGroup) => Element'.
    Types of parameters 'isEnabled' and 'hasFeature' are incompatible.
      Type 'boolean | FeatureGroup' is not assignable to type 'boolean'.
        Type 'FeatureGroup' is not assignable to type 'boolean'.ts(2322)

My TS skills aren't good enough to debug this myself but I got the sense that perhaps a feature may have been added since the examples were added?

This gives no warning, but I'm not sure I'm handling the possibility of isEnabled being a FeatureGroup here:

<Feature name="v2">
  {(isEnabled) => (isEnabled ? <h1>My App v2</h1> : <h1>My App v1</h1>)}
</Feature>;

Validate multiple feature names at once

Hello there!
how can I validate multiple feature names with the Feature component?

Basically I want to do this:

<Feature names={[feature1, feature2]}>
</Feature>

To enable the render only if all features are enabled

Error: Invalid hook call. Hooks can only be called inside of the body of a function component.

Current Behavior

This throws an error with React 18.2.0:

Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
    at resolveDispatcher (react.development.js:1476:1)
    at useContext (react.development.js:1484:1)
    at useFeatures (flagged.esm.js:44:20)
    at FlagsProvider (flagged.esm.js:37:1)
    at renderWithHooks (react-dom.development.js:16305:1)
    ...

This is the code I have for dist/flagged.esm lines 33-45:

function FlagsProvider(_ref) {
  var _ref$features = _ref.features,
      features = _ref$features === void 0 ? {} : _ref$features,
      children = _ref.children;
  var currentFeatures = useFeatures();
  return createElement(FeatureFlagsContext.Provider, {
    value: mergeFeatures(transformFlags(currentFeatures), transformFlags(features))
  }, children);
} // Custom Hook API

function useFeatures() {
  return useContext(FeatureFlagsContext);
} // Custom Hook API

Expected Behavior

No error. I had no error with React 17.0.2.

Suggested Solution(s)

After upgrading to React 18, the Auth0 Provider for v1.1.12 also gave the same error. Upgrading that to v2 fixed the error. So if you look at the https://github.com/auth0/auth0-react library provider changes between v1 and v2 that might give an idea for a fix.

Additional Context

Your Environment

Software Version
Flagged 2.0.9
React 18.2.0
Browser FF v116
npm/yarn 8.19.4

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.