Test server: https://tapahtumat.test.hel.ninja
Staging server: https://tapahtumat.stage.hel.ninja
Production server: https://tapahtumat.hel.fi (NOTE: this production server might still be deployed from the old Tapahtumat-repo)
This is a Next.js project originally bootstrapped with create-next-app
, but cloned from the Hobbies-Helsinki.
┌─────────────┐ ┌───────────────┐ ┌── Headless CMS (app specific datasource for the dynamic page and articles content)
│ │ supergraph > │ │ subgraphs > ├── Unified-Search (Elasticsearch-service for search results scoring)
│ Application ├───────────────┤ Apollo Router ├─────────────├── Events GraphQL Proxy (A GraphQL-proxy for the LinkedEvents)
│ │ │ │ └── Venues GraphQL Proxy (A GraphQL-proxy for the Palvelukartta/Servicemap / "TPREK" Toimipaikkarekisteri)
└─────────────┘ └───────────────┘
- Test / Staging: https://tapahtumat.app-staging.hkih.hion.dev/graphql (Wordpress-admin)
- Production: https://tapahtumat.content.api.hel.fi/wp-admin/graphql (Wordpress-admin)
The pages are served with some server side rendering (SSR) mechanism to offer better search engine optimization (SEO) and fast user-friendly UI. The pre-rendering process that we mostly use here is SSG - "automatically generated as static HTML + JSON (uses getStaticProps)". The server side rendered pages are under the pages -directory. More about NextJS's data fetching in https://nextjs.org/docs/basic-features/data-fetching/overview.
There are some rules that a content manager must follow while maintaining the CMS:
- / (The root path / the front page): The root path is set as a landing page and it acts as a home page or the front page. The slug for this page must be an empty string, so the uri is
/
in every language. - /search (The search page): The search page gets no content from the CMS, except the SEO information. The uri for this page must be
/search
in every language. It is translated to different languages with the i18nRoutes.config.json configuration file. - /article-archive (The article archive page): The article archive page gets the SEO content from the CMS and also makes some hardcoded article search queries there. The page is mostly rendered with the components that the HCRC-lib offers. The uri must be
/article-archive
in every language. It is translated to different languages with the i18nRoutes.config.json configuration file. - /pages (The root for the dynamic pages): All the dynamic pages must be children of the
/pages
-root-page. This strategy must be followed so that the application can internally handle the dynamic CMS pages. The path is translated to different languages with the i18nRoutes.config.json configuration file.
Run the development server:
yarn dev
# or
docker-compose up
Open http://localhost:3000 with your browser to see the result.
- Run
yarn install
andyarn postinstall
on project root. - Try
git commit -m foo
. It does not commit anything for real but pre-commit hook should be triggered.
Runs the application in development mode. Open http://localhost:3000 to view in the browser.
The page will reload if you make changes.
Builds the production application in the .next
folder.
Production build can be run locally with yarn start
.
Launches the test runner in the interactive watch mode.
Launches the Testcafe test runner for browser tests in the interactive watch mode. yarn test:browser:ci
runs the command line tool without the graphical interface.
Runs the eslinter, a static code analysis tool to flag programming errors, bugs, stylistic errors and suspicious constructs.
Running the yarn lint-fix
also fixes the automatically fixamble issues.
Transpiles the TypeScript code and reports the errors.
Uses the codegen tool to generate Graphql Schema file out from the graphql files inside the app. Note that the graphql.tsx inside the packages/components -directory contains the common types and hooks, so you should always copy the generated result and override the graphql file in the common components-package.
Events uses a lot of the components from the HCRC-lib. For example the article and event carousels are rendered with the HCRC-lib components.
Apollo Link is designed from day one to be easy to use middleware on your requests. Middlewares are used to inspect and modify every request made over the link, for example, adding authentication tokens to every query. In order to add middleware, you simply create a new link and join it with the HttpLink. - https://www.apollographql.com/docs/react/v2/networking/network-layer/#middleware
There are 2 Apollo-clients in implemented: an Apollo-client for Headless CMS
to fetch articles and dynamic pages from the CMS and an Apollo-client for LinkedEvents
to fetch events from the Event-proxy. They both contains URL-fields that are targeted to an external source. Since the content is wanted to be rendered inside the Events app, the URLs needs to be transformed so that they are pointing to an internal path. An Apollo Link is a create place to do the transformation, when the URL context is known. Therefore, the URL should include a hint of the context, e.g a context path like /articles*
or /pages*
or a domain e.g linkedvents.hel.fi
.
The transformation table is in the AppConfig.ts :
class AppConfig {
// ...
static get linkedEventsEventEndpoint() {
return getEnvOrError(
publicRuntimeConfig.linkedEvents,
"LINKEDEVENTS_EVENT_ENDPOINT"
);
}
static get cmsArticlesContextPath() {
return process.env.NEXT_PUBLIC_CMS_ARTICLES_CONTEXT_PATH ?? "/articles";
}
static get cmsPagesContextPath() {
return process.env.NEXT_PUBLIC_CMS_PAGES_CONTEXT_PATH ?? "/pages";
}
static get URLRewriteMapping() {
return {
[AppConfig.linkedEventsEventEndpoint]: ROUTES.EVENTS.replace(
"/[eventId]",
""
),
[`${AppConfig.cmsOrigin}[/fi|/en|/sv]*${AppConfig.cmsArticlesContextPath}`]:
ROUTES.ARTICLES.replace("/[...slug]", ""),
[`${AppConfig.cmsOrigin}[/fi|/en|/sv]*${AppConfig.cmsPagesContextPath}`]:
"/",
};
}
// ...
}
The application configuration is done via the AppConfig.ts as much as possible, so there would be a single point to configure it.
City of Helsinki Slack channel NO CHANNEL YET? (use #hobbieshelsinki)
You can learn more in the NextJs documentation.
To learn React, check out the React documentation.