Skip to content

Commit

Permalink
feat: add IfEnabled helper (#704)
Browse files Browse the repository at this point in the history
  • Loading branch information
ajwootto authored Jan 25, 2024
1 parent a9a4b64 commit 57ab969
Show file tree
Hide file tree
Showing 10 changed files with 130 additions and 102 deletions.
7 changes: 7 additions & 0 deletions e2e/nextjs/app-router/app/app/normal/ClientComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@ import {
useVariableValue,
useAllVariables,
useAllFeatures,
renderIfEnabled,
} from '@devcycle/nextjs-sdk'

const ConditionalComponent = renderIfEnabled(
'enabled-feature',
() => import('./ConditionalClientComponent'),
)

export const ClientComponent = () => {
const enabledVar = useVariableValue('enabled-feature', false)
const disabledVar = useVariableValue('disabled-feature', false)
Expand All @@ -18,6 +24,7 @@ export const ClientComponent = () => {
<p>Client Disabled Variable: {JSON.stringify(disabledVar)}</p>
<p>Client All Variables: {JSON.stringify(allVariables)}</p>
<p>Client All Features: {JSON.stringify(allFeatures)}</p>
<ConditionalComponent />
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use client'

export default function ConditionalClientComponent() {
return (
<div>
<h1>Client Component Conditionally Bundled</h1>
</div>
)
}
36 changes: 19 additions & 17 deletions e2e/nextjs/app-router/app/app/normal/devcycle.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import { setupDevCycle } from '@devcycle/nextjs-sdk/server'
import { headers } from 'next/headers'
const { getVariableValue, getClientContext, getAllVariables, getAllFeatures } =
setupDevCycle(
process.env.NEXT_PUBLIC_E2E_NEXTJS_KEY ?? '',
async () => {
const reqHeaders = headers()
return {
user_id: '123',
customData: {
// set a dummy field here so that the headers call stays in the build output
someKey: reqHeaders.get('some-key'),
},
}
},
{ enableStreaming: false },
)

export { getVariableValue, getClientContext, getAllVariables, getAllFeatures }
export const {
getVariableValue,
getClientContext,
getAllVariables,
getAllFeatures,
} = setupDevCycle(
process.env.NEXT_PUBLIC_E2E_NEXTJS_KEY ?? '',
async () => {
const reqHeaders = headers()
return {
user_id: '123',
customData: {
// set a dummy field here so that the headers call stays in the build output
someKey: reqHeaders.get('some-key'),
},
}
},
{ enableStreaming: false },
)
2 changes: 1 addition & 1 deletion e2e/nextjs/app-router/app/app/normal/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ServerComponent } from './ServerComponent'
import React, { Suspense } from 'react'
import Link from 'next/link'

const Home = () => {
const Home = async () => {
return (
<main>
<div>Streaming Disabled</div>
Expand Down
2 changes: 1 addition & 1 deletion e2e/nextjs/app-router/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
},
"dependencies": {
"@devcycle/nextjs-sdk": "file:../../../../dist/sdk/nextjs",
"next": "14.0.5-canary.38",
"next": "14.1.1-canary.7",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
Expand Down
139 changes: 63 additions & 76 deletions e2e/nextjs/app-router/app/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,16 @@ __metadata:
linkType: hard

"@devcycle/nextjs-sdk@file:../../../../dist/sdk/nextjs::locator=app%40workspace%3A.":
version: 0.0.7
resolution: "@devcycle/nextjs-sdk@file:../../../../dist/sdk/nextjs#../../../../dist/sdk/nextjs::hash=804f8c&locator=app%40workspace%3A."
version: 1.0.0
resolution: "@devcycle/nextjs-sdk@file:../../../../dist/sdk/nextjs#../../../../dist/sdk/nextjs::hash=8e3789&locator=app%40workspace%3A."
dependencies:
"@devcycle/bucketing": "npm:^1.7.7"
"@devcycle/js-client-sdk": "npm:^1.16.6"
"@devcycle/react-client-sdk": "npm:^1.14.6"
"@devcycle/types": "npm:^1.4.6"
hoist-non-react-statics: "npm:^3.3.2"
peerDependencies:
next: ">=14.0.0"
react: ^18.2.0
checksum: 0d9e23b033c555a7a77b733fe2512fbeea64828c4c87d7556de337e34d73bbcf56fd87abfcb0c25bbade715d29f9765fa86d64d692aca5ed3d821f14530a051b
server-only: "npm:^0.0.1"
checksum: cb51ef310f1fdf42be3ca85a5e030589064c41b2f7a12ace8d6c959f6ead4bf44abd793cf7f8041481cf690c4f40111469599ab7835d9d35eb62ff3db745fb49
languageName: node
linkType: hard

Expand Down Expand Up @@ -92,72 +90,72 @@ __metadata:
languageName: node
linkType: hard

"@next/env@npm:14.0.5-canary.38":
version: 14.0.5-canary.38
resolution: "@next/env@npm:14.0.5-canary.38"
checksum: 529c6e6ee1981027073854ab4d0d33b0faeaa3c07d2bc27508cdc6d79ccb412422c845bab8865d2c1f8e8a5b6a0c684eb30670b0b8471e8284349d568f91a928
"@next/env@npm:14.1.1-canary.7":
version: 14.1.1-canary.7
resolution: "@next/env@npm:14.1.1-canary.7"
checksum: 495fdab773a22bb7b9409bfd05cd5527c6032a39e086b8054c94e46193ad26ee25f83e990846a2b0b0db23b17ec2d4088dd619b29873b143ba9bfb3d1b30734e
languageName: node
linkType: hard

"@next/swc-darwin-arm64@npm:14.0.5-canary.38":
version: 14.0.5-canary.38
resolution: "@next/swc-darwin-arm64@npm:14.0.5-canary.38"
"@next/swc-darwin-arm64@npm:14.1.1-canary.7":
version: 14.1.1-canary.7
resolution: "@next/swc-darwin-arm64@npm:14.1.1-canary.7"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard

"@next/swc-darwin-x64@npm:14.0.5-canary.38":
version: 14.0.5-canary.38
resolution: "@next/swc-darwin-x64@npm:14.0.5-canary.38"
"@next/swc-darwin-x64@npm:14.1.1-canary.7":
version: 14.1.1-canary.7
resolution: "@next/swc-darwin-x64@npm:14.1.1-canary.7"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard

"@next/swc-linux-arm64-gnu@npm:14.0.5-canary.38":
version: 14.0.5-canary.38
resolution: "@next/swc-linux-arm64-gnu@npm:14.0.5-canary.38"
"@next/swc-linux-arm64-gnu@npm:14.1.1-canary.7":
version: 14.1.1-canary.7
resolution: "@next/swc-linux-arm64-gnu@npm:14.1.1-canary.7"
conditions: os=linux & cpu=arm64 & libc=glibc
languageName: node
linkType: hard

"@next/swc-linux-arm64-musl@npm:14.0.5-canary.38":
version: 14.0.5-canary.38
resolution: "@next/swc-linux-arm64-musl@npm:14.0.5-canary.38"
"@next/swc-linux-arm64-musl@npm:14.1.1-canary.7":
version: 14.1.1-canary.7
resolution: "@next/swc-linux-arm64-musl@npm:14.1.1-canary.7"
conditions: os=linux & cpu=arm64 & libc=musl
languageName: node
linkType: hard

"@next/swc-linux-x64-gnu@npm:14.0.5-canary.38":
version: 14.0.5-canary.38
resolution: "@next/swc-linux-x64-gnu@npm:14.0.5-canary.38"
"@next/swc-linux-x64-gnu@npm:14.1.1-canary.7":
version: 14.1.1-canary.7
resolution: "@next/swc-linux-x64-gnu@npm:14.1.1-canary.7"
conditions: os=linux & cpu=x64 & libc=glibc
languageName: node
linkType: hard

"@next/swc-linux-x64-musl@npm:14.0.5-canary.38":
version: 14.0.5-canary.38
resolution: "@next/swc-linux-x64-musl@npm:14.0.5-canary.38"
"@next/swc-linux-x64-musl@npm:14.1.1-canary.7":
version: 14.1.1-canary.7
resolution: "@next/swc-linux-x64-musl@npm:14.1.1-canary.7"
conditions: os=linux & cpu=x64 & libc=musl
languageName: node
linkType: hard

"@next/swc-win32-arm64-msvc@npm:14.0.5-canary.38":
version: 14.0.5-canary.38
resolution: "@next/swc-win32-arm64-msvc@npm:14.0.5-canary.38"
"@next/swc-win32-arm64-msvc@npm:14.1.1-canary.7":
version: 14.1.1-canary.7
resolution: "@next/swc-win32-arm64-msvc@npm:14.1.1-canary.7"
conditions: os=win32 & cpu=arm64
languageName: node
linkType: hard

"@next/swc-win32-ia32-msvc@npm:14.0.5-canary.38":
version: 14.0.5-canary.38
resolution: "@next/swc-win32-ia32-msvc@npm:14.0.5-canary.38"
"@next/swc-win32-ia32-msvc@npm:14.1.1-canary.7":
version: 14.1.1-canary.7
resolution: "@next/swc-win32-ia32-msvc@npm:14.1.1-canary.7"
conditions: os=win32 & cpu=ia32
languageName: node
linkType: hard

"@next/swc-win32-x64-msvc@npm:14.0.5-canary.38":
version: 14.0.5-canary.38
resolution: "@next/swc-win32-x64-msvc@npm:14.0.5-canary.38"
"@next/swc-win32-x64-msvc@npm:14.1.1-canary.7":
version: 14.1.1-canary.7
resolution: "@next/swc-win32-x64-msvc@npm:14.1.1-canary.7"
conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
Expand Down Expand Up @@ -222,7 +220,7 @@ __metadata:
"@types/node": "npm:^20"
"@types/react": "npm:18.2.20"
"@types/react-dom": "npm:18.2.6"
next: "npm:14.0.5-canary.38"
next: "npm:14.1.1-canary.7"
react: "npm:^18.2.0"
react-dom: "npm:^18.2.0"
typescript: "npm:^5"
Expand Down Expand Up @@ -266,10 +264,10 @@ __metadata:
languageName: node
linkType: hard

"caniuse-lite@npm:^1.0.30001406":
version: 1.0.30001570
resolution: "caniuse-lite@npm:1.0.30001570"
checksum: a9b939e003dd70580cc18bce54627af84f298af7c774415c8d6c99871e7cee13bd8278b67955a979cd338369c73e8821a10b37e607d1fff2fbc8ff92fc489653
"caniuse-lite@npm:^1.0.30001579":
version: 1.0.30001579
resolution: "caniuse-lite@npm:1.0.30001579"
checksum: 2cd0c02e5d66b09888743ad2b624dbde697ace5c76b55bfd6065ea033f6abea8ac3f5d3c9299c042f91b396e2141b49bc61f5e17086dc9ba3a866cc6790134c0
languageName: node
linkType: hard

Expand Down Expand Up @@ -331,14 +329,7 @@ __metadata:
languageName: node
linkType: hard

"glob-to-regexp@npm:^0.4.1":
version: 0.4.1
resolution: "glob-to-regexp@npm:0.4.1"
checksum: 9009529195a955c40d7b9690794aeff5ba665cc38f1519e111c58bb54366fd0c106bde80acf97ba4e533208eb53422c83b136611a54c5fefb1edd8dc267cb62e
languageName: node
linkType: hard

"graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.2.11":
"graceful-fs@npm:^4.2.11":
version: 4.2.11
resolution: "graceful-fs@npm:4.2.11"
checksum: bf152d0ed1dc159239db1ba1f74fdbc40cb02f626770dcd5815c427ce0688c2635a06ed69af364396da4636d0408fcf7d4afdf7881724c3307e46aff30ca49e2
Expand Down Expand Up @@ -432,27 +423,26 @@ __metadata:
languageName: node
linkType: hard

"next@npm:14.0.5-canary.38":
version: 14.0.5-canary.38
resolution: "next@npm:14.0.5-canary.38"
"next@npm:14.1.1-canary.7":
version: 14.1.1-canary.7
resolution: "next@npm:14.1.1-canary.7"
dependencies:
"@next/env": "npm:14.0.5-canary.38"
"@next/swc-darwin-arm64": "npm:14.0.5-canary.38"
"@next/swc-darwin-x64": "npm:14.0.5-canary.38"
"@next/swc-linux-arm64-gnu": "npm:14.0.5-canary.38"
"@next/swc-linux-arm64-musl": "npm:14.0.5-canary.38"
"@next/swc-linux-x64-gnu": "npm:14.0.5-canary.38"
"@next/swc-linux-x64-musl": "npm:14.0.5-canary.38"
"@next/swc-win32-arm64-msvc": "npm:14.0.5-canary.38"
"@next/swc-win32-ia32-msvc": "npm:14.0.5-canary.38"
"@next/swc-win32-x64-msvc": "npm:14.0.5-canary.38"
"@next/env": "npm:14.1.1-canary.7"
"@next/swc-darwin-arm64": "npm:14.1.1-canary.7"
"@next/swc-darwin-x64": "npm:14.1.1-canary.7"
"@next/swc-linux-arm64-gnu": "npm:14.1.1-canary.7"
"@next/swc-linux-arm64-musl": "npm:14.1.1-canary.7"
"@next/swc-linux-x64-gnu": "npm:14.1.1-canary.7"
"@next/swc-linux-x64-musl": "npm:14.1.1-canary.7"
"@next/swc-win32-arm64-msvc": "npm:14.1.1-canary.7"
"@next/swc-win32-ia32-msvc": "npm:14.1.1-canary.7"
"@next/swc-win32-x64-msvc": "npm:14.1.1-canary.7"
"@swc/helpers": "npm:0.5.2"
busboy: "npm:1.6.0"
caniuse-lite: "npm:^1.0.30001406"
caniuse-lite: "npm:^1.0.30001579"
graceful-fs: "npm:^4.2.11"
postcss: "npm:8.4.31"
styled-jsx: "npm:5.1.1"
watchpack: "npm:2.4.0"
peerDependencies:
"@opentelemetry/api": ^1.1.0
react: ^18.2.0
Expand Down Expand Up @@ -484,7 +474,7 @@ __metadata:
optional: true
bin:
next: dist/bin/next
checksum: 3e9e1372aa0f00c5f70d2f45a7c00cf10e69a9e59f8d9677697fe2125c133759a8729c770513da9743c710804d0787d3e649b3e78bcc0e9a6087b2e541bcd987
checksum: b542e2d8cb50ba10e88a9bbc25629f2b6f237254455ae5699136272f32375bbbb28e7f15527a5879b4e46fbebdfef2463529a2e96c9833a3e3fa3201058b9139
languageName: node
linkType: hard

Expand Down Expand Up @@ -564,6 +554,13 @@ __metadata:
languageName: node
linkType: hard

"server-only@npm:^0.0.1":
version: 0.0.1
resolution: "server-only@npm:0.0.1"
checksum: c432348956641ea3f460af8dc3765f3a1bdbcf7a1e0205b0756d868e6e6fe8934cdee6bff68401a1dd49ba4a831c75916517a877446d54b334f7de36fa273e53
languageName: node
linkType: hard

"source-map-js@npm:^1.0.2":
version: 1.0.2
resolution: "source-map-js@npm:1.0.2"
Expand Down Expand Up @@ -650,13 +647,3 @@ __metadata:
checksum: 4bf094641eb71729c06a42d669840e7189597ba655a8264adabac9bf03f95cd6fde5fbc894b0a13ee861bd4a852f56d2afdc9391aeaeb3fc0f9633a974140e12
languageName: node
linkType: hard

"watchpack@npm:2.4.0":
version: 2.4.0
resolution: "watchpack@npm:2.4.0"
dependencies:
glob-to-regexp: "npm:^0.4.1"
graceful-fs: "npm:^4.1.2"
checksum: 4280b45bc4b5d45d5579113f2a4af93b67ae1b9607cc3d86ae41cdd53ead10db5d9dc3237f24256d05ef88b28c69a02712f78e434cb7ecc8edaca134a56e8cab
languageName: node
linkType: hard
4 changes: 4 additions & 0 deletions e2e/nextjs/app-router/tests/app-router.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ test('has expected page elements', async ({ page }) => {
/Client All Features: .*"key":"enabled-feature","type":"permission"/,
),
).toBeVisible()

await expect(
page.getByText('Client Component Conditionally Bundled'),
).toBeVisible()
})

test('works after a client side navigation', async ({ page }) => {
Expand Down
15 changes: 8 additions & 7 deletions sdk/nextjs/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// Use this file to export React client code (e.g. those with 'use client' directive)
// or other non-server utilities
export * from './src/client/useVariableValue'
export * from './src/client/DevCycleClientsideProvider'
export * from './src/common/types'
export * from './src/client/useUserIdentity'
export * from './src/client/useTrack'
export * from './src/client/useAllVariables'
export * from './src/client/useAllFeatures'
export { useVariable, useVariableValue } from './src/client/useVariableValue'
export type * from './src/common/types'
export { useUserIdentity } from './src/client/useUserIdentity'
export { useTrack } from './src/client/useTrack'
export { useAllVariables } from './src/client/useAllVariables'
export { useAllFeatures } from './src/client/useAllFeatures'
export { renderIfEnabled } from './src/client/renderIfEnabled'
export { DevCycleClientsideProvider } from './src/client/DevCycleClientsideProvider'
18 changes: 18 additions & 0 deletions sdk/nextjs/src/client/renderIfEnabled.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { ComponentProps, ComponentType } from 'react'
import dynamic from 'next/dynamic'
import useVariableValue from './useVariableValue'

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const renderIfEnabled = <T extends { default: ComponentType<any> }>(
key: string,
importFunc: () => Promise<T>,
) => {
const Component = dynamic(() => importFunc())
return function (props: ComponentProps<T['default']>) {
const isEnabled = useVariableValue(key, false)
if (isEnabled) {
return <Component {...props} />
}
return null
}
}
File renamed without changes.

2 comments on commit 57ab969

@vercel
Copy link

@vercel vercel bot commented on 57ab969 Jan 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on 57ab969 Jan 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.