Migration from peek-alpha
This Guide concentrates on "how to implement @gooddev/peekjs" into existing project with peekjs-alpha versions
The main goal is, to remove all functions and components from project code, which now come from @gooddev/peekjs library.
Where to start?
Add the goodDEV npm registry to the project if not already done
to make npm aware of your custom registry, we need to create a .npmrc file in the root of the project.
@gooddev:registry=https://git.gooddev.de/api/v4/projects/253/packages/npm/
install PeekJS
After successful creation of .npmrc file, you can install the package via:
npm i @gooddev/peekjs@latest
It could be that your project needs to update to specific version (mantine, nextjs). Please update them accordingly to the Versions here listed: Requirements
It is recommended to update via ncu when updating:
ncu -i --format group
or update direcetly with the install or i npm command and the version @latest, e.g.
npm i @gooddev/peekjs@latest next@latest @mantine/core@latest
webpack adjustments
As explained in the Introduction, we need to make webpack accept typescript file loadings, by adding this into next.config.ja:
const nextConfig = {
// --- other configurations
webpack: (config, options) => {
config.resolve.extensions.push('.tsx');
config.resolve.extensions.push('.ts');
config.module.rules.push({
test: /\.(tsx|jsx|ts|js)?$/,
use: [
options.defaultLoaders.babel,
{
loader: 'ts-loader',
options: {
onlyCompileBundledFiles: true,
allowTsInNodeModules: true,
compilerOptions: {
sourceMap: false,
noEmit: false
}
}
}
],
include: [/node_modules\/@gooddev\/peekjs/]
});
return config;
}
// --- other configurations
};
put all code in src
Be sure that every code is inside a src directory, as this makes it easier to search through code-segment in IDE. Only folders which should stay outside are node_modules, .next, public and nginx
basic page rendering implementation
We start by refactor the pages/index.tsx component.
The aim should be, that we have a simple getStaticProps function which, in the end, looks like this:
export async function getStaticProps(context: GetStaticPropsContext) {
const pageProperties = await getDrupalGlobalPageProps({
context,
menues: ['main', 'meta', 'footer'],
blocks: [
{
blockJsonApiResourceName: 'block_content--contact_info',
region: 'footer',
filteredByContext: false
}
],
getParams,
resourceEnhancer
});
return await overwritePageProperties(pageProperties, null);
}
Depending on your needs, the properties of the helper-function getDrupalGlobalPageProps will change, e.g. when you do not need blocks, the blocks attribute can completely be removed.
Optional attributes are menues, blocks, getParams, resourceEnhancer and more, for details go to getDrupalGlobalPageProps API specification.
As you can see there, the only mandatory attribute ist context, which means the minimal call of getDrupalGlobalPageProps could look like this:
export async function getStaticProps(context: GetStaticPropsContext) {
const pageProperties = await getDrupalGlobalPageProps({
context
});
return await overwritePageProperties(pageProperties, null);
}
This would give you no menus or anything else you eventually need.
You should not replace the whole code just by copy paste. go through each line of your getStaticProps and check, if there are any project specific code-segments for pulling data into resource, which we probably will move to resourceEnhancer in a moment.
After this first setup, you should be able to get content from drupal when visiting a page.
When you have trouble, you could activate debug as explained here: Debugging
Important function adjustments!
You will need the following functions:
- add resourceEnhancer function to add additional Data to you page-resource, see: resourceEnhancer
- add enrichFieldContent function which is probably used inside resourceEnhancer to add data to paragraphs, see: enrichFieldContent
- add getParams function handles the necessary entity-reference relation includes, needed to get all referenced data from api, see: getParams
Be aware that some function maybe already exists and need only renaming and some adjustments! Like get-params.ts to getParams.ts
Component adjustments
This part is the most time-consuming, as you have to adjust a lot of component import, which are now excluded to @gooddev/peekjs-library. Luckily, some adjustments can be executed via codemod-Scripts.
GridRow
use codemod
npx @gooddev/codemod@latest grid-row .
...and delete this file src/components/elemets/GridRow.tsx.
getDrupalClientForServer / getDrupalClientForClient
(old was getDrupalServer)
use codemod
npx @gooddev/codemod@latest drupal-client .
...and delete this file src/utils/drupal.ts.
PageProperties delete file + replace imports
use codemod
npx @gooddev/codemod@latest page-properties .
after that delete types/PageProperties.ts or types/PageProperties.d.ts.
Webform
- change WebformComponent.tsx to Form.tsx which looks then like something this:
import styled from '@emotion/styled';
import { Webform } from '@gooddev/peekjs';
import React from 'react';
export const Form = ({ webform_id, elements_data }: any) => {
return (
<>
{elements_data && (
<Webform webformId={webform_id} elements={elements_data} />
)}
</>
);
};
- remove complete Webform Component / Directory under
src/components/elemets/Webform* - remove
src/hooks/useWebform.tsandsrc/hooks/useWebformFromDrupal.ts
elements/InlineButton.styles.ts + elements/InlineButton.tsx
replace with InlineButton from working project, e.g. dnr
Body.tsx ==> InlineButton
replace like in other project, e.g. dnr
MantineThemeProvider.tsx replace Pixel Spacings with Rem-Spacings
old example:
breakpoints: {
xs: parseInt(theme?.breakpoints.xs),
sm: parseInt(theme?.breakpoints.sm),
md: parseInt(theme?.breakpoints.md),
lg: parseInt(theme?.breakpoints.lg),
xl: parseInt(theme?.breakpoints.xl)
}
is going to look like this:
breakpoints: {
xs: rem(parseInt(theme?.breakpoints.xs)),
sm: rem(parseInt(theme?.breakpoints.sm)),
md: rem(parseInt(theme?.breakpoints.md)),
lg: rem(parseInt(theme?.breakpoints.lg)),
xl: rem(parseInt(theme?.breakpoints.xl))
}
...same is needed for spacing Mantine-Property.
ListView
- remove ListView imports, instead use
DrupalViewand import it from @gooddev/peekjs - ListViewCounter component (if used inside ListView/DrupalView) is now
DrupalView.CountDisplay
shouldUseMockdata
use codemod
npx @gooddev/codemod@latest use-mockdata .
...also, when shouldUseMockdata(true) change it to shouldUseMockdata({force: true})
after that delete src/utils/shouldUseMockdata.ts.
getGlobalData
remove this function, as this is executed inside of the function getDrupalGlobalPageProps. If you still use it somewhere, rebuild getStaticProps as explained here: 404-Template or Demo-Template
getAssetUrl
remove this function, as this comes from @gooddev/peekjs-library.
formatBytes
remove this function, as this comes from @gooddev/peekjs-library.
adjust 404 and 500 getStaticProps render-Function
should look like this:
export async function getStaticProps(context: GetStaticPropsContext) {
const pageProperties = await getDrupalGlobalPageProps({
resource: { title: 'Nicht gefunden' },
context,
menues: ['main', 'footer'],
isStaticPage: true
});
return await overwritePageProperties(pageProperties, null);
}
adjust Demo getStaticProps render-Function
should look like this:
export async function getStaticProps(context: GetStaticPropsContext) {
const useMockdata = shouldUseMockdata();
const mockData = useMockdata
? (await import('../../mock/data')).default
: undefined;
const pageProperties = await getDrupalGlobalPageProps({
resource: {
title: 'Impressum',
body: mockData?.IMPRINT || []
},
context,
menues: ['main', 'footer'],
isDemoPage: true,
useMockdata,
mockData
});
return await overwritePageProperties(pageProperties, null);
}
Additional components/functions/hooks you can check
- AppProvider.tsx
- maybe over time some more components/functions/hooks are implemented into @gooddev/peekjs-library. You could check all components/functions/hooks here: API
API-Endpoints Adjustments
adjust src/pages/api/views/load.ts
this should be the content of the api endpoint:
import {
FetchViewArgs,
getDrupalClientForServer,
loadDrupalViewData
} from '@gooddev/peekjs';
import { NextApiRequest, NextApiResponse } from 'next';
import { getRelationForView } from '../../../utils/getParams';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
try {
const {
view,
display,
limit,
offset,
exposedFilters,
contextFilters,
locale,
defaultLocale,
sort_by,
sort_order
}: FetchViewArgs = JSON.parse(req.body);
if (!view) throw new Error(`No View Name`);
if (!display) throw new Error(`No Display ID`);
const viewData = await loadDrupalViewData({
drupalServer: getDrupalClientForServer(),
view,
viewRelations: getRelationForView(view, display),
display,
exposedFilters,
contextFilters,
offset,
limit,
locale,
defaultLocale,
sort_by,
sort_order
});
if (viewData?.meta.count > 0) {
res.json(viewData);
} else {
res.json([]);
}
} catch (error) {
console.error(error);
return res.status(400).json((error as Error).message);
}
}
delete src/pages/api/webform/get.ts
delete this file completely if exist.
adjust src/pages/api/webform/submit.ts
import { getDrupalClientForServer, JsonError } from '@gooddev/peekjs';
import { NextApiRequest, NextApiResponse } from 'next';
export default async function handler(
request: NextApiRequest,
response: NextApiResponse
) {
try {
if (request.method === 'POST') {
const url = getDrupalClientForServer().buildUrl('/webform_rest/submit');
let body = request.body;
if (typeof body === 'string') {
body = JSON.parse(body);
}
// Submit to Drupal.
const result = await getDrupalClientForServer().fetch(url.toString(), {
method: 'POST',
withAuth: true,
body: JSON.stringify({
...body
}),
headers: {
'Content-Type': 'application/json'
}
});
const resData = await result.json();
if (!result.ok) {
throw new JsonError({
status: 400,
message: resData.message,
errors: resData.error
});
}
return response.status(200).json(resData);
}
} catch (err) {
if (err instanceof JsonError) {
return response
.status(err.status)
.json({ message: err.message, errors: err.errors });
} else {
console.error(err);
}
}
return response
.status(500)
.json('Something went wrong, please try again later...');
}
external Lib Code-Adjustments
- Mantine Modal https://mantine.dev/changelog/6-0-0/#modal-and-drawer-breaking-changes
- NextJS 13 codemods: https://nextjs.org/docs/pages/building-your-application/upgrading/codemods
- NextJS 13 Image width, height and quality are no more strings, but numbers
- NextJS 13 Image alt is mandatory