From dff806d75ed63825535171579ef5323dbf38152f Mon Sep 17 00:00:00 2001 From: Muhammad Aditya Hilmy Date: Wed, 3 Mar 2021 23:42:58 +0700 Subject: [PATCH 1/6] Use Gatsby dev to proxy dev-server Signed-off-by: James Hadfield --- auspicePaths.js | 49 ++++++++++++++++++++++++++++++++++++ develop.sh | 8 ++++++ package.json | 3 ++- server.js | 48 +---------------------------------- static-site/gatsby-config.js | 14 ++++++++++- 5 files changed, 73 insertions(+), 49 deletions(-) create mode 100644 auspicePaths.js create mode 100755 develop.sh diff --git a/auspicePaths.js b/auspicePaths.js new file mode 100644 index 000000000..0ced1c251 --- /dev/null +++ b/auspicePaths.js @@ -0,0 +1,49 @@ +const sources = require("./src/sources"); + +/* Dataset and narrative paths hit Auspice's entrypoint. + */ +const coreBuilds = [ + "/dengue", + "/ebola", + "/enterovirus", + "/flu", + "/lassa", + "/measles", + "/mers", + "/mumps", + "/ncov", + "/tb", + "/WNV", + "/yellow-fever", + "/zika", + ]; + + const groups = [...sources.keys()].filter((k) => !["core", "staging", "community"].includes(k)); + + const auspicePaths = [ + "/status", + "/status/*", + ...coreBuilds, + ...coreBuilds.map((url) => url + ":*"), + ...coreBuilds.map(url => url + "/*"), + "/narratives", + "/narratives/*", + "/staging", + "/staging/*", + ...groups.map((group) => `/groups/${group}`), + ...groups.map((group) => `/groups/${group}/*`), + + /* Auspice gets specific /community paths so it can show an index of datasets + * and narratives, but Gatsby gets top-level /community. + */ + "/community/:user/:repo", + "/community/:user/:repo/*", + + /* auspice gets /fetch/X URLs which result in loading of dataset accessible at URL X + * note that gatsby will redirect /fetch to the docs page explaining this behavior + */ + "/fetch/*" + ]; + + module.exports = auspicePaths; + \ No newline at end of file diff --git a/develop.sh b/develop.sh new file mode 100755 index 000000000..887ed3881 --- /dev/null +++ b/develop.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +trap 'kill 0' EXIT + +npm run server & +cd static-site && npm run develop + +wait diff --git a/package.json b/package.json index 8568d2472..725bf7d47 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,8 @@ "start": "npm run server", "smoke-test": "NODE_ENV=test ENV=dev jest ./test/smoke-test/auspice_client_requests.test.js", "smoke-test:ci": "start-server-and-test server http://localhost:5000 smoke-test", - "test:ci": "npm run smoke-test:ci" + "test:ci": "npm run smoke-test:ci", + "dev": "./develop.sh" }, "dependencies": { "argparse": "^1.0.10", diff --git a/server.js b/server.js index 8574df258..37286b7be 100644 --- a/server.js +++ b/server.js @@ -8,6 +8,7 @@ const favicon = require('serve-favicon'); const compression = require('compression'); const argparse = require('argparse'); const utils = require("./src/utils"); +const auspicePaths = require('./auspicePaths'); const cors = require('cors'); const production = process.env.NODE_ENV === "production"; @@ -34,7 +35,6 @@ global.verbose = args.verbose; // in them can use utils.verbose() at load time. const auspiceServerHandlers = require("./src/index.js"); const authn = require("./authn"); -const sources = require("./src/sources"); const redirects = require("./redirects"); /* Path helpers for static assets, to make routes more readable. @@ -101,52 +101,6 @@ app.route("/charon/getSourceInfo") app.route("/charon/*") .all((req, res) => res.status(404).end()); - -/* Dataset and narrative paths hit Auspice's entrypoint. - */ -const coreBuilds = [ - "/dengue", - "/ebola", - "/enterovirus", - "/flu", - "/lassa", - "/measles", - "/mers", - "/mumps", - "/ncov", - "/tb", - "/WNV", - "/yellow-fever", - "/zika", -]; - -const groups = [...sources.keys()].filter((k) => !["core", "staging", "community"].includes(k)); - -const auspicePaths = [ - "/status", - "/status/*", - ...coreBuilds, - ...coreBuilds.map((url) => url + ":*"), - ...coreBuilds.map(url => url + "/*"), - "/narratives", - "/narratives/*", - "/staging", - "/staging/*", - ...groups.map((group) => `/groups/${group}`), - ...groups.map((group) => `/groups/${group}/*`), - - /* Auspice gets specific /community paths so it can show an index of datasets - * and narratives, but Gatsby gets top-level /community. - */ - "/community/:user/:repo", - "/community/:user/:repo/*", - - /* auspice gets /fetch/X URLs which result in loading of dataset accessible at URL X - * note that gatsby will redirect /fetch to the docs page explaining this behavior - */ - "/fetch/*" -]; - app.route(auspicePaths).get((req, res) => { utils.verbose(`Sending Auspice entrypoint for ${req.originalUrl}`); res.sendFile(auspiceAssetPath("dist", "index.html"), {headers: {"Cache-Control": "no-cache, no-store, must-revalidate"}}); diff --git a/static-site/gatsby-config.js b/static-site/gatsby-config.js index 6def02804..74796ff77 100644 --- a/static-site/gatsby-config.js +++ b/static-site/gatsby-config.js @@ -1,4 +1,6 @@ +const createProxyMiddleware = require("http-proxy-middleware"); const config = require("./data/SiteConfig"); +const auspicePaths = require("../auspicePaths"); // const pathPrefix = config.pathPrefix === "/" ? "" : config.pathPrefix; @@ -69,5 +71,15 @@ module.exports = { }, "gatsby-plugin-sharp", // "gatsby-plugin-catch-links" // See https://github.com/nextstrain/nextstrain.org/issues/34 - ] + ], + developMiddleware: app => { + ['/charon', '/dist', ...auspicePaths].forEach(path => { + app.use( + path, + createProxyMiddleware({ + target: "http://localhost:5000", + }) + ); + }) + }, }; From 880e686e2c749a148e69dddd79aec8742ac6b8e2 Mon Sep 17 00:00:00 2001 From: James Hadfield Date: Thu, 4 Mar 2021 14:12:01 +1300 Subject: [PATCH 2/6] linting & npm deps --- auspicePaths.js | 87 ++++++++++++++++--------------- static-site/gatsby-config.js | 2 +- static-site/package-lock.json | 96 ++++++++++++++++++++++++++++------- static-site/package.json | 1 + 4 files changed, 123 insertions(+), 63 deletions(-) diff --git a/auspicePaths.js b/auspicePaths.js index 0ced1c251..2c92e5bb6 100644 --- a/auspicePaths.js +++ b/auspicePaths.js @@ -3,47 +3,46 @@ const sources = require("./src/sources"); /* Dataset and narrative paths hit Auspice's entrypoint. */ const coreBuilds = [ - "/dengue", - "/ebola", - "/enterovirus", - "/flu", - "/lassa", - "/measles", - "/mers", - "/mumps", - "/ncov", - "/tb", - "/WNV", - "/yellow-fever", - "/zika", - ]; - - const groups = [...sources.keys()].filter((k) => !["core", "staging", "community"].includes(k)); - - const auspicePaths = [ - "/status", - "/status/*", - ...coreBuilds, - ...coreBuilds.map((url) => url + ":*"), - ...coreBuilds.map(url => url + "/*"), - "/narratives", - "/narratives/*", - "/staging", - "/staging/*", - ...groups.map((group) => `/groups/${group}`), - ...groups.map((group) => `/groups/${group}/*`), - - /* Auspice gets specific /community paths so it can show an index of datasets - * and narratives, but Gatsby gets top-level /community. - */ - "/community/:user/:repo", - "/community/:user/:repo/*", - - /* auspice gets /fetch/X URLs which result in loading of dataset accessible at URL X - * note that gatsby will redirect /fetch to the docs page explaining this behavior - */ - "/fetch/*" - ]; - - module.exports = auspicePaths; - \ No newline at end of file + "/dengue", + "/ebola", + "/enterovirus", + "/flu", + "/lassa", + "/measles", + "/mers", + "/mumps", + "/ncov", + "/tb", + "/WNV", + "/yellow-fever", + "/zika", +]; + +const groups = [...sources.keys()].filter((k) => !["core", "staging", "community"].includes(k)); + +const auspicePaths = [ + "/status", + "/status/*", + ...coreBuilds, + ...coreBuilds.map((url) => url + ":*"), + ...coreBuilds.map(url => url + "/*"), + "/narratives", + "/narratives/*", + "/staging", + "/staging/*", + ...groups.map((group) => `/groups/${group}`), + ...groups.map((group) => `/groups/${group}/*`), + + /* Auspice gets specific /community paths so it can show an index of datasets + * and narratives, but Gatsby gets top-level /community. + */ + "/community/:user/:repo", + "/community/:user/:repo/*", + + /* auspice gets /fetch/X URLs which result in loading of dataset accessible at URL X + * note that gatsby will redirect /fetch to the docs page explaining this behavior + */ + "/fetch/*" +]; + +module.exports = auspicePaths; diff --git a/static-site/gatsby-config.js b/static-site/gatsby-config.js index 74796ff77..aca2ba1b7 100644 --- a/static-site/gatsby-config.js +++ b/static-site/gatsby-config.js @@ -80,6 +80,6 @@ module.exports = { target: "http://localhost:5000", }) ); - }) + }); }, }; diff --git a/static-site/package-lock.json b/static-site/package-lock.json index a9211231b..2c431199e 100644 --- a/static-site/package-lock.json +++ b/static-site/package-lock.json @@ -2174,6 +2174,14 @@ "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.5.tgz", "integrity": "sha512-wLD/Aq2VggCJXSjxEwrMafIP51Z+13H78nXIX0ABEuIGhmB5sNGbR113MOKo+yfw+RDo1ZU3DM6yfnnRF/+ouw==" }, + "@types/http-proxy": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.5.tgz", + "integrity": "sha512-GNkDE7bTv6Sf8JbV2GksknKOsk7OznNYHSdrtvPJXO0qJ9odZig6IZKUi5RFGi6d1bf6dgIAe4uXi3DBc7069Q==", + "requires": { + "@types/node": "*" + } + }, "@types/istanbul-lib-coverage": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", @@ -11405,9 +11413,9 @@ "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=" }, "http-proxy": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz", - "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==", + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "requires": { "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", @@ -11415,21 +11423,67 @@ }, "dependencies": { "eventemitter3": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", - "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==" + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" } } }, "http-proxy-middleware": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", - "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-1.0.6.tgz", + "integrity": "sha512-NyL6ZB6cVni7pl+/IT2W0ni5ME00xR0sN27AQZZrpKn1b+qRh+mLbBxIq9Cq1oGfmTc7BUq4HB77mxwCaxAYNg==", "requires": { - "http-proxy": "^1.17.0", - "is-glob": "^4.0.0", - "lodash": "^4.17.11", - "micromatch": "^3.1.10" + "@types/http-proxy": "^1.17.4", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "lodash": "^4.17.20", + "micromatch": "^4.0.2" + }, + "dependencies": { + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + } } }, "http-signature": { @@ -12792,11 +12846,6 @@ "has-symbols": "^1.0.1" } }, - "is-touch-device": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-touch-device/-/is-touch-device-1.0.1.tgz", - "integrity": "sha512-LAYzo9kMT1b2p19L/1ATGt2XcSilnzNlyvq6c0pbPRVisLbAPpLqr53tIJS00kvrTkj0HtR8U7+u8X0yR8lPSw==" - }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -24767,6 +24816,17 @@ } } }, + "http-proxy-middleware": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", + "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "requires": { + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" + } + }, "is-wsl": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", diff --git a/static-site/package.json b/static-site/package.json index 51447d5f1..a7d10ca8f 100644 --- a/static-site/package.json +++ b/static-site/package.json @@ -53,6 +53,7 @@ "gatsby-remark-smartypants": "^2.1.20", "gatsby-source-filesystem": "^2.1.46", "gatsby-transformer-remark": "^2.6.48", + "http-proxy-middleware": "^1.0.6", "lodash": "^4.17.15", "lodash-webpack-plugin": "^0.11.4", "mapbox-gl": "1.13.0", From f5f67bcee868215fce9a87c26430c877b551a8db Mon Sep 17 00:00:00 2001 From: eharkins Date: Fri, 5 Mar 2021 17:17:41 -0800 Subject: [PATCH 3/6] update READMEs reflecting #280 --- README.md | 6 ++++++ static-site/README.md | 5 +++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 705627fd6..64e860aeb 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,12 @@ from this directory (the "nextstrain.org" directory). 2. `npm run server` will then start a local instance, by default available at [localhost:5000](http://localhost:5000). This should mirror exactly what you see when you visit [nextstrain.org](https://nextstrain.org). +### Build nextstrain.org in development mode +Run `npm run dev` from the root of this repository to launch a development server of nextstrain.org, by default available at [localhost:8000](http://localhost:8000). + +This works by running the main nextstrain server on port 5000 and then running the Gatsby (see below for more on Gatsby) server on port 8000 and directing requests outside of Gatsby to port 5000. +See [nextstrain.org/pull/280](https://github.com/nextstrain/nextstrain.org/pull/280) for more on this. + #### Building with Nextstrain Groups (e.g. "Login") functionality You'll need AWS credentials configured (via environment or `~/.aws/credentials`) for the Bedford Lab account. If you add a new profile to `~/.aws/credentials`, you can then tell the local nextstrain.org server to use it by setting `AWS_PROFILE=...`. diff --git a/static-site/README.md b/static-site/README.md index 3cab0048f..bb9dfd7df 100644 --- a/static-site/README.md +++ b/static-site/README.md @@ -14,6 +14,8 @@ See [the readme](../README.md#build-nextstrainorg-locally) in the parent directo ### Developing locally +For most cases, development servers for nextstrain.org can by run from the root of this repo - see the main README section: [Build nextstrain.org in development mode](https://github.com/nextstrain/nextstrain.org#build-nextstrain.org-in-development-mode). + To develop just the static-site part of nextstrain.org, you may run: ``` @@ -22,8 +24,7 @@ npm run develop ``` Note that certain parts of the gatsby site rely on API handlers not implemented in the gatsby dev server. -For these to work in development mode, you should also run the nextstrain.org server on port 5000 via -`npm run server` from the root of this repo. +For these to work in development mode, you should run the gatsby dev server while also running the nextstrain.org server - see the main README section: [Build nextstrain.org in development mode](https://github.com/nextstrain/nextstrain.org#build-nextstrain.org-in-development-mode). ### Testing the production build From 0cecdaf1c300b3d90c53a075c7d0da176e47a5e8 Mon Sep 17 00:00:00 2001 From: james hadfield Date: Wed, 10 Mar 2021 12:18:21 +1300 Subject: [PATCH 4/6] Fix import of createProxyMiddleware Commit f5f67bc added `http-proxy-middleware` as an explicit dependency, rather than a transitive dependency. This had the side-effect of upgrading the package from v0 to v1, the latter of which no longer exposes the `createProxyMiddleware` function as default, thus we need to use an explicit require to import it. Co-authored-by: Muhammad Aditya Hilmy --- static-site/gatsby-config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static-site/gatsby-config.js b/static-site/gatsby-config.js index aca2ba1b7..999fe2b9c 100644 --- a/static-site/gatsby-config.js +++ b/static-site/gatsby-config.js @@ -1,4 +1,4 @@ -const createProxyMiddleware = require("http-proxy-middleware"); +const { createProxyMiddleware } = require("http-proxy-middleware"); const config = require("./data/SiteConfig"); const auspicePaths = require("../auspicePaths"); From 92419eadeb7ec4eef6a35d41a400eacfd6d7feea Mon Sep 17 00:00:00 2001 From: eharkins Date: Tue, 9 Mar 2021 17:09:37 -0800 Subject: [PATCH 5/6] edit README --- README.md | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 64e860aeb..22ee01d24 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ This repository provides the tools you need to [build nextstrain.org locally](#b --- ## Build nextstrain.org locally -### Install prerequisites +### 1. Install prerequisites Install the node dependencies by running ``` npm ci @@ -30,13 +30,21 @@ from this directory (the "nextstrain.org" directory). > Using `npm ci` instead of `npm install` ensures your dependency tree matches those in `package-lock.json`. -### Build locally mirroring the deployed (live) website -1. `npm run build`, which runs `./build.sh` to build both the static site & an auspice client with customisations. -2. `npm run server` will then start a local instance, by default available at [localhost:5000](http://localhost:5000). +### 2. Build the site +`npm run build` runs `./build.sh` to build both the static site & an auspice client with customisations. +The following section details the different ways to serve these pages on a local server after building the site. + +### 3. Run server + +#### Run server mirroring the deployed (live) website +`npm run server` will start a local server, by default available at [localhost:5000](http://localhost:5000). This should mirror exactly what you see when you visit [nextstrain.org](https://nextstrain.org). -### Build nextstrain.org in development mode -Run `npm run dev` from the root of this repository to launch a development server of nextstrain.org, by default available at [localhost:8000](http://localhost:8000). +#### Run server in development mode +If you are developing on nextstrain.org, we recommend running: + +`npm run dev` , which runs `./develop.sh` to launch a development server of nextstrain.org, by default available at [localhost:8000](http://localhost:8000). +Changes to files in `./static-site` will be reflected in the corresponding pages on the development server without needing to refresh. This works by running the main nextstrain server on port 5000 and then running the Gatsby (see below for more on Gatsby) server on port 8000 and directing requests outside of Gatsby to port 5000. See [nextstrain.org/pull/280](https://github.com/nextstrain/nextstrain.org/pull/280) for more on this. From 6875524834ca66685cb7283d629d40602e6078a7 Mon Sep 17 00:00:00 2001 From: eharkins Date: Tue, 9 Mar 2021 17:13:37 -0800 Subject: [PATCH 6/6] update static site README --- static-site/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static-site/README.md b/static-site/README.md index bb9dfd7df..e3f82172c 100644 --- a/static-site/README.md +++ b/static-site/README.md @@ -14,7 +14,7 @@ See [the readme](../README.md#build-nextstrainorg-locally) in the parent directo ### Developing locally -For most cases, development servers for nextstrain.org can by run from the root of this repo - see the main README section: [Build nextstrain.org in development mode](https://github.com/nextstrain/nextstrain.org#build-nextstrain.org-in-development-mode). +For most cases, development servers for nextstrain.org can by run from the root of this repo - see the main README section: [Build nextstrain.org in development mode](../README.md#run-server-in-development-mode). To develop just the static-site part of nextstrain.org, you may run: @@ -24,7 +24,7 @@ npm run develop ``` Note that certain parts of the gatsby site rely on API handlers not implemented in the gatsby dev server. -For these to work in development mode, you should run the gatsby dev server while also running the nextstrain.org server - see the main README section: [Build nextstrain.org in development mode](https://github.com/nextstrain/nextstrain.org#build-nextstrain.org-in-development-mode). +For these to work in development mode, you should run the gatsby dev server while also running the nextstrain.org server - see the main README section: [Build nextstrain.org in development mode](../README.md#run-server-in-development-mode). ### Testing the production build