diff --git a/packages/docusaurus-init/templates/bootstrap/package.json b/packages/docusaurus-init/templates/bootstrap/package.json index 1e9bc1f3cd..71c2f90867 100644 --- a/packages/docusaurus-init/templates/bootstrap/package.json +++ b/packages/docusaurus-init/templates/bootstrap/package.json @@ -6,7 +6,8 @@ "start": "docusaurus start", "build": "docusaurus build", "swizzle": "docusaurus swizzle", - "deploy": "docusaurus deploy" + "deploy": "docusaurus deploy", + "serve": "docusaurus serve" }, "dependencies": { "@docusaurus/core": "^2.0.0-alpha.58", diff --git a/packages/docusaurus-init/templates/classic/package.json b/packages/docusaurus-init/templates/classic/package.json index 078cc826ed..1e00fbfa67 100644 --- a/packages/docusaurus-init/templates/classic/package.json +++ b/packages/docusaurus-init/templates/classic/package.json @@ -6,7 +6,8 @@ "start": "docusaurus start", "build": "docusaurus build", "swizzle": "docusaurus swizzle", - "deploy": "docusaurus deploy" + "deploy": "docusaurus deploy", + "serve": "docusaurus serve" }, "dependencies": { "@docusaurus/core": "^2.0.0-alpha.58", diff --git a/packages/docusaurus-init/templates/facebook/package.json b/packages/docusaurus-init/templates/facebook/package.json index 6b6ec0019a..d79d724685 100644 --- a/packages/docusaurus-init/templates/facebook/package.json +++ b/packages/docusaurus-init/templates/facebook/package.json @@ -7,6 +7,7 @@ "build": "docusaurus build", "swizzle": "docusaurus swizzle", "deploy": "docusaurus deploy", + "serve": "docusaurus serve", "ci": "yarn lint && yarn prettier:diff", "lint": "eslint --cache \"**/*.js\" && stylelint \"**/*.css\"", "prettier": "prettier --config .prettierrc --write \"**/*.{js,md}\"", diff --git a/packages/docusaurus/bin/docusaurus.js b/packages/docusaurus/bin/docusaurus.js index 5678d3bc9e..e19917b31c 100755 --- a/packages/docusaurus/bin/docusaurus.js +++ b/packages/docusaurus/bin/docusaurus.js @@ -11,7 +11,14 @@ const chalk = require('chalk'); const semver = require('semver'); const path = require('path'); const cli = require('commander'); -const {build, swizzle, deploy, start, externalCommand} = require('../lib'); +const { + build, + swizzle, + deploy, + start, + externalCommand, + serve, +} = require('../lib'); const requiredVersion = require('../package.json').engines.node; const pkg = require('../package.json'); const updateNotifier = require('update-notifier'); @@ -149,6 +156,35 @@ cli }); }); +cli + .command('serve [siteDir]') + .description('Serve website') + .option( + '--dir ', + 'The full path for the new output directory, relative to the current workspace (default: build).', + ) + .option('-p, --port ', 'use specified port (default: 3000)') + .option('--build', 'Build website before serving (default: false)') + .option('-h, --host ', 'use specified host (default: localhost') + .action( + ( + siteDir = '.', + { + dir = 'build', + port = 3000, + host = 'localhost', + build: buildSite = false, + }, + ) => { + wrapCommand(serve)(path.resolve(siteDir), { + dir, + port, + build: buildSite, + host, + }); + }, + ); + cli.arguments('').action((cmd) => { cli.outputHelp(); console.log(` ${chalk.red(`\n Unknown command ${chalk.yellow(cmd)}.`)}`); diff --git a/packages/docusaurus/package.json b/packages/docusaurus/package.json index e3a6f30a29..bff4fd3c09 100644 --- a/packages/docusaurus/package.json +++ b/packages/docusaurus/package.json @@ -91,6 +91,7 @@ "react-router-config": "^5.1.1", "react-router-dom": "^5.1.2", "semver": "^6.3.0", + "serve-handler": "^6.1.3", "shelljs": "^0.8.4", "std-env": "^2.2.1", "terser-webpack-plugin": "^2.3.5", diff --git a/packages/docusaurus/src/commands/build.ts b/packages/docusaurus/src/commands/build.ts index d1ab306456..a2aeceed00 100644 --- a/packages/docusaurus/src/commands/build.ts +++ b/packages/docusaurus/src/commands/build.ts @@ -128,7 +128,9 @@ export default async function build( console.log( `\n${chalk.green('Success!')} Generated static files in ${chalk.cyan( relativeDir, - )}.\n`, + )}.Use ${chalk.greenBright( + '`npm run serve`', + )} to test your build locally.\n`, ); if (forceTerminate && !cliOptions.bundleAnalyzer) { process.exit(0); diff --git a/packages/docusaurus/src/commands/serve.ts b/packages/docusaurus/src/commands/serve.ts new file mode 100644 index 0000000000..6c6c4ba87a --- /dev/null +++ b/packages/docusaurus/src/commands/serve.ts @@ -0,0 +1,52 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import http from 'http'; +import serveHandler from 'serve-handler'; +import boxen from 'boxen'; +import chalk from 'chalk'; +import path from 'path'; + +import build from './build'; +import choosePort from '../choosePort'; + +export default async function serve( + siteDir: string, + cliOptions: {port: number; build: boolean; dir: string; host: string}, +): Promise { + let dir = path.join(siteDir, cliOptions.dir); + if (cliOptions.build) { + dir = await build( + siteDir, + { + outDir: dir, + }, + false, + ); + } + const port = await choosePort(cliOptions.host, cliOptions.port); + const server = http.createServer((req, res) => { + serveHandler(req, res, { + cleanUrls: true, + public: dir, + }); + }); + console.log( + boxen( + `${chalk.green(`Serving ${cliOptions.dir}!`)}\n\n- Local: http://${ + cliOptions.host + }:${port}`, + { + borderColor: 'green', + padding: 1, + margin: 1, + align: 'center', + }, + ), + ); + server.listen(port); +} diff --git a/packages/docusaurus/src/index.ts b/packages/docusaurus/src/index.ts index f6a0efa902..455d5a42bd 100644 --- a/packages/docusaurus/src/index.ts +++ b/packages/docusaurus/src/index.ts @@ -10,3 +10,4 @@ export {default as start} from './commands/start'; export {default as swizzle} from './commands/swizzle'; export {default as deploy} from './commands/deploy'; export {default as externalCommand} from './commands/external'; +export {default as serve} from './commands/serve'; diff --git a/website/docs/cli.md b/website/docs/cli.md index ec40208547..b72e165bf9 100644 --- a/website/docs/cli.md +++ b/website/docs/cli.md @@ -111,3 +111,14 @@ Deploys your site with [GitHub Pages](https://pages.github.com/). Check out the | --- | --- | --- | | `--out-dir` | `build` | The full path for the new output directory, relative to the current workspace. | | `--skip-build` | `false` | Deploy website without building it. This may be useful when using custom deploy script. | + +### `docusaurus serve` + +Serve your built website localy. + +| Name | Default | Description | +| --- | --- | --- | +| `--port` | `3000` | Use specified port | +| `--dir` | `build` | The full path for the output directory, relative to the current workspace | +| `--build` | `false` | Build website before serving | +| `--host` | `localhost` | Specify a host to use. For example, if you want your server to be accessible externally, you can use `--host 0.0.0.0`. | diff --git a/website/docs/deployment.md b/website/docs/deployment.md index 34ebd739de..bfcdb621dd 100644 --- a/website/docs/deployment.md +++ b/website/docs/deployment.md @@ -13,6 +13,29 @@ Once it finishes, the static files will be generated within the `build/` directo You can deploy your site to static site hosting services such as [Vercel](https://vercel.com/), [GitHub Pages](https://pages.github.com/), [Netlify](https://www.netlify.com/), [Render](https://render.com/static-sites), and [Surge](https://surge.sh/help/getting-started-with-surge). Docusaurus sites are statically rendered so they work without JavaScript too! +## Testing Build Local + +It is important to test build before deploying to a production. Docusaurus includes a [`docusaurus serve`](cli.md#docusaurus-serve) command to test build localy. + +```bash npm2yarn +npm run serve +``` + +## Self Hosting + +:::warning + +It is not the most performant solution + +::: + +Docusaurus can be self hosted using [`docusaurus serve`](cli.md#docusaurus-serve). Change port using `--port` and `--host` to change host. + +```bash npm2yarn +npm run serve --build --port 80 --host 0.0.0.0 + +``` + ## Deploying to GitHub Pages Docusaurus provides an easy way to publish to [GitHub Pages](https://pages.github.com/). Which is hosting that comes for free with every GitHub repository. diff --git a/yarn.lock b/yarn.lock index 3fdec62475..5d68c85670 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16476,7 +16476,7 @@ serialize-javascript@^2.1.2: resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== -serve-handler@6.1.3: +serve-handler@6.1.3, serve-handler@^6.1.3: version "6.1.3" resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.3.tgz#1bf8c5ae138712af55c758477533b9117f6435e8" integrity sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==