Skip to main content

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.

/.npmrc
@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
Warning

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:

next.config.js
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:

/src/pages/index.tsx
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.

Warning

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.

Info

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
Info

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.ts and src/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 DrupalView and 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