A custom Next.JS implementation with some nice extra's
- Next.JS
- Express.JS
- GraphQL
- GraphQL Playground
- JSON Schema
- Simple Node Logger
- Sitemap
Every time you startup a new project you always end up making the same thing because you need them. For example: a sitemap, robots.txt, api endpoints for frontend data, etc.
That's why we took Next.JS as our SSR base and implemented all sorts of useful stuff that you almost need in every project.
Setting up the Core is simple and only requires 2 files, 2 folders and an npm install.
- Run
npm i --save @domparty/nextjs-core react react-dom
inside your project - Create the following folder structure
src/pages
- Create the following file
src/server.js
with the following content:
const App = require('@domparty/nextjs-core');
const core = new App(__dirname, process.cwd());
core.init();
- Create the following file
src/pages/index.js
with the following content:
import React from 'react';
function Home() {
return <div>Hello World!</div>;
}
export default Home;
- Add the following script to your package.json:
"start": "node ./src/server.js"
- Run
npm start
and go tohttp://localhost:5678/
Don't want to set it up yourself? No problem we got you covered. Below is a link to an example project that is ready to go:
https://github.com/domparty/nextjs-core-example
By default we include and expose an application config. Below you will find the default value's for this config:
const baseConfig = {
application: {
name: '',
host: '0.0.0.0',
port: 5678,
dompartyHeaders: true
},
next: {
pagesDir: ""
},
logger: {
location: './log',
filename: 'app.log',
level: 'trace'
},
pwa: {
shortName: 'Project',
name: 'DOMParty Project',
version: 'v0.0.0',
backgroundColor: '#000000',
themeColor: '#000000'
},
cli: {
maxExecutionTimeout: 30,
},
graphql: {
enabled: true
},
robots: {
disallowAll: true,
disallowRules: []
},
sitemap: {
urls: []
}
};
To change or update the config you can do 2 things:
- Include a
config.json
in the following location:$PROJECT_ROOT/config/config.json
- Change the config after the construct of the core:
const core = new App(__dirname, process.cwd());
->console.log(core.config)
After a new
core has been constructed a global variable will be available that contains the logger.
Using the following functions you are able to log messages to the console and log file. Depending on the log level inside the config these messages will be printed to the console.
global.log.trace('');
global.log.debug('');
global.log.info('');
global.log.warn('');
global.log.error('');
global.log.fatal('');
The application default log level is set to trace
.
You can change the log level by adding the following block to your config file:
{
"logger": {
"level": "trace"
}
}
The CLI can be used to run one-time jobs or to implement a cron-job. If the app detects that an extra command line argument is given the CLI mode will be used and search for the task.
node server.js exampleCommand
New CLI tasks can be created in the tasks file that can be found in the root of your project. Below you will find and example tasks.js:
module.exports = {
exampleCommand: (core, args, completed) => {
console.log('Hello World from a task!');
completed();
}
};
To make sure your CLI task won't be running forever we end tasks running longer then 30 seconds by default. This can be changed by changing the config:
{
"cli": {
"maxExecutionTimeout": 30
}
}
The web server running the whole show is Express.JS. This allows for easy extending of custom routes, middlewares and much more.
The complete express instance and http connection are exposed after a core has been constructed and can be accessed like this:
const core = new App(__dirname, process.cwd());
const express = core.server;
const httpSession = core.http;
Some express functions to add middlewares and routes have been replicated to ensure they are pushed in the right place during the initialization. These functions are available:
const core = new App(__dirname, process.cwd());
core.use((req, res, next) => {
console.log('Your middleware here');
next();
});
core.get('/test', (req, res) => {
console.log('Route accessed!');
res.send('Hello');
});
core.post('/test', (req, res) => {
console.log('Route accessed!');
res.send('Hello');
});
core.put('/test', (req, res) => {
console.log('Route accessed!');
res.send('Hello');
});
core.patch('/test', (req, res) => {
console.log('Route accessed!');
res.send('Hello');
});
core.delete('/test', (req, res) => {
console.log('Route accessed!');
res.send('Hello');
});
The Next.JS compiler takes some time to boot up. This is more noticeable in the dev version then the production build. But to ensure that we are not waiting on Next.JS we implemented Instant Listen. This means an alternative page (Loading Page) will be shown until Next.JS is ready to serve pages. No need to reload this loading page since we are checking in the background if Next.JS is ready. After Next.JS is ready we will reload the page for you.
Since we are not waiting on Next.JS this also means that routes for GraphQL and for example the Sitemap are instant ready to go and don't need to wait.
Coming soon...
PWA's are the next generation app replacements. We implemented the 2 required parts in our core to have your app PWA ready.
The manifest is a file used to describe your application and can be updated by changing the config like this:
{
"pwa": {
"shortName": "Project",
"name": "DOMParty Project",
"version": "v0.0.0",
"backgroundColor": "#000000",
"themeColor": "#000000"
}
}
A service worker is a script that your browser runs in the background, separate from a web page, opening the door to features that don't need a web page or user interaction. Today, they already include features like push notifications and background sync. In the future, service workers might support other things like periodic sync or geofencing. The reason this is such an exciting API is that it allows you to support offline experiences, giving developers complete control over the experience.
We opted for a more static version of a service worker. Our service worker runs on /sw.js
and does nothing.
Yeah you head it right nothing. No offline support, no caching, nothing. But why?
Well to get your project ready for the time you are going to implement these things.
Right now we only implemented a simple offline page. That means that when the service worker registers and a user is offline we show a basis you are offline page.
By default we include a robots.txt for search engines to find the sitemap but also to disallow some routes. This can be changed by updating the config. An example config can be found below:
{
"robots": {
"disallowAll": false,
"disallowRules": [
"/fonts",
"/api",
"/some/page/search/engines/dont/need/to/index"
]
}
}
By default we include a sitemap.xml for search engines to index the site. This sitemap can be updated by changing the config. An example can be found here:
{
"sitemap": {
"urls": [
{
"url": "/page/1",
"changefreq": "daily",
"priority": 0.3
},
{
"url": "/page/2",
"changefreq": "daily",
"priority": 0.6
}
]
}
}
Coming soon...
MIT