Enable more react pages (#19935)
* enable more react landing pages * move nextjs page logic to separate middleware * enable codespaces landing page + fixes * enable /education * enable /admin * use pathToRegexp to match routes for react rendering * run lint * fix: typo in url * update sidebar test
This commit is contained in:
@@ -139,7 +139,10 @@ export const getProductLandingContextFromRequest = (req: any): ProductLandingCon
|
||||
})
|
||||
.map(([key, links]: any) => {
|
||||
return {
|
||||
label: req.context.site.data.ui.toc[key],
|
||||
label:
|
||||
key === 'popular'
|
||||
? req.context.page.featuredLinks.popularHeading || req.context.site.data.ui.toc[key]
|
||||
: req.context.site.data.ui.toc[key],
|
||||
viewAllHref:
|
||||
key === 'guides' && !req.context.currentCategory && hasGuidesPage
|
||||
? `${req.context.currentPath}/guides`
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ArrowRightIcon, SearchIcon } from '@primer/octicons-react'
|
||||
import { useProductLandingContext } from 'components/context/ProductLandingContext'
|
||||
import { useTranslation } from 'components/hooks/useTranslation'
|
||||
import { CodeExampleCard } from 'components/landing/CodeExampleCard'
|
||||
import { Link } from 'components/Link'
|
||||
|
||||
const PAGE_SIZE = 6
|
||||
export const CodeExamples = () => {
|
||||
@@ -60,19 +61,19 @@ export const CodeExamples = () => {
|
||||
)}
|
||||
|
||||
{isSearching && searchResults.length === 0 && (
|
||||
<div className="d-none py-4 text-center color-text-secondary font-mktg">
|
||||
<div className="py-4 text-center color-text-secondary font-mktg">
|
||||
<div className="mb-3">
|
||||
<SearchIcon size={24} />{' '}
|
||||
</div>
|
||||
<h3 className="text-normal">
|
||||
{t('sorry')} <strong className="js-filter-card-value"></strong>
|
||||
{t('sorry')} <strong>{search}</strong>
|
||||
</h3>
|
||||
<p className="my-3 f4">
|
||||
{t('no_example')} <br /> {t('try_another')}
|
||||
</p>
|
||||
<a href="https://github.com/github/docs/blob/main/data/variables/discussions_community_examples.yml">
|
||||
{t('add_your_community')} <ArrowRightIcon />
|
||||
</a>
|
||||
<Link href="https://github.com/github/docs/blob/main/data/variables/actions_code_examples.yml">
|
||||
{t('learn')} <ArrowRightIcon />
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -60,7 +60,7 @@ export function ProductReleases() {
|
||||
})}
|
||||
</div>
|
||||
|
||||
<Link href={`${currentPath}/release-notes}`} className="btn btn-outline float-right">
|
||||
<Link href={`${currentPath}/release-notes`} className="btn btn-outline float-right">
|
||||
{t('explore_release_notes')} <ArrowRightIcon />
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -128,6 +128,7 @@ module.exports = function (app) {
|
||||
app.use(asyncMiddleware(instrument('./dev-toc')))
|
||||
app.use(asyncMiddleware(instrument('./featured-links')))
|
||||
app.use(asyncMiddleware(instrument('./learning-track')))
|
||||
app.use(asyncMiddleware(instrument('./is-next-request')))
|
||||
|
||||
// *** Headers for pages only ***
|
||||
app.use(require('./set-fastly-cache-headers'))
|
||||
|
||||
52
middleware/is-next-request.js
Normal file
52
middleware/is-next-request.js
Normal file
@@ -0,0 +1,52 @@
|
||||
const pathToRegexp = require('path-to-regexp')
|
||||
|
||||
const { FEATURE_NEXTJS } = process.env;
|
||||
|
||||
const productIds = [
|
||||
// 'actions',
|
||||
'admin',
|
||||
"billing",
|
||||
"code-security",
|
||||
"codespaces",
|
||||
"communities",
|
||||
"desktop",
|
||||
"developers",
|
||||
"discussions",
|
||||
// 'early-access',
|
||||
"education",
|
||||
// 'github',
|
||||
"graphql",
|
||||
// 'insights',
|
||||
"issues",
|
||||
"organizations",
|
||||
// 'packages',
|
||||
"pages",
|
||||
"rest",
|
||||
"sponsors",
|
||||
];
|
||||
|
||||
const landingPageExp = pathToRegexp('/:locale/:versionId?/:productId')
|
||||
|
||||
module.exports = function isNextRequest(req, res, next) {
|
||||
req.renderWithNextjs = false;
|
||||
|
||||
if (FEATURE_NEXTJS) {
|
||||
if ('nextjs' in req.query) {
|
||||
req.renderWithNextjs = true;
|
||||
} else {
|
||||
// Custom path matching to determine if we should render with nextjs
|
||||
|
||||
// Remove any query string (?...) and/or fragment identifier (#...)
|
||||
const { pathname } = new URL(req.originalUrl, "https://docs.github.com");
|
||||
|
||||
// Should the current path be rendered by NextJS?
|
||||
const landingPageMatch = landingPageExp.exec(pathname)
|
||||
if (landingPageMatch) {
|
||||
const productId = landingPageMatch[3]
|
||||
req.renderWithNextjs = productIds.includes(productId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
@@ -9,24 +9,8 @@ const RedisAccessor = require('../lib/redis-accessor')
|
||||
const { isConnectionDropped } = require('./halt-on-dropped-connection')
|
||||
const { nextHandleRequest } = require('./next')
|
||||
|
||||
const { HEROKU_RELEASE_VERSION, FEATURE_NEXTJS } = process.env
|
||||
const { HEROKU_RELEASE_VERSION } = process.env
|
||||
|
||||
const defaultNextJSRoutes = FEATURE_NEXTJS
|
||||
? [
|
||||
'/en/billing',
|
||||
'/en/code-security',
|
||||
'/en/communities',
|
||||
'/en/discussions',
|
||||
'/en/developers',
|
||||
'/en/desktop',
|
||||
'/en/graphql',
|
||||
'/en/issues',
|
||||
'/en/organizations',
|
||||
'/en/pages',
|
||||
'/en/rest',
|
||||
'/en/sponsors'
|
||||
]
|
||||
: []
|
||||
const pageCacheDatabaseNumber = 1
|
||||
const pageCacheExpiration = 24 * 60 * 60 * 1000 // 24 hours
|
||||
|
||||
@@ -104,9 +88,6 @@ module.exports = async function renderPage (req, res, next) {
|
||||
// Is the request for JSON debugging info?
|
||||
const isRequestingJsonForDebugging = 'json' in req.query && process.env.NODE_ENV !== 'production'
|
||||
|
||||
// Should the current path be rendered by NextJS?
|
||||
const renderWithNextjs = (defaultNextJSRoutes.includes(pathname) || 'nextjs' in req.query) && FEATURE_NEXTJS
|
||||
|
||||
// Is in an airgapped session?
|
||||
const isAirgapped = Boolean(req.cookies.AIRGAP)
|
||||
|
||||
@@ -124,7 +105,7 @@ module.exports = async function renderPage (req, res, next) {
|
||||
// Skip for JSON debugging info requests
|
||||
!isRequestingJsonForDebugging &&
|
||||
// Skip for NextJS rendering
|
||||
!renderWithNextjs &&
|
||||
!req.renderWithNextjs &&
|
||||
// Skip for airgapped sessions
|
||||
!isAirgapped &&
|
||||
// Skip for the GraphQL Explorer page
|
||||
@@ -202,7 +183,7 @@ module.exports = async function renderPage (req, res, next) {
|
||||
}
|
||||
|
||||
// Hand rendering over to NextJS when appropriate
|
||||
if (renderWithNextjs) {
|
||||
if (req.renderWithNextjs) {
|
||||
req.context.renderedPage = context.renderedPage
|
||||
req.context.miniTocItems = context.miniTocItems
|
||||
return nextHandleRequest(req, res)
|
||||
|
||||
1
package-lock.json
generated
1
package-lock.json
generated
@@ -55,6 +55,7 @@
|
||||
"next": "^10.2.3",
|
||||
"node-fetch": "^2.6.1",
|
||||
"parse5": "^6.0.1",
|
||||
"path-to-regexp": "^0.1.7",
|
||||
"port-used": "^2.0.8",
|
||||
"rate-limit-redis": "^2.1.0",
|
||||
"react": "^17.0.2",
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
"next": "^10.2.3",
|
||||
"node-fetch": "^2.6.1",
|
||||
"parse5": "^6.0.1",
|
||||
"path-to-regexp": "^0.1.7",
|
||||
"port-used": "^2.0.8",
|
||||
"rate-limit-redis": "^2.1.0",
|
||||
"react": "^17.0.2",
|
||||
|
||||
@@ -15,8 +15,8 @@ describe('sidebar', () => {
|
||||
})
|
||||
|
||||
test('highlights active product on Enterprise pages', async () => {
|
||||
expect($enterprisePage('.sidebar li.sidebar-product').length).toBe(1)
|
||||
expect($enterprisePage('.sidebar li.sidebar-product > a').text().trim()).toBe('GitHub Enterprise')
|
||||
expect($enterprisePage('.sidebar-products li.sidebar-product').length).toBe(1)
|
||||
expect($enterprisePage('.sidebar-products li.sidebar-product > a').text().trim()).toBe('GitHub Enterprise')
|
||||
})
|
||||
|
||||
test('highlights active product on GitHub pages', async () => {
|
||||
|
||||
Reference in New Issue
Block a user