Skip to content

Commit

Permalink
Refactor base server to remove native dependencies (vercel#33499)
Browse files Browse the repository at this point in the history
Part of vercel#31506, this PR removes `loadEnvConfig` and `chalk` from the base server while keeping the same behavior for the node server.

## Bug

- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`

## Documentation / Examples

- [ ] Make sure the linting passes by running `yarn lint`
  • Loading branch information
shuding authored and nevilm-lt committed Apr 22, 2022
1 parent b6cb044 commit 9324dfd
Show file tree
Hide file tree
Showing 16 changed files with 97 additions and 50 deletions.
2 changes: 1 addition & 1 deletion packages/next/build/entries.ts
Expand Up @@ -4,7 +4,7 @@ import { stringify } from 'querystring'
import { API_ROUTE, DOT_NEXT_ALIAS, PAGES_DIR_ALIAS } from '../lib/constants'
import { MIDDLEWARE_ROUTE } from '../lib/constants'
import { __ApiPreviewProps } from '../server/api-utils'
import { isTargetLikeServerless } from '../server/config'
import { isTargetLikeServerless } from '../server/utils'
import { normalizePagePath } from '../server/normalize-page-path'
import { warn } from './output/log'
import { MiddlewareLoaderOptions } from './webpack/loaders/next-middleware-loader'
Expand Down
3 changes: 2 additions & 1 deletion packages/next/build/index.ts
Expand Up @@ -57,7 +57,8 @@ import {
isDynamicRoute,
} from '../shared/lib/router/utils'
import { __ApiPreviewProps } from '../server/api-utils'
import loadConfig, { isTargetLikeServerless } from '../server/config'
import loadConfig from '../server/config'
import { isTargetLikeServerless } from '../server/utils'
import { BuildManifest } from '../server/get-page-files'
import { normalizePagePath } from '../server/normalize-page-path'
import { getPagePath } from '../server/require'
Expand Down
2 changes: 1 addition & 1 deletion packages/next/build/output/log.ts
@@ -1,4 +1,4 @@
import chalk from 'next/dist/compiled/chalk'
import chalk from '../../lib/chalk'

export const prefixes = {
wait: chalk.cyan('wait') + ' -',
Expand Down
@@ -1,7 +1,15 @@
import { IncomingMessage, ServerResponse } from 'http'
import type { IncomingMessage, ServerResponse } from 'http'
import type { Rewrite } from '../../../../lib/load-custom-routes'
import type { BuildManifest } from '../../../../server/get-page-files'
import type { NextConfig } from '../../../../server/config'
import type {
GetServerSideProps,
GetStaticPaths,
GetStaticProps,
} from '../../../../types'

import { format as formatUrl, UrlWithParsedQuery, parse as parseUrl } from 'url'
import { parse as parseQs, ParsedUrlQuery } from 'querystring'
import { Rewrite } from '../../../../lib/load-custom-routes'
import { normalizeLocalePath } from '../../../../shared/lib/i18n/normalize-locale-path'
import pathMatch from '../../../../shared/lib/router/utils/path-match'
import { getRouteRegex } from '../../../../shared/lib/router/utils/route-regex'
Expand All @@ -11,19 +19,12 @@ import {
prepareDestination,
} from '../../../../shared/lib/router/utils/prepare-destination'
import { __ApiPreviewProps } from '../../../../server/api-utils'
import { BuildManifest } from '../../../../server/get-page-files'
import {
GetServerSideProps,
GetStaticPaths,
GetStaticProps,
} from '../../../../types'
import { acceptLanguage } from '../../../../server/accept-header'
import { detectLocaleCookie } from '../../../../shared/lib/i18n/detect-locale-cookie'
import { detectDomainLocale } from '../../../../shared/lib/i18n/detect-domain-locale'
import { denormalizePagePath } from '../../../../server/denormalize-page-path'
import cookie from 'next/dist/compiled/cookie'
import { TEMPORARY_REDIRECT_STATUS } from '../../../../shared/lib/constants'
import { NextConfig } from '../../../../server/config'
import { addRequestMeta } from '../../../../server/request-meta'
import { BaseNextRequest } from '../../../../server/base-http'

Expand Down
3 changes: 2 additions & 1 deletion packages/next/export/index.ts
Expand Up @@ -28,7 +28,8 @@ import {
SERVERLESS_DIRECTORY,
SERVER_DIRECTORY,
} from '../shared/lib/constants'
import loadConfig, { isTargetLikeServerless } from '../server/config'
import loadConfig from '../server/config'
import { isTargetLikeServerless } from '../server/utils'
import { NextConfigComplete } from '../server/config-shared'
import { eventCliSession } from '../telemetry/events'
import { hasNextSupport } from '../telemetry/ci-info'
Expand Down
9 changes: 9 additions & 0 deletions packages/next/lib/chalk.ts
@@ -0,0 +1,9 @@
let chalk: typeof import('next/dist/compiled/chalk')

if (typeof window === 'undefined') {
chalk = require('next/dist/compiled/chalk')
} else {
chalk = require('./web/chalk').default
}

export default chalk
2 changes: 1 addition & 1 deletion packages/next/lib/load-custom-routes.ts
@@ -1,6 +1,6 @@
import type { NextConfig } from '../server/config'

import chalk from 'next/dist/compiled/chalk'
import chalk from './chalk'
import { parse as parseUrl } from 'url'
import * as pathToRegexp from 'next/dist/compiled/path-to-regexp'
import { escapeStringRegexp } from '../shared/lib/escape-regexp'
Expand Down
19 changes: 19 additions & 0 deletions packages/next/lib/web/chalk.ts
@@ -0,0 +1,19 @@
// In the web runtime, we create an alternative object that just outputs the
// message to the console without any styling. The same APIs are supported
// for compatibility:
// - chalk.red('error')
// - chalk.bold.cyan('message')
// - chalk.hex('#fff').underline('hello')
const log = console.log
const chalk: any = new Proxy(log, {
get(_, prop: string) {
if (
['hex', 'rgb', 'ansi256', 'bgHex', 'bgRgb', 'bgAnsi256'].includes(prop)
) {
return () => chalk
}
return chalk
},
})

export default chalk
6 changes: 4 additions & 2 deletions packages/next/server/api-utils.ts
@@ -1,7 +1,7 @@
import { IncomingMessage, ServerResponse } from 'http'
import type { IncomingMessage, ServerResponse } from 'http'

import { parse } from 'next/dist/compiled/content-type'
import { CookieSerializeOptions } from 'next/dist/compiled/cookie'
import getRawBody from 'next/dist/compiled/raw-body'
import { PageConfig, PreviewData } from 'next/types'
import { Stream } from 'stream'
import { isResSent, NextApiRequest, NextApiResponse } from '../shared/lib/utils'
Expand Down Expand Up @@ -157,6 +157,8 @@ export async function parseBody(
let buffer

try {
const getRawBody =
require('next/dist/compiled/raw-body') as typeof import('next/dist/compiled/raw-body')
buffer = await getRawBody(req, { encoding, limit })
} catch (e) {
if (isError(e) && e.type === 'entity.too.large') {
Expand Down
1 change: 1 addition & 0 deletions packages/next/server/base-http.ts
@@ -1,5 +1,6 @@
import type { ServerResponse, IncomingMessage, IncomingHttpHeaders } from 'http'
import type { Writable, Readable } from 'stream'

import { PERMANENT_REDIRECT_STATUS } from '../shared/lib/constants'
import {
getCookieParser,
Expand Down
23 changes: 4 additions & 19 deletions packages/next/server/base-server.ts
Expand Up @@ -43,7 +43,7 @@ import {
import * as envConfig from '../shared/lib/runtime-config'
import { DecodeError, normalizeRepeatedSlashes } from '../shared/lib/utils'
import { setLazyProp, getCookieParser, tryGetPreviewData } from './api-utils'
import { isTargetLikeServerless } from './config'
import { isTargetLikeServerless } from './utils'
import pathMatch from '../shared/lib/router/utils/path-match'
import Router, { replaceBasePath, route } from './router'
import {
Expand All @@ -55,7 +55,6 @@ import { IncrementalCache } from './incremental-cache'
import { execOnce } from '../shared/lib/utils'
import { isBlockedPage, isBot } from './utils'
import RenderResult from './render-result'
import { loadEnvConfig } from '@next/env'
import { removePathTrailingSlash } from '../client/normalize-trailing-slash'
import getRouteFromAssetPath from '../shared/lib/router/utils/get-route-from-asset-path'
import { denormalizePagePath } from './denormalize-page-path'
Expand Down Expand Up @@ -274,6 +273,8 @@ export default abstract class Server {
onWarning?: (warning: Error) => void
}): Promise<FetchEventResult | null>

protected abstract loadEnvConfig(params: { dev: boolean }): void

public constructor({
dir = '.',
quiet = false,
Expand All @@ -286,7 +287,7 @@ export default abstract class Server {
}: Options) {
this.dir = resolve(dir)
this.quiet = quiet
loadEnvConfig(this.dir, dev, Log)
this.loadEnvConfig({ dev })

// TODO: should conf be normalized to prevent missing
// values from causing issues as this can be user provided
Expand Down Expand Up @@ -376,22 +377,6 @@ export default abstract class Server {
flushToDisk: !minimalMode && this.nextConfig.experimental.isrFlushToDisk,
})
this.responseCache = new ResponseCache(this.incrementalCache)

/**
* This sets environment variable to be used at the time of SSR by head.tsx.
* Using this from process.env allows targeting both serverless and SSR by calling
* `process.env.__NEXT_OPTIMIZE_IMAGES`.
* TODO(atcastle@): Remove this when experimental.optimizeImages are being cleaned up.
*/
if (this.renderOpts.optimizeFonts) {
process.env.__NEXT_OPTIMIZE_FONTS = JSON.stringify(true)
}
if (this.renderOpts.optimizeImages) {
process.env.__NEXT_OPTIMIZE_IMAGES = JSON.stringify(true)
}
if (this.renderOpts.optimizeCss) {
process.env.__NEXT_OPTIMIZE_CSS = JSON.stringify(true)
}
}

public logError(err: Error): void {
Expand Down
8 changes: 1 addition & 7 deletions packages/next/server/config.ts
@@ -1,4 +1,4 @@
import chalk from 'next/dist/compiled/chalk'
import chalk from '../lib/chalk'
import findUp from 'next/dist/compiled/find-up'
import { basename, extname, relative, isAbsolute, resolve } from 'path'
import { pathToFileURL } from 'url'
Expand Down Expand Up @@ -656,12 +656,6 @@ export default async function loadConfig(
return completeConfig
}

export function isTargetLikeServerless(target: string) {
const isServerless = target === 'serverless'
const isServerlessTrace = target === 'experimental-serverless-trace'
return isServerless || isServerlessTrace
}

export function setHttpAgentOptions(
options: NextConfigComplete['httpAgentOptions']
) {
Expand Down
2 changes: 1 addition & 1 deletion packages/next/server/lib/find-page-file.ts
@@ -1,5 +1,5 @@
import { join, sep as pathSeparator, normalize } from 'path'
import chalk from 'next/dist/compiled/chalk'
import chalk from '../../lib/chalk'
import { warn } from '../../build/output/log'
import { promises } from 'fs'
import { denormalizePagePath } from '../normalize-page-path'
Expand Down
37 changes: 32 additions & 5 deletions packages/next/server/next-server.ts
@@ -1,15 +1,17 @@
import type { Params, Route } from './router'
import { CacheFs, execOnce } from '../shared/lib/utils'
import type { CacheFs } from '../shared/lib/utils'
import type { MiddlewareManifest } from '../build/webpack/plugins/middleware-plugin'
import type RenderResult from './render-result'
import type { FetchEventResult } from './web/types'
import type { ParsedNextUrl } from '../shared/lib/router/utils/parse-next-url'

import { execOnce } from '../shared/lib/utils'
import {
addRequestMeta,
getRequestMeta,
NextParsedUrlQuery,
NextUrlWithParsedQuery,
} from './request-meta'
import type { MiddlewareManifest } from '../build/webpack/plugins/middleware-plugin'
import type RenderResult from './render-result'
import type { FetchEventResult } from './web/types'
import type { ParsedNextUrl } from '../shared/lib/router/utils/parse-next-url'

import fs from 'fs'
import { join, relative, resolve, sep } from 'path'
Expand Down Expand Up @@ -46,6 +48,7 @@ import { ParsedUrl } from '../shared/lib/router/utils/parse-url'
import * as Log from '../build/output/log'

import BaseServer, {
Options,
FindComponentsResult,
prepareServerlessUrl,
stringifyQuery,
Expand All @@ -62,6 +65,7 @@ import { prepareDestination } from '../shared/lib/router/utils/prepare-destinati
import { normalizeLocalePath } from '../shared/lib/i18n/normalize-locale-path'
import { getMiddlewareRegex, getRouteMatcher } from '../shared/lib/router/utils'
import { MIDDLEWARE_ROUTE } from '../lib/constants'
import { loadEnvConfig } from '@next/env'

export * from './base-server'

Expand All @@ -80,11 +84,34 @@ export interface NodeRequestHandler {
}

export default class NextNodeServer extends BaseServer {
constructor(options: Options) {
super(options)
/**
* This sets environment variable to be used at the time of SSR by head.tsx.
* Using this from process.env allows targeting both serverless and SSR by calling
* `process.env.__NEXT_OPTIMIZE_IMAGES`.
* TODO(atcastle@): Remove this when experimental.optimizeImages are being cleaned up.
*/
if (this.renderOpts.optimizeFonts) {
process.env.__NEXT_OPTIMIZE_FONTS = JSON.stringify(true)
}
if (this.renderOpts.optimizeImages) {
process.env.__NEXT_OPTIMIZE_IMAGES = JSON.stringify(true)
}
if (this.renderOpts.optimizeCss) {
process.env.__NEXT_OPTIMIZE_CSS = JSON.stringify(true)
}
}

private compression =
this.nextConfig.compress && this.nextConfig.target === 'server'
? (compression() as ExpressMiddleware)
: undefined

protected loadEnvConfig({ dev }: { dev: boolean }) {
loadEnvConfig(this.dir, dev, Log)
}

protected getHasStaticDir(): boolean {
return fs.existsSync(join(this.dir, 'static'))
}
Expand Down
5 changes: 3 additions & 2 deletions packages/next/server/send-payload.ts
@@ -1,9 +1,10 @@
import { IncomingMessage, ServerResponse } from 'http'
import type { IncomingMessage, ServerResponse } from 'http'
import type { BaseNextResponse } from './base-http'

import { isResSent } from '../shared/lib/utils'
import generateETag from 'next/dist/compiled/etag'
import fresh from 'next/dist/compiled/fresh'
import RenderResult from './render-result'
import { BaseNextResponse } from './base-http'

export type PayloadOptions =
| { private: true }
Expand Down
6 changes: 6 additions & 0 deletions packages/next/server/utils.ts
Expand Up @@ -20,3 +20,9 @@ export function isBot(userAgent: string): boolean {
userAgent
)
}

export function isTargetLikeServerless(target: string) {
const isServerless = target === 'serverless'
const isServerlessTrace = target === 'experimental-serverless-trace'
return isServerless || isServerlessTrace
}

0 comments on commit 9324dfd

Please sign in to comment.