Fixed route changes not using getUrl causing invalid url to be used when

using pathPrefix, renamed basePath to prefixPath, updated how getUrl
gets the prefixPath to prevent the need for rebuilding when its changed
now just requires restart
This commit is contained in:
JJ Kasper
2018-06-01 20:56:02 -05:00
parent 017a9993ee
commit e35f6f74eb
12 changed files with 80 additions and 54 deletions

View File

@@ -1,4 +1,7 @@
{ {
"globals": {
"app": false
},
"parser": "babel-eslint", "parser": "babel-eslint",
"plugins": [ "plugins": [
"react" "react"

View File

@@ -49,7 +49,7 @@ host.json
| ---- | ----------- | | ---- | ----------- |
| host | The host to listen on | | host | The host to listen on |
| port | The port to listen on | | port | The port to listen on |
| basePath | Used to prefix all urls for reverse proxies | | prefixPath | Used to prefix all urls for reverse proxies |
production.json (overrides default.json with production NODE_ENV var) production.json (overrides default.json with production NODE_ENV var)
@@ -85,12 +85,6 @@ Lint both
npm lint npm lint
``` ```
## Changelog
__0.1.0__
- Initial release
## License ## License
Copyright (c) 2017 Copyright (c) 2017

View File

@@ -1,6 +1,5 @@
{ {
"host": "localhost", "host": "localhost",
"port": 3030, "port": 3030,
"protocol": "http", "pathPrefix": "/"
"basePath": "/"
} }

View File

@@ -3,7 +3,7 @@ import getUrl from '../util/getUrl'
export default class MyDocument extends Document { export default class MyDocument extends Document {
render() { render() {
const favicon = getUrl('favicon.ico') const favicon = getUrl('favicon.icon')
return ( return (
<html> <html>
<Head> <Head>
@@ -16,6 +16,11 @@ export default class MyDocument extends Document {
<link rel="icon" href={favicon} type="image/x-icon" /> <link rel="icon" href={favicon} type="image/x-icon" />
<link rel="stylesheet" href={getUrl('/_next/static/style.css')} /> <link rel="stylesheet" href={getUrl('/_next/static/style.css')} />
<title>My Knowledge Base</title> <title>My Knowledge Base</title>
<script
dangerouslySetInnerHTML={{
__html: 'window.kbConf=' + JSON.stringify(app.get('kbConf')),
}}
/>
</Head> </Head>
<body> <body>
<Main /> <Main />

View File

@@ -2,12 +2,14 @@ import React, { Component } from 'react'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import Router from 'next/router' import Router from 'next/router'
import Paginate from 'react-paginate' import Paginate from 'react-paginate'
import { format } from 'url'
import Page from '../comps/Page' import Page from '../comps/Page'
import PaddedRow from '../comps/PaddedRow' import PaddedRow from '../comps/PaddedRow'
import Spinner from '../comps/Spinner' import Spinner from '../comps/Spinner'
import DocItem from '../comps/DocItem' import DocItem from '../comps/DocItem'
import { $limit, getDocs, buildQ } from '../util/getDocs' import { $limit, getDocs, buildQ } from '../util/getDocs'
import getJwt from '../util/getJwt' import getJwt from '../util/getJwt'
import getUrl from '../util/getUrl'
import mapUser from '../util/mapUser' import mapUser from '../util/mapUser'
class Index extends Component { class Index extends Component {
@@ -20,6 +22,7 @@ class Index extends Component {
total: 0, total: 0,
docs: [], docs: [],
} }
static async getInitialProps({ req, query }) { static async getInitialProps({ req, query }) {
let page = 1, let page = 1,
$search = '' $search = ''
@@ -33,6 +36,25 @@ class Index extends Component {
const data = await getDocs(q, req ? jwt : false) const data = await getDocs(q, req ? jwt : false)
return { ...data, page, $search } return { ...data, page, $search }
} }
static getDerivedStateFromProps(nextProps, prevState) {
let { docs, total, page, $search } = nextProps
if (
docs.length !== prevState.docs.length ||
page !== prevState.page ||
$search !== prevState.$search
) {
return { total, docs, page, $search, pending: false }
}
return null
}
pushQuery = query =>
Router.push(
{ pathname: '/', query },
format({ pathname: getUrl('/'), query })
)
updDocs = (time, doSearch) => { updDocs = (time, doSearch) => {
clearTimeout(this.docsTime) clearTimeout(this.docsTime)
this.docsTime = setTimeout(async () => { this.docsTime = setTimeout(async () => {
@@ -40,7 +62,7 @@ class Index extends Component {
if (doSearch) { if (doSearch) {
const query = { search: $search } const query = { search: $search }
if (!$search) delete query.search if (!$search) delete query.search
Router.push({ pathname: '/', query }) this.pushQuery(query)
} }
this.setState({ error: null }) this.setState({ error: null })
this.docsTime = setTimeout(() => { this.docsTime = setTimeout(() => {
@@ -53,10 +75,12 @@ class Index extends Component {
this.setState({ ...data, pending: false }) this.setState({ ...data, pending: false })
}, time || 275) }, time || 275)
} }
updQuery = e => { updQuery = e => {
this.setState({ [e.target.id]: e.target.value }) this.setState({ [e.target.id]: e.target.value })
this.updDocs(0, e.target.id === '$search') this.updDocs(0, e.target.id === '$search')
} }
handlePage = ({ selected }) => { handlePage = ({ selected }) => {
const { $search } = this.state const { $search } = this.state
const page = selected + 1 const page = selected + 1
@@ -64,25 +88,16 @@ class Index extends Component {
this.setState({ page }) this.setState({ page })
if (page > 1) query.page = page if (page > 1) query.page = page
if ($search) query.search = $search if ($search) query.search = $search
Router.push({ pathname: '/', query }) this.pushQuery(query)
this.updDocs(1) this.updDocs(1)
} }
static getDerivedStateFromProps(nextProps, prevState) {
let { docs, total, page, $search } = nextProps
if (
docs.length !== prevState.docs.length ||
page !== prevState.page ||
$search !== prevState.$search
) {
return { total, docs, page, $search, pending: false }
}
return null
}
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
const { user, docs } = this.props const { user, docs } = this.props
if (prevProps.user.email === user.email) return if (prevProps.user.email === user.email) return
if (user.email && docs.length === 0) this.updDocs(1) if (user.email && docs.length === 0) this.updDocs(1)
} }
render() { render() {
const { $sort, $search, pending, error, docs, total, page } = this.state const { $sort, $search, pending, error, docs, total, page } = this.state
const pages = Math.ceil(total / $limit) const pages = Math.ceil(total / $limit)

View File

@@ -18,7 +18,7 @@ class k extends Component {
headers: { Authorization: getJwt() }, headers: { Authorization: getJwt() },
method: 'DELETE', method: 'DELETE',
}).catch(({ message }) => ({ ok: false, message })) }).catch(({ message }) => ({ ok: false, message }))
if (del.ok) Router.push('/') if (del.ok) Router.push('/', getUrl('/'))
else { else {
if (!del.message) { if (!del.message) {
const data = await del.json() const data = await del.json()

View File

@@ -21,14 +21,15 @@ const channels = require('./channels')
const authentication = require('./authentication') const authentication = require('./authentication')
const dev = process.env.NODE_ENV !== 'production' const dev = process.env.NODE_ENV !== 'production'
const basePath = require('../util/basePath') const pathPrefix = require('../util/pathPrefix')
const stripBase = require('../util/stripBase') const stripBase = require('../util/stripPrefix')
const getUrl = require('../util/getUrl') const getUrl = require('../util/getUrl')
const { parse } = require('url') const { parse } = require('url')
const nxt = require('next')({ dev, quiet: true }) const nxt = require('next')({ dev, quiet: true })
const nxtHandler = nxt.getRequestHandler() const nxtHandler = nxt.getRequestHandler()
const app = express(feathers()) const app = express(feathers())
global.app = app
app.run = async port => { app.run = async port => {
const server = app.listen(port) const server = app.listen(port)
@@ -36,7 +37,8 @@ app.run = async port => {
if (dev) { if (dev) {
server.on('upgrade', (req, socket) => { server.on('upgrade', (req, socket) => {
nxtHandler(req, socket, parse(stripBase(req.url), true)) req.url = stripBase(req.url)
nxtHandler(req, socket, parse(req.url, true))
}) })
} }
return server return server
@@ -45,10 +47,12 @@ app.run = async port => {
// Load app configuration // Load app configuration
app.configure(configuration()) app.configure(configuration())
// load host config // load host and setup settings
Object.keys(hostConfig).forEach(key => app.set(key, hostConfig[key])) Object.keys(hostConfig).forEach(key => app.set(key, hostConfig[key]))
app.set('kbConf', {
pathPrefix,
})
app.set('didSetup', false) app.set('didSetup', false)
try { try {
fs.statSync(path.join(__dirname, '..', 'db', '.didSetup')) fs.statSync(path.join(__dirname, '..', 'db', '.didSetup'))
app.set('didSetup', true) app.set('didSetup', true)
@@ -88,6 +92,8 @@ app.configure(authentication) // Set up authentication
app.configure(services) // Set up our services (see `services/index.js`) app.configure(services) // Set up our services (see `services/index.js`)
app.configure(channels) // Set up event channels (see channels.js) app.configure(channels) // Set up event channels (see channels.js)
nxt.setAssetPrefix(pathPrefix)
const checkJWT = async (req, res, next) => { const checkJWT = async (req, res, next) => {
const result = await req.app.authenticate('jwt', {})(req) const result = await req.app.authenticate('jwt', {})(req)
if (result.success) { if (result.success) {
@@ -97,7 +103,6 @@ const checkJWT = async (req, res, next) => {
} }
next() next()
} }
nxt.setAssetPrefix(basePath) // setup next.js routes
;['/', '/logout', '/new', '/settings'].forEach(route => { ;['/', '/logout', '/new', '/settings'].forEach(route => {
app.get(getUrl(route), cookieParser, checkJWT, (req, res) => { app.get(getUrl(route), cookieParser, checkJWT, (req, res) => {
const { query } = parse(req.url, true) const { query } = parse(req.url, true)
@@ -115,9 +120,11 @@ app.use((req, res, next) => {
let accept = req.get('accept') let accept = req.get('accept')
if (accept && accept.toLowerCase() === 'application/json') if (accept && accept.toLowerCase() === 'application/json')
return notFound(req, res, next) return notFound(req, res, next)
if (req.url.substr(0, basePath.length) !== basePath) if (req.url.substr(0, pathPrefix.length) !== pathPrefix)
return nxt.render404(req, res) return nxt.render404(req, res)
nxtHandler(req, res, parse(stripBase(req.url), true))
req.url = stripBase(req.url)
nxtHandler(req, res, parse(req.url, true))
}) })
app.use(express.errorHandler({ logger })) app.use(express.errorHandler({ logger }))

View File

@@ -1,8 +0,0 @@
// make sure basePath doesn't end with /
let { basePath } = require('../config/host.json')
const urlChars = basePath.split('')
if (basePath.length > 1 && urlChars.pop() === '/') {
basePath = urlChars.join('')
}
module.exports = basePath

View File

@@ -1,15 +1,18 @@
const url = require('url') const url = require('url')
const urljoin = require('url-join') const urljoin = require('url-join')
const basePath = require('./basePath')
const { host, port, protocol } = require('../config/host.json')
module.exports = (path, absolute) => { module.exports = (path, absolute) => {
path = urljoin(basePath, path) const { pathPrefix } =
typeof window === 'undefined' ? app.get('kbConf') : window.kbConf
path = urljoin(pathPrefix, path)
if (!absolute) return path if (!absolute) return path
// absolute should only be used during ssr
return url.format({ return url.format({
hostname: host, hostname: app.get('host'),
port, port: app.get('port'),
protocol,
pathname: path, pathname: path,
protocol: 'http',
}) })
} }

8
util/pathPrefix.js Normal file
View File

@@ -0,0 +1,8 @@
// make sure basePath doesn't end with /
let { pathPrefix } = require('../config/host.json')
const urlChars = pathPrefix.split('')
if (pathPrefix.length > 1 && urlChars.pop() === '/') {
pathPrefix = urlChars.join('')
}
module.exports = pathPrefix

View File

@@ -1,8 +0,0 @@
const basePath = require('./basePath')
module.exports = url => {
if (basePath !== '/') {
url = url.split(basePath).join('')
}
return url
}

8
util/stripPrefix.js Normal file
View File

@@ -0,0 +1,8 @@
const pathPrefix = require('./pathPrefix')
module.exports = url => {
if (pathPrefix !== '/') {
url = url.split(pathPrefix).join('')
}
return url
}