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

Commit d390ee5

Browse files
authored
Absolute Routes, Trailing Slash, Route Caching (#33)
* Trailing slash fix * Trailing slash settings * Absolute routes, Route caching
1 parent 6ac52a9 commit d390ee5

File tree

9 files changed

+67
-12
lines changed

9 files changed

+67
-12
lines changed

.npmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}
22
registry=https://registry.npmjs.org/
3-
always-auth=true
3+
always-auth=true

examples/simple/package-lock.json

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/simple/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"license": "ISC",
1313
"dependencies": {
1414
"@trisbee/next-i18n-routes-middleware": "^0.1.6",
15+
"@types/node": "^14.14.2",
1516
"express": "^4.17.1",
1617
"next": "^9.4.4",
1718
"react": "^16.13.1",

examples/simple/server/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// This file doesn't go through babel or webpack transformation.
22
// Make sure the syntax and sources this file requires are compatible with the current node version you are running
33
// See https://github.com/zeit/next.js/issues/1245 for discussions on Universal Webpack or universal Babel
4+
// const getNextI18nRoutesMiddleware = require('../../../index').getNextI18nRoutesMiddleware;
5+
46
const routes = require('./routes').routes;
57
const supportedLangs = require('./routes').supportedLangs;
68
const express = require("express");
@@ -15,4 +17,4 @@ app.prepare().then(() => {
1517
server.use(getNextI18nRoutesMiddleware(server, app, { supportedLangs: supportedLangs, routes: routes, shouldHandleEmptyRoute: true }));
1618

1719
server.listen(process.env.PORT || 3000);
18-
});
20+
});

src/middleware/index.ts

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { getPatternSupportedLangs } from '../utils/lang';
55
import { NextFunction } from 'connect';
66
import { GetNextI18nRoutesMiddleware } from './types';
77

8+
let cashedPaths : {[key: string]: {data: any, template: string}} = {};
9+
810
// 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)
911
const getNextI18nRoutesMiddleware: GetNextI18nRoutesMiddleware = (
1012
server,
@@ -20,20 +22,54 @@ const getNextI18nRoutesMiddleware: GetNextI18nRoutesMiddleware = (
2022
})
2123
}
2224

23-
server.get(`${routePatternSupportedLangs}/*`, (reqEndpoint: Request, resEndpoint: Response) => {
24-
const path = getPath(reqEndpoint.url);
25+
if (settings.trailingSlashRedirect === undefined) settings.trailingSlashRedirect = true;
26+
27+
server.get(`${routePatternSupportedLangs}*`, (reqEndpoint: Request, resEndpoint: Response) => {
28+
29+
const cache = cashedPaths[reqEndpoint.url];
30+
31+
//Checks cache
32+
if (cache) {
33+
return app.render(
34+
reqEndpoint,
35+
resEndpoint,
36+
cache.template,
37+
cache.data
38+
);
39+
}
40+
41+
let path = getPath(reqEndpoint.url);
2542

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

48+
// Strip trailing slash from url
49+
let trailingSlash = false;
50+
if (path.substr(-1) === '/') {
51+
path = path.substring(0, path.length-1)
52+
trailingSlash = true;
53+
}
54+
3155
// Get RouteMatchedObject out of path
3256
const routeMatchedObject = getRouteMatchedObject(settings.routes, path, lang);
57+
58+
// Redirects to url without trailing slash.
59+
if (settings.trailingSlashRedirect && trailingSlash) {
60+
resEndpoint.redirect(301, path);
61+
return;
62+
}
63+
3364
if (!routeMatchedObject) {
3465
return app.render(reqEndpoint, resEndpoint, path, responseQuery);
3566
}
3667

68+
cashedPaths[reqEndpoint.url] = {
69+
template: routeMatchedObject.template,
70+
data: { ...responseQuery, ...routeMatchedObject.params }
71+
}
72+
3773
// Render matched route + add dynamic params to the query object
3874
return app.render(
3975
reqEndpoint,
@@ -45,9 +81,16 @@ const getNextI18nRoutesMiddleware: GetNextI18nRoutesMiddleware = (
4581

4682
const handle = app.getRequestHandler();
4783

48-
server.get("*", (req, res) => {
49-
handle(req, res);
50-
});
84+
//prevents from double getProps calling in devEnviroment
85+
if (process.env.NODE_ENV !== 'production') {
86+
server.get(/^(?:(?!_next\/data).)*$/, (req, res) => {
87+
return handle(req, res);
88+
});
89+
} else {
90+
server.get('*', (req, res) => {
91+
return handle(req, res);
92+
});
93+
}
5194

5295
server.post('*', (req, res) => {
5396
return handle(req, res)
@@ -57,4 +100,4 @@ const getNextI18nRoutesMiddleware: GetNextI18nRoutesMiddleware = (
57100
};
58101
};
59102

60-
export { getNextI18nRoutesMiddleware };
103+
export { getNextI18nRoutesMiddleware };

src/middleware/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Application, RequestHandler } from 'express';
44
interface NextI18nRoutesSettings {
55
supportedLangs: string[],
66
routes: Route[],
7+
trailingSlashRedirect?: boolean,
78
shouldHandleEmptyRoute?: boolean,
89
}
910

@@ -13,4 +14,4 @@ type GetNextI18nRoutesMiddleware = (
1314
settings: NextI18nRoutesSettings
1415
) => RequestHandler;
1516

16-
export { NextI18nRoutesSettings, GetNextI18nRoutesMiddleware }
17+
export { NextI18nRoutesSettings, GetNextI18nRoutesMiddleware }

src/utils/routing/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ const getPath = (url: string): string => {
1515
const getRouteMatchedObject = (routes: Route[], path: string, currentLang: string) => {
1616
// 1) get matched route
1717
const routeMatched = routes.find((route: Route) => {
18+
19+
if (route.id.startsWith('/absoluteRoute:')) return false;
20+
1821
const match = createMatcher(route.aliases[currentLang]);
1922

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

41-
export { getPath, getRouteMatchedObject }
44+
export { getPath, getRouteMatchedObject }

src/utils/routing/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@ interface Route {
1313
type GetPathParsed = (route: Route, path: string, currentLang: string ) => Match<object>
1414
type SliceOutQueryString = (url: string) => string
1515

16-
export { Aliases, Route, GetPathParsed, SliceOutQueryString }
16+
export { Aliases, Route, GetPathParsed, SliceOutQueryString }

src/utils/routing/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@ const sliceOutQueryString: SliceOutQueryString = (url) => {
1717
return url
1818
};
1919

20-
export { getPathParsed, sliceOutQueryString }
20+
export { getPathParsed, sliceOutQueryString }

0 commit comments

Comments
 (0)