Skip to content

Commit

Permalink
feat(module): add option onDecode and onDecodeError (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
ricardogobbosouza authored and manniL committed Mar 14, 2019
1 parent c8d3f8b commit 4000dc7
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 15 deletions.
36 changes: 35 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,26 @@ loss or incorrect handling. But this time is over!
}
```

## Options

### `rules`

- Default: `[]`

Rules of your redirects.

### `onDecode`

- Default: `(req, res, next) => decodeURI(req.url)`

You can set decode.

### `onDecodeError`

- Default: `(error, req, res, next) => next(error)`

You can set callback when there is an error in the decode.

## Usage

Simply add the links you want to redirect as objects to the module option array:
Expand Down Expand Up @@ -100,12 +120,26 @@ redirect: async () => {
}
```

Now, if you want to customize your redirects, how your decode is done
or when there is some error in the decode, you can also:

```js
redirect: {
rules: [
{ from: '^/myoldurl', to: '/mynewurl' }
],
onDecode: (req, res, next) => decodeURI(req.url),
onDecodeError: (error, req, res, next) => next(error)
}
```

**ATTENTION**: The factory function **must** return an array with redirect
objects (as seen above).

## Gotchas

The redirect module will not work in combination with `nuxt generate`. Redirects are realized through a server middleware, which can only react when there is a server running.
The redirect module will not work in combination with `nuxt generate`.
Redirects are realized through a server middleware, which can only react when there is a server running.

## Development

Expand Down
13 changes: 10 additions & 3 deletions lib/middleware.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
// Creates new middleware using provided options
module.exports = function (rules) {
module.exports = function (options) {
return async function redirectRoute(req, res, next) {
const decodedBaseUrl = decodeURI(req.url)
const foundRule = rules.find(o => o.from.test(decodedBaseUrl))
let decodedBaseUrl

try {
decodedBaseUrl = options.onDecode(req, res, next)
} catch (error) {
return options.onDecodeError(error, req, res, next)
}

const foundRule = options.rules.find(o => o.from.test(decodedBaseUrl))

if (!foundRule) {
return next()
Expand Down
32 changes: 23 additions & 9 deletions lib/module.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
async function redirectModule(moduleOptions) {
const options = [
...await parseOptions(moduleOptions),
...await parseOptions(this.options.redirect)
]
const defaults = {
rules: [],
onDecode: (req, res, next) => decodeURI(req.url),
onDecodeError: (error, req, res, next) => next(error)
}

const options = {
...defaults,
...await parseOptions(this.options.redirect),
...await parseOptions(moduleOptions)
}

// Transform each "from" value to a RegExp for later test
const regExpRules = options.map(o => ({ ...o, from: new RegExp(o.from) }))
const middleware = require('./middleware.js')(regExpRules)
options.rules = options.rules.map(rule => ({ ...rule, from: new RegExp(rule.from) }))

const middleware = require('./middleware.js')(options)
this.addServerMiddleware(middleware)
}

Expand All @@ -20,8 +26,16 @@ async function parseOptions(options) {
return []
}

if (!Array.isArray(options)) {
options = [options]
if (Array.isArray(options)) {
return { rules: options }
}

if (typeof options.rules === 'function') {
options.rules = await options.rules()
}

if (options.rules && !Array.isArray(options.rules)) {
options.rules = [options.rules]
}

return options
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"babel-eslint": "latest",
"babel-jest": "latest",
"codecov": "latest",
"consola": "latest",
"eslint": "latest",
"eslint-config-standard": "latest",
"eslint-plugin-import": "latest",
Expand Down
4 changes: 3 additions & 1 deletion test/fixture/nuxt.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@ module.exports = {
modules: [
{ handler: require('../../') }
],
redirect: require('./redirects')
redirect: {
rules: require('./redirects')
}
}
49 changes: 48 additions & 1 deletion test/module.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ jest.setTimeout(60000)
const { Nuxt, Builder } = require('nuxt-edge')
const request = require('request-promise-native')
const getPort = require('get-port')
const consola = require('consola')

const redirects = require('./fixture/redirects')
const config = require('./fixture/nuxt.config')
config.dev = false

let nuxt, port

consola.mockTypes(() => jest.fn())

const url = path => `http://localhost:${port}${path}`
const get = path => request(url(path))

Expand Down Expand Up @@ -103,7 +106,7 @@ describe('function inline', () => {
nuxt = await setupNuxt({
...config,
modules: [
[require('../'), redirects[0]]
[require('../'), redirects]
]
})
})
Expand All @@ -114,3 +117,47 @@ describe('function inline', () => {

testSuite()
})

describe('error', () => {
const e = new Error('Error on decode')

beforeAll(async () => {
nuxt = await setupNuxt({
...config,
redirect: {
rules: async () => {
await Promise.resolve(r => setTimeout(r, 100))
return redirects[0]
},

onDecode: (req) => {
if (req.url === '/error') {
throw e
}
}
}
})
})

beforeEach(() => {
consola.error.mockClear()
})

afterAll(async () => {
await nuxt.close()
})

test('on decode', async () => {
await expect(get('/error')).rejects.toMatchObject({
statusCode: 500
})

expect(consola.error).toHaveBeenCalledWith(e)
})

test('not found', async () => {
await expect(get('/not-found')).rejects.toMatchObject({
statusCode: 404
})
})
})
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2388,6 +2388,11 @@ consola@^2.0.0-1, consola@^2.3.0, consola@^2.4.0:
std-env "^2.2.1"
string-width "^3.0.0"

consola@latest:
version "2.5.6"
resolved "https://registry.yarnpkg.com/consola/-/consola-2.5.6.tgz#5ce14dbaf6f5b589c8a258ef80ed97b752fa57d5"
integrity sha512-DN0j6ewiNWkT09G3ZoyyzN3pSYrjxWcx49+mHu+oDI5dvW5vzmyuzYsqGS79+yQserH9ymJQbGzeqUejfssr8w==

console-browserify@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
Expand Down

0 comments on commit 4000dc7

Please sign in to comment.