From 91bd11bccb8477d3169b26fa68524668b7e18991 Mon Sep 17 00:00:00 2001 From: Kamil Tunkiewicz Date: Fri, 16 Oct 2020 17:05:14 +0200 Subject: [PATCH] CLI: Adding options to serve static files from a folder --- cli/README.md | 1 + cli/index.ts | 39 ++++++++++++++++++++++++++++++++++----- cli/package-lock.json | 18 ++++++++++++++++++ cli/package.json | 2 ++ 4 files changed, 55 insertions(+), 5 deletions(-) diff --git a/cli/README.md b/cli/README.md index 32bb0e0e..82fcd429 100644 --- a/cli/README.md +++ b/cli/README.md @@ -18,5 +18,6 @@ Some examples: - Serve with `nativeScrollbars` option set to true:
`$ redoc-cli serve [spec] --options.nativeScrollbars` - Bundle using custom template (check [default template](https://github.com/Redocly/redoc/blob/master/cli/template.hbs) for reference):
`$ redoc-cli bundle [spec] -t custom.hbs` - Bundle using custom template and add custom `templateOptions`:
`$ redoc-cli bundle [spec] -t custom.hbs --templateOptions.metaDescription "Page meta description"` +- Allow `./resources` folder for be statically served: `$ redoc-cli serve [spec] --static resources` For more details run `redoc-cli --help`. diff --git a/cli/index.ts b/cli/index.ts index 7c836f09..ba766964 100644 --- a/cli/index.ts +++ b/cli/index.ts @@ -7,6 +7,7 @@ import { ServerStyleSheet } from 'styled-components'; import { compile } from 'handlebars'; import { createServer, IncomingMessage, ServerResponse } from 'http'; import { dirname, join, resolve } from 'path'; +import { lookup } from 'mime-types'; import * as zlib from 'zlib'; @@ -29,6 +30,7 @@ import * as YargsParser from 'yargs'; interface Options { ssr?: boolean; watch?: boolean; + static?: string; cdn?: boolean; output?: string; title?: string; @@ -72,6 +74,10 @@ YargsParser.command( type: 'boolean', }); + yargs.option('static', { + type: 'string', + }); + yargs.demandOption('spec'); return yargs; }, @@ -80,6 +86,7 @@ YargsParser.command( ssr: argv.ssr as boolean, title: argv.title as string, watch: argv.watch as boolean, + static: argv.static as string, templateFileName: argv.template as string, templateOptions: argv.templateOptions || {}, redocOptions: getObjectOrJSON(argv.options), @@ -88,7 +95,7 @@ YargsParser.command( console.log(config); try { - await serve(argv.port as number, argv.spec as string, config); + await serve(argv.port as number, argv.spec as string, argv.static as string, config); } catch (e) { handleError(e); } @@ -162,12 +169,19 @@ YargsParser.command( describe: 'ReDoc options, use dot notation, e.g. options.nativeScrollbars', }).argv; -async function serve(port: number, pathToSpec: string, options: Options = {}) { +async function serve(port: number, pathToSpec: string, staticFolder: string, options: Options = {}) { let spec = await loadAndBundleSpec(pathToSpec); let pageHTML = await getPageHTML(spec, pathToSpec, options); const server = createServer((request, response) => { console.time('GET ' + request.url); + + const fileNotFound = () => { + response.writeHead(404); + response.write('Not found'); + response.end(); + }; + if (request.url === '/redoc.standalone.js') { respondWithGzip( createReadStream(join(BUNDLES_DIR, 'redoc.standalone.js'), 'utf8'), @@ -187,9 +201,24 @@ async function serve(port: number, pathToSpec: string, options: Options = {}) { 'Content-Type': 'application/json', }); } else { - response.writeHead(404); - response.write('Not found'); - response.end(); + if (staticFolder !== '' && request.url.split('/').shift() === staticFolder) { + const filePath = join(dirname(pathToSpec), request.url); + const fileExists = existsSync(filePath); + if (fileExists) { + respondWithGzip( + createReadStream(filePath, 'utf8'), + request, + response, + { + 'Content-Type': lookup(filePath), + }, + ); + } else { + fileNotFound(); + } + } else { + fileNotFound(); + } } console.timeEnd('GET ' + request.url); diff --git a/cli/package-lock.json b/cli/package-lock.json index 38ccb979..324663b8 100644 --- a/cli/package-lock.json +++ b/cli/package-lock.json @@ -226,6 +226,11 @@ "handlebars": "*" } }, + "@types/mime-types": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.0.tgz", + "integrity": "sha1-nKUs2jY/aZxpRmwqbM2q2RPqenM=" + }, "@types/mkdirp": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-1.0.1.tgz", @@ -1047,6 +1052,19 @@ "brorand": "^1.0.1" } }, + "mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" + }, + "mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "requires": { + "mime-db": "1.44.0" + } + }, "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", diff --git a/cli/package.json b/cli/package.json index 7cfa547d..ae109174 100644 --- a/cli/package.json +++ b/cli/package.json @@ -11,9 +11,11 @@ "node": ">= 8" }, "dependencies": { + "@types/mime-types": "^2.1.0", "chokidar": "^3.4.1", "handlebars": "^4.7.6", "isarray": "^2.0.5", + "mime-types": "^2.1.27", "mkdirp": "^1.0.4", "mobx": "^4.2.0", "node-libs-browser": "^2.2.1",