Skip to content

Commit

Permalink
Chore | Improve gatsby-plugin-nginx configurability (#747)
Browse files Browse the repository at this point in the history
  • Loading branch information
tlgimenes authored Jun 2, 2021
1 parent 6664588 commit 97a7fef
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 14 deletions.
32 changes: 31 additions & 1 deletion packages/gatsby-plugin-nginx/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ module.exports = {
plugins: [
// [...]
{
resolve: require.resolve('@vtex/gatsby-plugin-nginx'),
resolve: '@vtex/gatsby-plugin-nginx',
options: {
transformHeaders: (headers, path) => {
const DEFAULT_SECURITY_HEADERS = [
Expand Down Expand Up @@ -180,3 +180,33 @@ This location finally handles pages with mismatching *path* and *matchPath*.

`createRedirect` with relative paths are not yet implemented.

### Adding custom blocks to nginx config
Our default nginx config may not be suited for all use cases. For those use cases where you need to enable/disable some extra flags in the `server` and `http` block you can use the `serverOptions` and `httpOptions` params respectively.

For instance, say we don't want to use Google's dns server, but use the AWS one instead. One could configure the plugin like:
```js
// gatsby-config.js
module.exports = {
// [...]
plugins: [
// [...]
{
resolve: '@vtex/gatsby-plugin-nginx',
options: {
// other options
serverOptions: [['resolver', '169.254.169.253']],
}
},
],
}
```

This will create an `nginx.conf` file similar to:
```
...
server {
resolver 169.254.169.253;
...
}
...
```
1 change: 1 addition & 0 deletions packages/gatsby-plugin-nginx/src/gatsby-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export const onPostBuild: GatsbyNode['onPostBuild'] = async (
const options = pluginOptions(opt)

const timer = reporter.activityTimer(`write out nginx configuration`)

timer.start()

const { program, pages: pagesMap, redirects } = store.getState() as {
Expand Down
47 changes: 40 additions & 7 deletions packages/gatsby-plugin-nginx/src/nginx-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ function generateNginxConfiguration({
files: string[]
options: PluginOptions
}): string {
const {
disableBrotliEncoding,
writeOnlyLocations,
serverOptions,
httpOptions,
} = options

const filesSet = new Set(files)
const locations = [
...Object.entries(headersMap)
Expand All @@ -40,7 +47,7 @@ function generateNginxConfiguration({
...generateRewrites(rewrites),
]

const brotliConf = options.disableBrotliEncoding
const brotliConf = disableBrotliEncoding
? []
: [
{ cmd: ['brotli', 'on'] },
Expand Down Expand Up @@ -74,7 +81,7 @@ function generateNginxConfiguration({
},
]

const conf = options.writeOnlyLocations
const conf = writeOnlyLocations
? locations
: [
{ cmd: ['worker_processes', '3'] },
Expand All @@ -88,6 +95,7 @@ function generateNginxConfiguration({
{
cmd: ['http'],
children: [
...httpOptions.map((cmd) => ({ cmd })),
// $use_url_tmp = $host OR $http_origin
{
cmd: ['map', '$host', '$use_url_tmp'],
Expand Down Expand Up @@ -149,9 +157,8 @@ function generateNginxConfiguration({
{
cmd: ['server'],
children: [
...serverOptions.map((cmd) => ({ cmd })),
{ cmd: ['listen', '0.0.0.0:$PORT', 'default_server'] },
{ cmd: ['resolver', '8.8.8.8'] },

// https://www.gatsbyjs.com/docs/how-to/adding-common-features/add-404-page/
{ cmd: ['error_page', '404', '/404.html'] },

Expand Down Expand Up @@ -185,16 +192,42 @@ function stringify(directives: NginxDirective[]): string {
.join('\n')
}

const wildcard = /\*/g
const namedSegment = /:[^/]+/g

// Converts a gatsby path to nginx location path
// Ex:
// '/:p1/:p2/foo/*' => '^/([^/]+)/([^/]+)/foo/(.*)$'
// '/:splat' => '^/([^/]+)$'
// '/foo/bar/:splat' => '^/foo/bar/([^/]+)$'
export function convertToRegExp(path: string) {
return `^${path.replace(/\*/g, '(.*)').replace(/:slug/g, '[^/]+')}$`
const converted = path
.replace(wildcard, '(.*)') // replace * with (.*)
.replace(namedSegment, '([^/]+)') // replace :param like with url component like regex ([^/]+)

return `^${converted}$`
}

function isRegExpMatch(path: string) {
return /\*/g.test(path) || /:slug/g.test(path)
return wildcard.test(path) || namedSegment.test(path)
}

// Converts a gatsby path to nginx proxy_pass path
// Ex:
// '/:p1/:p2/foo/*' => /$1/$2/foo/$3
// '/:splat' => '/$1'
// '/foo/bar/:splat' => '/foo/bar/$1'
function convertToPath(path: string) {
return path.replace(/:splat/g, '$1')
let it = 0

return path.replace(
new RegExp(`${wildcard.source}|${namedSegment.source}`, 'g'),
() => {
it += 1

return `$${it}`
}
)
}

function parseRewrite({
Expand Down
4 changes: 4 additions & 0 deletions packages/gatsby-plugin-nginx/src/pluginOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const defaultOptions: PluginOptions = {
disableBrotliEncoding: false,
serveFileDirective: ['try_files', '/$file', '=404'],
plugins: [],
httpOptions: [['proxy_http_version', '1.1']],
serverOptions: [['resolver', '8.8.8.8']],
}

export function pluginOptions(options: Partial<PluginOptions>): PluginOptions {
Expand All @@ -33,6 +35,8 @@ export function pluginOptions(options: Partial<PluginOptions>): PluginOptions {
options.serveFileDirective ??
defaultOptions.serveFileDirective,
plugins: options.plugins ?? defaultOptions.plugins,
httpOptions: options.httpOptions ?? defaultOptions.httpOptions,
serverOptions: options.serverOptions ?? defaultOptions.serverOptions,
}
}

Expand Down
21 changes: 21 additions & 0 deletions packages/gatsby-plugin-nginx/src/typings/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { NginxDirective } from './../../dist/nginx-generator.d'
import {
PageProps,
Actions,
Expand Down Expand Up @@ -53,5 +54,25 @@ declare global {
* @default false
*/
disableBrotliEncoding: boolean
/**
* Add attributes to nginx's server block options
*
* @example
* // Add Google dns server
* serverOptions: [['resolver', '8.8.8.8']]
*
* @default [['resolver', '8.8.8.8']]
*/
serverOptions: string[][]
/**
* Add attributes to nginx's http block options
*
* @example
* // Disable merge_slashes nginx config
* httpOptions: [['merge_slashes', 'off']]
*
* * @default [['proxy_http_version', '1.1']]
*/
httpOptions: string[][]
}
}
31 changes: 25 additions & 6 deletions packages/gatsby-plugin-nginx/test/nginx-generator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,15 @@ describe('stringify', () => {

describe('convert Gatsby paths into nginx RegExp', () => {
it('handles :slug', () => {
expect(convertToRegExp('/:slug/p')).toEqual('^/[^/]+/p$')
expect(convertToRegExp('/:slug')).toEqual('^/[^/]+$')
expect(convertToRegExp('/pt/:slug/p')).toEqual('^/pt/[^/]+/p$')
expect(convertToRegExp('/:slug/p')).toEqual('^/([^/]+)/p$')
expect(convertToRegExp('/:slug')).toEqual('^/([^/]+)$')
expect(convertToRegExp('/pt/:slug/p')).toEqual('^/pt/([^/]+)/p$')
})

it('handles multiple params', () => {
expect(convertToRegExp('/:p1/:p2/p')).toEqual('^/([^/]+)/([^/]+)/p$')
expect(convertToRegExp('/base/:p1/:p2')).toEqual('^/base/([^/]+)/([^/]+)$')
expect(convertToRegExp('/:p1/foo/:p2')).toEqual('^/([^/]+)/foo/([^/]+)$')
})

it('handles wildcard (*)', () => {
Expand Down Expand Up @@ -90,11 +96,11 @@ describe('generateRewrites', () => {
cmd: ['rewrite', '.+', '/__client-side-product__/p'],
},
],
cmd: ['location', '~*', '"^/[^/]+/p$"'],
cmd: ['location', '~*', '"^/([^/]+)/p$"'],
},
{
children: [{ cmd: ['rewrite', '.+', '/pt/__client-side-product__/p'] }],
cmd: ['location', '~*', '"^/pt/[^/]+/p$"'],
cmd: ['location', '~*', '"^/pt/([^/]+)/p$"'],
},
{
children: [{ cmd: ['rewrite', '.+', '/__client-side-search__'] }],
Expand All @@ -104,6 +110,14 @@ describe('generateRewrites', () => {
children: [{ cmd: ['rewrite', '.+', '/pt/__client-side-search__'] }],
cmd: ['location', '~*', '"^/pt/(.*)$"'],
},
{
children: [{ cmd: ['rewrite', '.+', '/foo-path'] }],
cmd: ['location', '~*', '"^/([^/]+)/([^/]+)/foo$"'],
},
{
children: [{ cmd: ['rewrite', '.+', '/bar-path'] }],
cmd: ['location', '~*', '"^/([^/]+)/bar/([^/]+)$"'],
},
]

expect(
Expand All @@ -112,6 +126,8 @@ describe('generateRewrites', () => {
{ fromPath: '/pt/:slug/p', toPath: '/pt/__client-side-product__/p' },
{ fromPath: '/*', toPath: '/__client-side-search__' },
{ fromPath: '/pt/*', toPath: '/pt/__client-side-search__' },
{ fromPath: '/:p1/:p2/foo', toPath: '/foo-path' },
{ fromPath: '/:p1/bar/:p2', toPath: '/bar-path' },
])
).toEqual(expected)
})
Expand Down Expand Up @@ -184,6 +200,8 @@ describe('generateNginxConfiguration', () => {
serveFileDirective: ['try_files', '/$file', '=404'],
transformHeaders: undefined,
writeOnlyLocations: false,
serverOptions: [],
httpOptions: [],
}

expect(
Expand Down Expand Up @@ -230,7 +248,6 @@ describe('generateNginxConfiguration', () => {
gzip_types text/plain text/css text/xml application/javascript application/x-javascript application/xml application/xml+rss application/emacscript application/json image/svg+xml;
server {
listen 0.0.0.0:$PORT default_server;
resolver 8.8.8.8;
error_page 404 /404.html;
location /nginx.conf {
deny all;
Expand Down Expand Up @@ -277,6 +294,8 @@ describe('generateNginxConfiguration', () => {
.filter((h) => !h.includes(`Cache-Control`))
.concat(`Cache-Control: public`),
writeOnlyLocations: false,
serverOptions: [],
httpOptions: [],
}

const start = performance.now()
Expand Down

0 comments on commit 97a7fef

Please sign in to comment.