-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixed the issue with lib dir being ignored.
- Loading branch information
Miloš Brajević
committed
Nov 6, 2019
1 parent
6e256af
commit 1bf9243
Showing
8 changed files
with
288 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -105,4 +105,4 @@ dist | |
|
||
# Build-generated files | ||
es | ||
lib | ||
cjs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,21 @@ | ||
{ | ||
"name": "next-universal-route", | ||
"version": "0.7.0", | ||
"version": "0.7.1", | ||
"description": "Universal Next.js Route", | ||
"main": "./lib/index.js", | ||
"main": "./cjs/index.js", | ||
"module": "./es/index.js", | ||
"modules.root": "./es", | ||
"types": "./lib/index.d.ts", | ||
"types": "./cjs/index.d.ts", | ||
"author": "Miloš Brajević <[email protected]>", | ||
"repository": "brajevicm/next-universal-route", | ||
"license": "MIT", | ||
"scripts": { | ||
"lint": "tslint -c tslint.json --project tsconfig.json", | ||
"test": "jest --config jest.config.json && codecov", | ||
"test:watch": "jest --config jest.config.json --watchAll", | ||
"build": " rimraf ./dist && npm run build:es && npm run build:lib", | ||
"build": " rimraf ./dist && npm run build:es && npm run build:cjs", | ||
"build:es": "tsc --module es2015 --target es5 --outDir es", | ||
"build:lib": "tsc --module commonjs --target es5 --outDir lib" | ||
"build:cjs": "tsc --module commonjs --target es5 --outDir cjs" | ||
}, | ||
"keywords": [ | ||
"react", | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import React, { Children, ReactChildren } from 'react'; | ||
import NextLink from 'next/link'; | ||
|
||
import { NextRoute } from './NextRoute'; | ||
|
||
type LinkProps = { | ||
href: NextRoute | string; | ||
replace?: boolean; | ||
scroll?: boolean; | ||
shallow?: boolean; | ||
passHref?: boolean; | ||
prefetch?: boolean; | ||
children?: ReactChildren; | ||
}; | ||
|
||
export const Link = (props: LinkProps) => { | ||
const { href, ...rest } = props; | ||
const newHref = typeof href === 'string' ? href : href.toHref(); | ||
|
||
if (typeof href === 'string' || href.isAbsolutePath) { | ||
const child: any = Children.only(props.children); | ||
const { children, ...newRest } = rest; | ||
|
||
if (props.passHref || (child.type === 'a' && !('href' in child.props))) { | ||
return React.cloneElement(child, { href: newHref, ...newRest }); | ||
} | ||
|
||
return ( | ||
<a href={newHref} {...newRest}> | ||
{children} | ||
</a> | ||
); | ||
} | ||
|
||
return <NextLink href={href.toHref()} as={href.toAs()} {...rest} />; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { stringify } from 'qs'; | ||
import { generatePath } from '../utils/generatePath'; | ||
import { isAbsolutePath } from '../utils//isAbsolutePath'; | ||
|
||
export class NextRoute { | ||
public path: string; | ||
public page?: string; | ||
public params?: object; | ||
public queryStringParams?: object; | ||
public query?: object; | ||
public isAbsolutePath: boolean; | ||
|
||
constructor( | ||
path: string, | ||
page?: string, | ||
params?: object, | ||
queryStringParams?: object, | ||
query?: object | ||
) { | ||
this.path = path; | ||
this.page = page; | ||
this.params = params; | ||
this.queryStringParams = queryStringParams; | ||
this.query = query; | ||
this.isAbsolutePath = isAbsolutePath(path); | ||
} | ||
|
||
public toAs(): string { | ||
if (this.isAbsolutePath) { | ||
return this.path; | ||
} | ||
|
||
const path = generatePath(this.path, this.params); | ||
const queryString = stringify(this.queryStringParams); | ||
|
||
return queryString ? `${path}?${queryString}` : path; | ||
} | ||
|
||
public toHref(): string { | ||
if (this.isAbsolutePath) { | ||
return this.path; | ||
} | ||
|
||
const queryString = stringify({ | ||
...this.query, | ||
...this.params, | ||
...this.queryStringParams | ||
}); | ||
|
||
return queryString ? `${this.page}?${queryString}` : this.page; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import pathToRegexp from 'path-to-regexp'; | ||
import { parse } from 'url'; | ||
|
||
import { NextRoute } from './NextRoute'; | ||
import { isFunction } from '../utils/isFunction'; | ||
import { mapValues } from '../utils/mapValues'; | ||
import { formatUrl } from '../utils/formatUrl'; | ||
|
||
export class Route { | ||
public path: string; | ||
public page?: string; | ||
private _query: object; | ||
private urlFormatter?: Function; | ||
private params: object; | ||
private queryStringParams: object; | ||
|
||
constructor(path: string, page?: string, urlFormatter?: Function) { | ||
this.path = path; | ||
this.setPage(`/${page}`); | ||
this.urlFormatter = urlFormatter; | ||
this.params = {}; | ||
this.queryStringParams = {}; | ||
} | ||
|
||
get query() { | ||
return { ...this._query, ...this.queryStringParams }; | ||
} | ||
|
||
public generateUrl(params: object = {}, queryStringParams?: object) { | ||
const newParams = this.formatUrl({ ...this.params, ...params }); | ||
const newQueryStringParams = this.formatUrl({ | ||
...this.queryStringParams, | ||
...queryStringParams | ||
}); | ||
|
||
return new NextRoute( | ||
this.path, | ||
this.page, | ||
newParams, | ||
newQueryStringParams, | ||
this._query | ||
); | ||
} | ||
|
||
public generateFromUrl(url: string, params: object): NextRoute { | ||
const { pathname, query } = this.parseUrl(url); | ||
const keys = []; | ||
const regex = pathToRegexp(this.path, keys); | ||
const values = regex.exec(pathname); | ||
|
||
const newParams = this.getQuery(values.slice(1), keys); | ||
const queryStringParams = { | ||
...this.queryStringParams, | ||
...query, | ||
...params | ||
}; | ||
|
||
return this.generateUrl(newParams, queryStringParams); | ||
} | ||
|
||
public isMatch(url: string) { | ||
const { pathname, query } = this.parseUrl(url); | ||
|
||
const keys = []; | ||
const regex = pathToRegexp(this.path, keys); | ||
const isMatch = regex.test(pathname); | ||
|
||
if (isMatch) { | ||
const values = regex.exec(pathname); | ||
|
||
this._query = { | ||
...this._query, | ||
...this.getQuery(values.slice(1), keys) | ||
}; | ||
|
||
this.queryStringParams = query; | ||
} | ||
|
||
return isMatch; | ||
} | ||
|
||
private setPage(url: string): void { | ||
const { pathname, query } = this.parseUrl(url); | ||
|
||
this._query = query; | ||
this.page = pathname; | ||
} | ||
|
||
private formatUrl(params: object): object { | ||
let fn: Function = formatUrl; | ||
|
||
if (isFunction(this.urlFormatter)) { | ||
fn = (string: string) => formatUrl(this.urlFormatter(string)); | ||
} | ||
|
||
return mapValues(params, (param: string | number) => | ||
typeof param === 'string' ? fn(param) : param | ||
); | ||
} | ||
|
||
private getQuery(values, keys) { | ||
return values.reduce((params, val, i) => { | ||
return { | ||
...params, | ||
[keys[i].name]: decodeURIComponent(val) | ||
}; | ||
}, {}); | ||
} | ||
|
||
private parseUrl(url: string) { | ||
const parsedUrl = parse(url, true); | ||
const { pathname, query } = parsedUrl; | ||
|
||
return { | ||
pathname, | ||
query | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import NextRouter, { NextRouter as NextRouterType } from 'next/router'; | ||
|
||
import { Route } from './Route'; | ||
import { NextRoute } from './NextRoute'; | ||
|
||
// import { clone } from './lib/deepClone'; | ||
|
||
// TODO: Find the way to replace Next's Router completely | ||
// const ClonedRouter = ((router: NextRouterType) => { | ||
// const newRouter = clone(router); | ||
|
||
// newRouter.push = (href: NextRoute, options?: object) => | ||
// router.push(href.toHref(), href.toAs(), options); | ||
|
||
// newRouter.prefetch = (href: NextRoute) => router.prefetch(href.toHref()); | ||
|
||
// newRouter.replace = (href: NextRoute, options?: object) => | ||
// router.replace(href.toHref(), href.toAs(), options); | ||
|
||
// return newRouter; | ||
// })(NextRouter); | ||
|
||
export const Router = ((router: NextRouterType) => { | ||
const push = (href: NextRoute, options?: object) => | ||
router.push(href.toHref(), href.toAs(), options); | ||
|
||
const prefetch = (href: NextRoute) => router.prefetch(href.toHref()); | ||
|
||
const replace = (href: NextRoute, options?: object) => | ||
router.replace(href.toHref(), href.toAs(), options); | ||
|
||
const update = (href: Route, params: object) => | ||
push( | ||
href.generateFromUrl( | ||
`${window.location.pathname}${window.location.search}`, | ||
params | ||
) | ||
); | ||
|
||
return { | ||
push, | ||
prefetch, | ||
replace, | ||
update | ||
}; | ||
})(NextRouter); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { Route } from './Route'; | ||
|
||
export class Routes { | ||
private routes: Route[]; | ||
|
||
constructor(routes) { | ||
this.routes = Object.values(routes); | ||
} | ||
|
||
public getRoute(url: string) { | ||
return this.routes.filter(route => route.isMatch(url))[0]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { Routes } from './Routes'; | ||
|
||
export const getRequestHandler = (app, routes) => { | ||
const nextHandler = app.getRequestHandler(); | ||
const router = new Routes(routes); | ||
|
||
return (req, res) => { | ||
const route = router.getRoute(req.url); | ||
|
||
if (route) { | ||
app.render(req, res, route.page, route.query); | ||
} else { | ||
nextHandler(req, res, req.url); | ||
} | ||
}; | ||
}; |