Skip to content

Commit

Permalink
enable NextJS experiments (#237)
Browse files Browse the repository at this point in the history
  • Loading branch information
quisido authored Oct 24, 2024
1 parent cb8feac commit 31260aa
Show file tree
Hide file tree
Showing 30 changed files with 277 additions and 170 deletions.
2 changes: 1 addition & 1 deletion packages/authn/src/features/authn-user-id.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { MILLISECONDS_PER_DAY } from '../constants/time.js';
import AuthnTest from '../test/authn-test.js';

const SINGLE = 1;
const TEST_USER_ID = 1234;
const TEST_NOW: number = Date.now();
const TEST_USER_ID = 1234;

describe('getAuthnUserIdFromMemory', (): void => {
it('should clear and emit for expired values', async (): Promise<void> => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import {
AppRouterContext,
type AppRouterInstance,
} from 'next/dist/shared/lib/app-router-context.shared-runtime.js';
import { useContext, type RefObject } from 'react';
import { useContext, type MutableRefObject, type RefObject } from 'react';

interface State {
readonly Consumer: () => null;
readonly appRouter: RefObject<AppRouterInstance | null>;
}

export default function createAppRouterConsumer(): State {
const appRouter: RefObject<AppRouterInstance | null> = {
const appRouter: MutableRefObject<AppRouterInstance | null> = {
current: null,
};

Expand Down
4 changes: 2 additions & 2 deletions packages/mock-next-router/src/test/create-router-consumer.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { RouterContext } from 'next/dist/shared/lib/router-context.shared-runtime.js';
import type { NextRouter } from 'next/router.js';
import { useContext, type RefObject } from 'react';
import { useContext, type MutableRefObject, type RefObject } from 'react';

interface State {
readonly Consumer: () => null;
readonly router: RefObject<NextRouter | null>;
}

export default function createRouterConsumer(): State {
const router: RefObject<NextRouter | null> = {
const router: MutableRefObject<NextRouter | null> = {
current: null,
};

Expand Down
4 changes: 3 additions & 1 deletion packages/next/csp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ connect-src
https://localhost:6586/1/
https://o592283.ingest.sentry.io/api/5740642/envelope/
https://r.logr-ingest.com/i
https://r.lrkt-in.com/i
https://region1.analytics.google.com/g/collect
https://rs.fullstory.com/rec/bundle/v2
https://rs.fullstory.com/rec/page
Expand Down Expand Up @@ -83,6 +84,7 @@ script-src-elem
'unsafe-inline'
https://ajax.cloudflare.com/
https://cdn.logr-ingest.com/logger-1.min.js
https://cdn.lrkt-in.com/logger-1.min.js
https://edge.fullstory.com/s/fs.js
https://quisi.do/cdn-cgi/speculation
https://static.cloudflareinsights.com/
Expand All @@ -92,7 +94,7 @@ script-src-elem

style-src-attr
'unsafe-inline';
S

style-src-elem
'self'
'unsafe-inline'
Expand Down
9 changes: 9 additions & 0 deletions packages/next/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ export default [
},
},

{
files: ['src/modules/react-google-analytics/**/*.ts'],
rules: {
'@typescript-eslint/no-unused-vars': 'off',
camelcase: 'off',
'prefer-rest-params': 'off',
},
},

{
files: ['src/utils/assert.ts'],
rules: {
Expand Down
42 changes: 41 additions & 1 deletion packages/next/next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@ import withNextJsBundleAnalyzer from './src/utils/with-nextjs-bundle-analyzer.js
const cpus: number = getCpus();
const handleDemandEntries = mapNodeEnvToOnDemandEntries(process.env.NODE_ENV);

const OUTPUT: Required<NextConfig>['output'] = mapNodeEnvToOutput(
process.env.NODE_ENV,
);

export default withNextJsBundleAnalyzer({
assetPrefix: '',
basePath: '',
compress: true,
distDir: '.next',
generateBuildId: getVersion,
...optional('onDemandEntries', handleDemandEntries),
output: mapNodeEnvToOutput(process.env.NODE_ENV),
output: OUTPUT,
poweredByHeader: false,
productionBrowserSourceMaps: true,
reactStrictMode: true,
Expand Down Expand Up @@ -57,14 +61,50 @@ export default withNextJsBundleAnalyzer({

experimental: {
cpus,
fullySpecified: true,
memoryBasedWorkersCount: true,
nextScriptWorkers: true,
optimizeCss: true,
optimizeServerReact: true,
ppr: OUTPUT !== 'export',
serverMinification: true,
serverSourceMaps: true,
staticGenerationMaxConcurrency: cpus,
staticGenerationRetryCount: 3,
strictNextHead: true,
swcTraceProfiling: true,
taint: true,
useEarlyImport: true,
useWasmBinary: true,
webVitalsAttribution: ['CLS', 'FCP', 'FID', 'INP', 'LCP', 'TTFB'],
webpackMemoryOptimizations: false,

extensionAlias: {
'.js': ['.ts', '.tsx', '.js', '.jsx'],
'.jsx': ['.tsx', '.jsx'],
},

sri: {
algorithm: 'sha512',
},

turbo: {
treeShaking: true,
},

// Error: Jest worker encountered 1 child process exceptions, exceeding retry limit
parallelServerBuildTraces: false,
parallelServerCompiles: false,
webpackBuildWorker: false,

// DOMException [DataCloneError]: ... could not be cloned.
workerThreads: false,
} satisfies ExperimentalConfig,

sassOptions: {
silenceDeprecations: ['legacy-js-api'],
},

typescript: {
ignoreBuildErrors: true,
tsconfigPath: './tsconfig.prepack.json',
Expand Down
6 changes: 3 additions & 3 deletions packages/next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@
"mixpanel-browser": "^2.55.1",
"next": "15.0.0-canary.199",
"number-format-react": "workspace:^",
"react": "^18.3.1",
"react": "0.0.0-experimental-1631855f-20241023",
"react-datadog": "workspace:^",
"react-dom": "^18.3.1",
"react-dom": "0.0.0-experimental-1631855f-20241023",
"react-innertext": "^1.1.5",
"recharts": "^2.13.0",
"relative-timestamp": "^1.0.0",
Expand Down Expand Up @@ -155,7 +155,7 @@
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-react": "^7.37.1",
"eslint-plugin-react-compiler": "^19.0.0-beta-9ee70a1-20241017",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-hooks": "0.0.0-experimental-1631855f-20241023",
"eslint-plugin-react-refresh": "^0.4.12",
"identity-obj-proxy": "^3.0.0",
"istanbul-lib-coverage": "^3.2.2",
Expand Down
44 changes: 25 additions & 19 deletions packages/next/src/components/log-rocket.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';

import { useEffect, type ReactElement, type ReactNode } from 'react';
import { useEffect } from 'react';
import { GITHUB_SHA } from '../constants/github-sha.js';
import { WHOAMI } from '../constants/whoami.js';
import useLogRocket from '../hooks/use-log-rocket.js';
Expand All @@ -9,7 +9,6 @@ import getHostname from '../utils/get-hostname.js';

interface Props {
readonly appId: string;
readonly children: ReactNode;
}

const BROWSER: Required<Required<LogRocketOptions>['browser']> = {
Expand All @@ -32,6 +31,8 @@ const CONSOLE: Required<Required<LogRocketOptions>['console']> = {
};

const DOM: Required<Omit<Required<LogRocketOptions>['dom'], 'baseHref'>> = {
disablePageTitles: false,
disableWebAnimations: false,
hiddenAttributes: [],
inputSanitizer: false,
isEnabled: true,
Expand Down Expand Up @@ -74,31 +75,36 @@ const NETWORK: Required<Required<LogRocketOptions>['network']> = {
},
};

export default function LogRocket({ appId, children }: Props): ReactElement {
const OPTIONS: Required<Omit<LogRocketOptions, 'rootHostname' | 'serverURL' | 'shouldSendData' | 'uploadTimeInterval'>> = {
browser: BROWSER,
childDomains: [],
console: CONSOLE,
disableBusyFramesTracker: false,
dom: DOM,
mergeIframes: true,
network: NETWORK,
parentDomain: null,
release: GITHUB_SHA ?? 'dev',
shouldAugmentNPS: true,
shouldCaptureIP: true,
shouldDebugLog: false,
shouldDetectExceptions: true,
shouldParseXHRBlob: true,
};

export default function LogRocket({ appId }: Props): null {
const LogRocket = useLogRocket();

useEffect((): void => {
LogRocket.init(appId, {
browser: BROWSER,
childDomains: [],
console: CONSOLE,
disableBusyFramesTracker: false,
mergeIframes: true,
network: NETWORK,
parentDomain: null,
release: GITHUB_SHA ?? 'dev',
...OPTIONS,
rootHostname: getHostname(),
shouldAugmentNPS: true,
shouldCaptureIP: true,
shouldDebugLog: false,
shouldDetectExceptions: true,
shouldParseXHRBlob: true,
dom: {
...DOM,
...OPTIONS.dom,
baseHref: `${window.location.origin}/`,
},
} satisfies Required<Omit<LogRocketOptions, 'serverURL' | 'shouldSendData' | 'uploadTimeInterval'>>);
});
}, [appId, LogRocket]);

return <>{children}</>;
return null;
}
104 changes: 54 additions & 50 deletions packages/next/src/features/datadog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,56 +8,60 @@ const APPLICATION_ID: string = validateString(process.env['DD_APPLICATION_ID']);
const CLIENT_TOKEN: string = validateString(process.env['DD_CLIENT_TOKEN']);
const EXPERIMENTAL_FEATURES: string[] = ['feature_flags'];

export default function Datadog(): null {
useDatadog({
allowFallbackToLocalStorage: true,
allowUntrustedEvents: true,
applicationId: APPLICATION_ID,
clientToken: CLIENT_TOKEN,
compressIntakeRequests: true,
defaultPrivacyLevel: 'mask-user-input',
enabled: true,
enableExperimentalFeatures: EXPERIMENTAL_FEATURES,
env: process.env.NODE_ENV,
service: 'quisi.do',
sessionReplayRecording: true,
sessionReplaySampleRate: 100,
sessionSampleRate: 100,
silentMultipleInit: true,
site: 'datadoghq.com',
storeContextsAcrossPages: true,
startSessionReplayRecordingManually: false,
telemetryConfigurationSampleRate: 100,
telemetrySampleRate: 100,
telemetryUsageSampleRate: 100,
traceContextInjection: 'all',
traceSampleRate: 100,
trackLongTasks: true,
trackResources: true,
trackSessionAcrossSubdomains: true,
trackUserInteractions: true,
trackViewsManually: false,
trackingConsent: 'not-granted',
usePartitionedCrossSiteSessionCookie: true,
useSecureSessionCookie: true,
version: GITHUB_SHA ?? 'unknown',
} satisfies Required<
Omit<
Props,
| 'actionNameAttribute'
| 'allowedTracingUrls'
| 'beforeSend'
| 'datacenter'
| 'excludedActivityUrls'
| 'internalAnalyticsSubdomain'
| 'proxy'
| 'replica'
| 'subdomain'
| 'useCrossSiteSessionCookie'
| 'user'
| 'workerUrl'
>
>);
const PROPS: Required<
Omit<
Props,
| 'actionNameAttribute'
| 'allowedTracingUrls'
| 'beforeSend'
| 'betaPlugins'
| 'datacenter'
| 'excludedActivityUrls'
| 'internalAnalyticsSubdomain'
| 'proxy'
| 'remoteConfigurationId'
| 'replica'
| 'subdomain'
| 'useCrossSiteSessionCookie'
| 'user'
| 'workerUrl'
>
> = {
allowFallbackToLocalStorage: true,
allowUntrustedEvents: true,
applicationId: APPLICATION_ID,
clientToken: CLIENT_TOKEN,
compressIntakeRequests: true,
defaultPrivacyLevel: 'mask-user-input',
enableExperimentalFeatures: EXPERIMENTAL_FEATURES,
enablePrivacyForActionName: true,
enabled: true,
env: process.env.NODE_ENV,
service: 'quisi.do',
sessionReplayRecording: true,
sessionReplaySampleRate: 100,
sessionSampleRate: 100,
silentMultipleInit: true,
site: 'datadoghq.com',
startSessionReplayRecordingManually: false,
storeContextsAcrossPages: true,
telemetryConfigurationSampleRate: 100,
telemetrySampleRate: 100,
telemetryUsageSampleRate: 100,
traceContextInjection: 'all',
traceSampleRate: 100,
trackLongTasks: true,
trackResources: true,
trackSessionAcrossSubdomains: true,
trackUserInteractions: true,
trackViewsManually: false,
trackingConsent: 'not-granted',
usePartitionedCrossSiteSessionCookie: true,
useSecureSessionCookie: true,
version: GITHUB_SHA ?? 'unknown',
};

export default function Datadog(): null {
useDatadog(PROPS);
return null;
}
2 changes: 1 addition & 1 deletion packages/next/src/features/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ const Contexts: ComponentType<PropsWithChildren> = withWrappers(
CloudWatchRUM,
Fullstory,
HostnameProvider,
LogRocket,
NotificationsProvider,
Sentry,
SessionIdProvider,
Expand Down Expand Up @@ -68,6 +67,7 @@ function RootLayout({ children }: Readonly<PropsWithChildren>): ReactElement {
</Contexts>
<Datadog />
<GoogleAnalytics />
<LogRocket />
<Mixpanel />
</body>
</html>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
'use client';

import { usePathname, useRouter } from 'next/navigation.js';
import { useMemo } from 'react';
import { experimental_useEffectEvent as useEffectEvent, useMemo } from 'react';
import { default as Locale, validateLocale } from '../../constants/locale.js';
import useEffectEvent from '../../hooks/use-effect-event.js';
import type Params from './types/params.js';

interface Props {
Expand Down
Loading

0 comments on commit 31260aa

Please sign in to comment.