-
Getting Started
-
Setting up a new project
-
.env
An overview over
next-karma
s use of environment variables.next-karma
makes extensive use of environment variables. A short overview before we dive into specific implementations:Required environment variables for internationalization.
-
NEXT_PUBLIC_ENABLED_LANGUAGES
A list of the currently enabled languages.
- type:
string
- example:
en,de
- type:
-
NEXT_PUBLIC_FALLBACK_LANGUAGE
Should a user with an unknown
Accept-Language
header visit the site, this language will be used as fallback.Must be a part of
NEXT_PUBLIC_ENABLED_LANGUAGES
.- type:
string
- default:
en
- type:
Required environment variables for authentication.
-
NEXT_PUBLIC_ENABLED_PROVIDER
A list of the currently enabled 3rd party provider.
Each provider must also have both
CLIENT_ID
andCLIENT_SECRET
defined.- type:
string
- example:
google,discord
- type:
-
NEXT_PUBLIC_SESSION_LIFETIME
Session lifetime of the httpOnly cookie in seconds.
- type:
number
- default: 28800 (8 hours)
- type:
-
GITHUB_CLIENT_ID
-
GITHUB_CLIENT_SECRET
GitHub App client ID and secret. See
Authentication > GitHub
. -
GOOGLE_CLIENT_ID
-
GOOGLE_CLIENT_SECRET
Google App client ID and secret. See
Authentication > Google
. -
FACEBOOK_CLIENT_ID
-
FACEBOOK_CLIENT_SECRET
Facebook App client ID and secret. See
Authentication > Facebook
. -
DISCORD_CLIENT_ID
-
DISCORD_CLIENT_SECRET
Discord App client ID and secret. See
Authentication > Discord
.
Environment variables for
Sentry
. These will be automatically created by the Vercel Integration.-
NEXT_PUBLIC_SENTRY_DSN
Sentry API endpoint.
-
SENTRY_ORG
The organization this project belongs to.
-
SENTRY_PROJECT
The name of the project within
Sentry
. -
SENTRY_AUTH_TOKEN
Token created by
Sentry
to support sourcemap uploads.
How to set up CI/CD with GitHub
To deploy via GitHub Actions you need the following secrets set in your repository:
CC_TEST_REPORTER_ID
- Login to CodeClimate
- After setting up your repository, go to
Repo Settings
- Select
Test coverage
in the left menu - Copy the
TEST REPORTER ID
VERCEL_TOKEN
- create one here
VERCEL_PROJECT_ID
VERCEL_ORG_ID
GITHUB_TOKEN
- create one here with repository scope
To add a secret, go to your repositories
Settings
tab and then selectSecrets
.VERCEL_PROJECT_ID
andVERCEL_ORG_ID
can be retrieved from your projects.vercel/project.json
file. For that, you will need to globally install the Vercel CLI:npm i -g vercel
After logging in, in your project simply execute
vercel
, it will create the required file (more info here).If you wish to skip any of those steps, edit
.github/workflows/deploy.yml
accordingly. -
-
GitHub Issue Template
next-karma
comes with two templates out of the box:-
Bug Report
Associated label(s):
bug
-
Feature Request
Associated label(s):
enhancement
You may edit them in
.github/ISSUE_TEMPLATE/Bug Fix.md
. -
-
GitHub PR Template
next-karma
comes with one template out of the box:-
Bug Fix
Associated label(s):
bug
You may edit it in
.github/PULL_REQUEST_TEMPLATE/Bug Fix.md
. -
-
Using Sentry
How to set up
Sentry
Sentry
account (register here)- Vercel Integration
next-karma
leverages several ofSentry
s tools:-
preconfigured, global ErrorBoundary in
_app.tsx
via@sentry/react
This global ErrorBoundary is just here for the worst case. You should use some yourself additionally.
Due to
Sentry
being initialized in the UI, any frontend error will be caught, traced and reported. -
next-connect
API route middleware via@sentry/node
When using the included
sentryMiddleware
, API route errors will be caught, traced and reported. -
release management with source map support via
@sentry/webpack-plugin
During build, a separate release visible within the
Sentry
dashboard will be created.
-
-
Authentication
-
Custom Authentication
-
Discord
How to setup OAuth2 with Discord
- Discord Account
- go to https://discord.com/developers/applications
- create a new application
- choose a name
- copy
CLIENT ID
andCLIENT SECRET
into.env
- select the
OAuth2
tab on the left - enter http://localhost:3000/api/v1/auth/discord as well as any staging/production URLs you might need
If you need more profile access than just the basics, read up on how to here.
-
Facebook
How to setup OAuth2 with Facebook
- Facebook Account
- go to https://developers.facebook.com/apps/
- add a new app
- choose a name
- add
Facebook Login
from the list of products - choose
Web
- enter your site url (you may change this later too)
- in the left navigation, go to
Settings > Basic
- copy
App ID
andApp Secret
fields over to the.env
file - in the left navigation, go to
Facebook Login > Settings
- add any staging/production URLs to the field
Valid OAuth Redirect URIs
-
GitHub
How to setup OAuth2 with GitHub
- GitHub Account
- go to https://github.com/settings/developers
- create a
New OAuth App
- copy
Client ID
andClient Secret
over into.env
- set
Authorization callback URL
according to your current environment
GitHub does not allow multiple redirect URLs. For each environment, you will need a separate app.
-
Google
How to setup OAuth2 with Google
- Google Account
- go to https://console.developers.google.com/apis/credentials
- click on
CREATE CREDENTIALS
- select
OAuth client ID
- select
Web Application
asApplication type
-
-
Internationalization
An overview over the
react-i18next
integration withinnext-karma
.i18next is a well established, well maintained internationalization framework.
next-karma
initializes with defaults which you may find inkarma/client/i18n.ts
.Shoutout to UnlyEd & isaachinman
At the time of writing, the commonly used i18n solution for Next.js,
next-i18next
is serverless compatible, but still relies onApp.getInitialProps
which is no longer recommended when using Next.js 9.3+. UnlyEd and their projectnext-right-now
implemented a solution whichnext-karma
draws inspiration from.If you are already familiar with
next-i18next
,next-karma
s solution will feel similar in how to set up.Just like
next-i18next
,next-karma
expects your internationalization data to be stored inpublic/static/locales/$SLUG/$NAMESPACE.json
files.For demonstration purposes,
next-karma
ships with 4 granular namespaces:auth
,i18n
,serviceWorker
andtheme
in both English and German.Namespaces need to be imported defined within
karma/server/i18n/cache.ts
following the existing pattern.Finally, on a per page basis, follow this pattern:
// e.g. /pages/page.tsx import type { WithKarma } from '../karma/client/Karma'; import { KarmaProvider, createGetServerSideProps } from '../karma/client/Karma'; import type { Namespace } from '../karma/server/i18n/cache'; // adjust accordingly export type PageProps = WithKarma; // eslint-disable-next-line import/no-default-export export default function Page({ karma }: PageProps): JSX.Element { return ( <KarmaProvider {...karma}> <h1>next-karma</h1> </KarmaProvider> ); } const i18nNamespaces: Namespace[] = ['serviceWorker', 'theme']; export const getServerSideProps = createGetServerSideProps({ i18nNamespaces });
This ensures only the namespaces you need for this specific site will be loaded in
getServerSideProps
while keeping type-safety.next-karma
will automatically detect the language server-side based on (ordered by priority):- cookies (
react-i18next
sets a cookie to remember the language) - HTTP Accept-Language header through an internal parser to avoid unnecessary dependencies
- dev-defined
FALLBACK_LANGUAGE
(see.env
chapter)
Following the spirit of
@testing-library
s integrative testing approach, all components have access to all languages and namsepaces. This means you can freely change keys in your translation. However, you might have to adjust tests when changing your actual translation as this is a change which affects users.When a user changes the language,
next-karma
will adjust the- html.dir attribute using an allowlist
- html.lang attribute
- cookies (
-
Included Components
next-karma
comes with a few predefined components for you to use. None of them are mandatory. All are tested.-
Core Components
These are components that
next-karma
uses internally. It is recommended to keep them where they are.Location:
/karma/client/components
Used at:
/karma/client/Karma.tsx
-
<MetaThemeColorSynchronizer />
As the name already hints - synchronizes the
<meta name="theme-color" />
tag to the currently active color mode.Dependencies:
@chakra-ui
When to touch:
- when you change the default background colors
More info:
-
<ServiceWorker />
Again, as the name already hints - registers the service worker provided by
next-offline
.Disabled in development! If you run
yarn build
in development, theservice-worker.js
inpublic
will however be registered as the file is now present. Keep an eye out for accidental registrations in dev. This is intentional, as you can test the component in dev this way.Dependencies:
@chakra-ui
i18next
react-i18next
When to touch:
- when you want to add functionality
- when you want to change the internationalization namespace of the service worker (default:
serviceWorker
) - when you don't care about service workers, you can safely delete all references of the component:
- delete usage of component in
src/client/Karma.tsx
- delete
src/client/__tests__/ServiceWorker.test.tsx
- uninstall
next-offline
- remove
next-offline
config innext.config.js
- delete usage of component in
-
-
Other
These are demo components
next-karma
partially uses in the docs. They are also a showcase of@chakra-ui
capabilities. Do with them what you want.Location:
/src/client/components
-
<ColorModeSwitch />
One of two color mode toggles coming with
next-karma
. Changes the color mode on click. Fully accessible.Dependencies:
@chakra-ui
react-i18next
react-icons
-
<ColorModeSwitchAlt />
One of two color mode toggles coming with
next-karma
. Changes the color mode on click. Fully accessible.Dependencies:
@chakra-ui
i18next
react-i18next
react-icons
-
<CustomPWAInstallPrompt />
Very barebones example component on how to integrate a custom PWA install prompt.
Relies on the
beforeinstallprompt
event which is only supported by Chrome and Android WebView!Dependencies:
@chakra-ui
-
<ExternalLink />
Preconfigured component with sane defaults for linking to external sites, built upon
@chakra-ui/Link
.Dependencies:
@chakra-ui
-
<InternalLink />
Preconfigured component for linking internally, built upon
@chakra-ui/Link
andnext/link
.Dependencies:
@chakra-ui
-
<LanguageSwitch />
Menu-based language selection with bundle-loading support.
Dependencies:
@chakra-ui
i18next
react-i18next
react-icons
react-flag-kit
-
<WebShareButton />
Mobile share button using the
navigator.share
API. Only renders wherenavigator.share
is supported.Dependencies:
@chakra-ui
react-icons
-
-
-
-
Guides
-
API routes with next-connect
-
Using custom middlewares
A common requirement for API routes is to protect them from unauthorized access. The authNSecurityMiddleware ensures that only authenticated requests make it through your actual API route and on top decrypts the stored session, exposing it on the request object.
export default nextConnect().use(authNSecurityMiddleware).get(myApiRoute);
To be able to access the manipulated request property in TypeScript, you will need to extend the RequestHandler interface of next-connect. An example can be found in the /pages/api/v1/user/me.ts route.
const SESSION_COOKIE_NAME = "session"; interface AuthenticatedRequest { [SESSION_COOKIE_NAME]: User; } const meHandler: RequestHandler<AuthenticatedRequest> = (req, res) => { return res.json(req[SESSION_COOKIE_NAME]); };
Many requests to the backend have a JSON body which has to be parsed before being able to use it. The expectJSONBodyMiddleware ensures that given a
req.body
, it contains a valid JSON, parses it and overwrites the originalreq.body
. if not, it bails with status code 400 (BAD REQUEST).For further implementation detail, please inspect /karma/server/middlewares/expectJSONBody.ts.
export default nextConnect() .use(expectJSONBodyMiddleware) .post(myRouteExpectingJSON);
The request object supports this out of the box, so this is natively type-safe.
Just like on the frontend, we should know once something goes wrong in the backend. The sentryMiddleware will boot Sentry in an API route, attach metadata such as url, method, host, cookies, query, headers and body.
export default nextConnect() .use(sentryMiddleware) .post(myRouteThatMightError);
-
-
Authentication
- Adding another provider
-
Internationalization
- Adding a language
- Adding a namespace
-
-
Testing
-
Testing Components
next-karma
utilizes jest in combination with @testing-library/react for all component tests.If you are unfamiliar with @testing-library, I'd recommend to familiarize yourself with it first. The basics are easy to pick up.
It is highly recommended to use Testing Playground when writing tests.
next-karma
comes with a predefinedcustom render function
for component tests. Its API extends the regular @testing-libraryrender
function:render(<Component />, options);
It ensures that all tested components are rendered within the following providers:
ChakraProvider
with default themeI18NextProvider
with a static i18next instance with access to every translationAuthContextProvider
which defaults to no session
Some components may receive properties of the result of
useTranslation
via props. To prevent mocking those all the time and having to resort to check for the existence of translation keys, you may use this:render(<Component />, { i18n: { // may also be an array of strings; inherits from useTranslation types namespace: "namespace-to-use", }, });
To rename props you may pass an additional alias object. This will overwrite provided i18n props with the actual props while preserving type-safety.
render( <Component translate={jest.fn()} i18nInstance={jest.fn()} i18nReady={false} />, { i18n: { namespace: "namespace-to-use", alias: { t: "translate", i18n: "i18nInstance", ready: "i18nReady", }, }, } );
Some components may depend on an existing session. To allow those components to properly render in tests, you may pass a
session
torender
. It defaults to null and if given, must match the implementation ofAuthContextDefinition['user']
from theAuthContextProvider
.render(<Component />, { session: mockGithubProfile, });
To easen accessibility testing, a wrapper around jest-axe is included. From the same file where the custom render is defined, simply import
testA11Y
:it("passes a11y test", async () => { await testA11Y(<MyComponent />, options); });
If you need to perform some kind of action, e.g. opening a Menu or Modal before testing for accessibility, you may also pass an element to
testA11Y
:it("passes a11y test when opened", async () => { const { container } = render(<MyComponent />); const button = screen.getByRole("button"); // actually open the menu as other elements are not rendered before userEvent.click(button); await testA11Y(container); });
To disable certain html validation rules, e.g. when unavoidable for reasons beyond your control, you may pass an object
axeOptions
tooptions
, which is a proxy foraxe-core
configuration options.it("passes a11y test", async () => { await testA11Y(<MyComponent />, { axeOptions: { rules: { "image-alt": { enabled: false }, }, }, }); });
To easen HTML validity testing, a wrapper around html-validate is included. From the same file where the custom render is defined, simply import
validateHtml
:it("contains valid html", () => { validateHtml(<MyComponent />, options); });
If you need to perform some kind of action, e.g. opening a Menu or Modal before testing for accessibility, you may also pass an element to
validateHtml
:it("passes a11y test when opened", () => { const { container } = render(<MyComponent />); const button = screen.getByRole("button"); // actually open the menu as other elements are not rendered before userEvent.click(button); validateHtml(container); });
To disable certain html validation rules, e.g. when unavoidable for reasons beyond your control, you may pass an object
htmlValidate
tooptions
, which is a proxy for html-validate options:it("contains valid html", () => { validateHtml(<MyComponent />, { htmlValidate: { rules: { "attribute-boolean-style": "off", }, }, }); });
-
-
Testing API Routes
-
Best Practices
- only type non-primitive types to let inferrence work
- use the included
WithChildren
interface to explicitly typechildren
over the use ofReact.FC
- name component props not just
Props
, but export them and name them like the component, e.g.Button
hasButtonProps
- when using
Sentry
andnext-connect
, always usesentryMiddleware
as first middleware
- avoid naming tests with conjunctives:
- do:
changes theme on click
- don't:
should change theme on click
- do:
- with required props, always import the type/interface of the components props and use it for your default props definition
- always use the custom render function unless no render context needed
- always use the accessibility
testA11Y
function- always name the a11y test
passes a11y test
|...given default props
|...when opened
- always name the a11y test
- always use the html validation
validateHtml
function- always name the html test
contains valid html
|...given default props
|...when opened
- always name the html test
-
Notifications
You must be signed in to change notification settings - Fork 0
ljosberinn/next-karma-docs
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
 |  | |||
Repository files navigation
About
Documentation for next-karma
Resources
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published