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:
@@ -1,4 +1,7 @@
|
|||||||
{
|
{
|
||||||
|
"globals": {
|
||||||
|
"app": false
|
||||||
|
},
|
||||||
"parser": "babel-eslint",
|
"parser": "babel-eslint",
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"react"
|
"react"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"host": "localhost",
|
"host": "localhost",
|
||||||
"port": 3030,
|
"port": 3030,
|
||||||
"protocol": "http",
|
"pathPrefix": "/"
|
||||||
"basePath": "/"
|
|
||||||
}
|
}
|
||||||
@@ -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 />
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
23
src/app.js
23
src/app.js
@@ -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 }))
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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
8
util/pathPrefix.js
Normal 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
|
||||||
@@ -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
8
util/stripPrefix.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
const pathPrefix = require('./pathPrefix')
|
||||||
|
|
||||||
|
module.exports = url => {
|
||||||
|
if (pathPrefix !== '/') {
|
||||||
|
url = url.split(pathPrefix).join('')
|
||||||
|
}
|
||||||
|
return url
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user