Skip to content
This repository has been archived by the owner on Feb 7, 2023. It is now read-only.

Commit

Permalink
Absolute Routes, Trailing Slash, Route Caching (#33)
Browse files Browse the repository at this point in the history
* Trailing slash fix

* Trailing slash settings

* Absolute routes, Route caching
  • Loading branch information
HamAndRock authored Mar 3, 2021
1 parent 6ac52a9 commit d390ee5
Show file tree
Hide file tree
Showing 9 changed files with 67 additions and 12 deletions.
2 changes: 1 addition & 1 deletion .npmrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}
registry=https://registry.npmjs.org/
always-auth=true
always-auth=true
5 changes: 5 additions & 0 deletions examples/simple/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/simple/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"license": "ISC",
"dependencies": {
"@trisbee/next-i18n-routes-middleware": "^0.1.6",
"@types/node": "^14.14.2",
"express": "^4.17.1",
"next": "^9.4.4",
"react": "^16.13.1",
Expand Down
4 changes: 3 additions & 1 deletion examples/simple/server/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// This file doesn't go through babel or webpack transformation.
// Make sure the syntax and sources this file requires are compatible with the current node version you are running
// See https://github.com/zeit/next.js/issues/1245 for discussions on Universal Webpack or universal Babel
// const getNextI18nRoutesMiddleware = require('../../../index').getNextI18nRoutesMiddleware;

const routes = require('./routes').routes;
const supportedLangs = require('./routes').supportedLangs;
const express = require("express");
Expand All @@ -15,4 +17,4 @@ app.prepare().then(() => {
server.use(getNextI18nRoutesMiddleware(server, app, { supportedLangs: supportedLangs, routes: routes, shouldHandleEmptyRoute: true }));

server.listen(process.env.PORT || 3000);
});
});
55 changes: 49 additions & 6 deletions src/middleware/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { getPatternSupportedLangs } from '../utils/lang';
import { NextFunction } from 'connect';
import { GetNextI18nRoutesMiddleware } from './types';

let cashedPaths : {[key: string]: {data: any, template: string}} = {};

// Has to have any - next does not expose type for app (The type is called "Server" but is deeply nested and not exposed to the public)
const getNextI18nRoutesMiddleware: GetNextI18nRoutesMiddleware = (
server,
Expand All @@ -20,20 +22,54 @@ const getNextI18nRoutesMiddleware: GetNextI18nRoutesMiddleware = (
})
}

server.get(`${routePatternSupportedLangs}/*`, (reqEndpoint: Request, resEndpoint: Response) => {
const path = getPath(reqEndpoint.url);
if (settings.trailingSlashRedirect === undefined) settings.trailingSlashRedirect = true;

server.get(`${routePatternSupportedLangs}*`, (reqEndpoint: Request, resEndpoint: Response) => {

const cache = cashedPaths[reqEndpoint.url];

//Checks cache
if (cache) {
return app.render(
reqEndpoint,
resEndpoint,
cache.template,
cache.data
);
}

let path = getPath(reqEndpoint.url);

// Create response query from "lang dynamic parameter" + query string
const lang = reqEndpoint.params.lang;
const query = parse(reqEndpoint.url, true).query;
const responseQuery = {...query, lang};

// Strip trailing slash from url
let trailingSlash = false;
if (path.substr(-1) === '/') {
path = path.substring(0, path.length-1)
trailingSlash = true;
}

// Get RouteMatchedObject out of path
const routeMatchedObject = getRouteMatchedObject(settings.routes, path, lang);

// Redirects to url without trailing slash.
if (settings.trailingSlashRedirect && trailingSlash) {
resEndpoint.redirect(301, path);
return;
}

if (!routeMatchedObject) {
return app.render(reqEndpoint, resEndpoint, path, responseQuery);
}

cashedPaths[reqEndpoint.url] = {
template: routeMatchedObject.template,
data: { ...responseQuery, ...routeMatchedObject.params }
}

// Render matched route + add dynamic params to the query object
return app.render(
reqEndpoint,
Expand All @@ -45,9 +81,16 @@ const getNextI18nRoutesMiddleware: GetNextI18nRoutesMiddleware = (

const handle = app.getRequestHandler();

server.get("*", (req, res) => {
handle(req, res);
});
//prevents from double getProps calling in devEnviroment
if (process.env.NODE_ENV !== 'production') {
server.get(/^(?:(?!_next\/data).)*$/, (req, res) => {
return handle(req, res);
});
} else {
server.get('*', (req, res) => {
return handle(req, res);
});
}

server.post('*', (req, res) => {
return handle(req, res)
Expand All @@ -57,4 +100,4 @@ const getNextI18nRoutesMiddleware: GetNextI18nRoutesMiddleware = (
};
};

export { getNextI18nRoutesMiddleware };
export { getNextI18nRoutesMiddleware };
3 changes: 2 additions & 1 deletion src/middleware/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Application, RequestHandler } from 'express';
interface NextI18nRoutesSettings {
supportedLangs: string[],
routes: Route[],
trailingSlashRedirect?: boolean,
shouldHandleEmptyRoute?: boolean,
}

Expand All @@ -13,4 +14,4 @@ type GetNextI18nRoutesMiddleware = (
settings: NextI18nRoutesSettings
) => RequestHandler;

export { NextI18nRoutesSettings, GetNextI18nRoutesMiddleware }
export { NextI18nRoutesSettings, GetNextI18nRoutesMiddleware }
5 changes: 4 additions & 1 deletion src/utils/routing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ const getPath = (url: string): string => {
const getRouteMatchedObject = (routes: Route[], path: string, currentLang: string) => {
// 1) get matched route
const routeMatched = routes.find((route: Route) => {

if (route.id.startsWith('/absoluteRoute:')) return false;

const match = createMatcher(route.aliases[currentLang]);

return !!match(path);
Expand All @@ -38,4 +41,4 @@ const getRouteMatchedObject = (routes: Route[], path: string, currentLang: strin
};
};

export { getPath, getRouteMatchedObject }
export { getPath, getRouteMatchedObject }
2 changes: 1 addition & 1 deletion src/utils/routing/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ interface Route {
type GetPathParsed = (route: Route, path: string, currentLang: string ) => Match<object>
type SliceOutQueryString = (url: string) => string

export { Aliases, Route, GetPathParsed, SliceOutQueryString }
export { Aliases, Route, GetPathParsed, SliceOutQueryString }
2 changes: 1 addition & 1 deletion src/utils/routing/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ const sliceOutQueryString: SliceOutQueryString = (url) => {
return url
};

export { getPathParsed, sliceOutQueryString }
export { getPathParsed, sliceOutQueryString }

0 comments on commit d390ee5

Please sign in to comment.