CLI: Adding options to serve static files from a folder

This commit is contained in:
Kamil Tunkiewicz 2020-10-16 17:05:14 +02:00
parent f5eeacfd05
commit 91bd11bccb
4 changed files with 55 additions and 5 deletions

View File

@ -18,5 +18,6 @@ Some examples:
- Serve with `nativeScrollbars` option set to true: <br> `$ redoc-cli serve [spec] --options.nativeScrollbars` - Serve with `nativeScrollbars` option set to true: <br> `$ 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): <br> `$ redoc-cli bundle [spec] -t custom.hbs` - Bundle using custom template (check [default template](https://github.com/Redocly/redoc/blob/master/cli/template.hbs) for reference): <br> `$ redoc-cli bundle [spec] -t custom.hbs`
- Bundle using custom template and add custom `templateOptions`: <br> `$ redoc-cli bundle [spec] -t custom.hbs --templateOptions.metaDescription "Page meta description"` - Bundle using custom template and add custom `templateOptions`: <br> `$ 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`. For more details run `redoc-cli --help`.

View File

@ -7,6 +7,7 @@ import { ServerStyleSheet } from 'styled-components';
import { compile } from 'handlebars'; import { compile } from 'handlebars';
import { createServer, IncomingMessage, ServerResponse } from 'http'; import { createServer, IncomingMessage, ServerResponse } from 'http';
import { dirname, join, resolve } from 'path'; import { dirname, join, resolve } from 'path';
import { lookup } from 'mime-types';
import * as zlib from 'zlib'; import * as zlib from 'zlib';
@ -29,6 +30,7 @@ import * as YargsParser from 'yargs';
interface Options { interface Options {
ssr?: boolean; ssr?: boolean;
watch?: boolean; watch?: boolean;
static?: string;
cdn?: boolean; cdn?: boolean;
output?: string; output?: string;
title?: string; title?: string;
@ -72,6 +74,10 @@ YargsParser.command(
type: 'boolean', type: 'boolean',
}); });
yargs.option('static', {
type: 'string',
});
yargs.demandOption('spec'); yargs.demandOption('spec');
return yargs; return yargs;
}, },
@ -80,6 +86,7 @@ YargsParser.command(
ssr: argv.ssr as boolean, ssr: argv.ssr as boolean,
title: argv.title as string, title: argv.title as string,
watch: argv.watch as boolean, watch: argv.watch as boolean,
static: argv.static as string,
templateFileName: argv.template as string, templateFileName: argv.template as string,
templateOptions: argv.templateOptions || {}, templateOptions: argv.templateOptions || {},
redocOptions: getObjectOrJSON(argv.options), redocOptions: getObjectOrJSON(argv.options),
@ -88,7 +95,7 @@ YargsParser.command(
console.log(config); console.log(config);
try { 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) { } catch (e) {
handleError(e); handleError(e);
} }
@ -162,12 +169,19 @@ YargsParser.command(
describe: 'ReDoc options, use dot notation, e.g. options.nativeScrollbars', describe: 'ReDoc options, use dot notation, e.g. options.nativeScrollbars',
}).argv; }).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 spec = await loadAndBundleSpec(pathToSpec);
let pageHTML = await getPageHTML(spec, pathToSpec, options); let pageHTML = await getPageHTML(spec, pathToSpec, options);
const server = createServer((request, response) => { const server = createServer((request, response) => {
console.time('GET ' + request.url); console.time('GET ' + request.url);
const fileNotFound = () => {
response.writeHead(404);
response.write('Not found');
response.end();
};
if (request.url === '/redoc.standalone.js') { if (request.url === '/redoc.standalone.js') {
respondWithGzip( respondWithGzip(
createReadStream(join(BUNDLES_DIR, 'redoc.standalone.js'), 'utf8'), 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', 'Content-Type': 'application/json',
}); });
} else { } else {
response.writeHead(404); if (staticFolder !== '' && request.url.split('/').shift() === staticFolder) {
response.write('Not found'); const filePath = join(dirname(pathToSpec), request.url);
response.end(); 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); console.timeEnd('GET ' + request.url);

18
cli/package-lock.json generated
View File

@ -226,6 +226,11 @@
"handlebars": "*" "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": { "@types/mkdirp": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-1.0.1.tgz", "resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-1.0.1.tgz",
@ -1047,6 +1052,19 @@
"brorand": "^1.0.1" "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": { "minimalistic-assert": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",

View File

@ -11,9 +11,11 @@
"node": ">= 8" "node": ">= 8"
}, },
"dependencies": { "dependencies": {
"@types/mime-types": "^2.1.0",
"chokidar": "^3.4.1", "chokidar": "^3.4.1",
"handlebars": "^4.7.6", "handlebars": "^4.7.6",
"isarray": "^2.0.5", "isarray": "^2.0.5",
"mime-types": "^2.1.27",
"mkdirp": "^1.0.4", "mkdirp": "^1.0.4",
"mobx": "^4.2.0", "mobx": "^4.2.0",
"node-libs-browser": "^2.2.1", "node-libs-browser": "^2.2.1",