From 1c1a4de0e2d38090fcf95ef0a6f6790006aaa124 Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Thu, 20 Jan 2022 22:25:44 +0100 Subject: [PATCH] Refactor base server to remove native dependencies (#33499) Part of #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` --- packages/next/build/entries.ts | 2 +- packages/next/build/index.ts | 3 +- packages/next/build/output/log.ts | 2 +- .../loaders/next-serverless-loader/utils.ts | 19 +++++----- packages/next/export/index.ts | 3 +- packages/next/lib/chalk.ts | 9 +++++ packages/next/lib/load-custom-routes.ts | 2 +- packages/next/lib/web/chalk.ts | 19 ++++++++++ packages/next/server/api-utils.ts | 6 ++- packages/next/server/base-http.ts | 1 + packages/next/server/base-server.ts | 23 ++---------- packages/next/server/config.ts | 8 +--- packages/next/server/lib/find-page-file.ts | 2 +- packages/next/server/next-server.ts | 37 ++++++++++++++++--- packages/next/server/send-payload.ts | 5 ++- packages/next/server/utils.ts | 6 +++ 16 files changed, 97 insertions(+), 50 deletions(-) create mode 100644 packages/next/lib/chalk.ts create mode 100644 packages/next/lib/web/chalk.ts diff --git a/packages/next/build/entries.ts b/packages/next/build/entries.ts index 3779caae4ebbb..dab27b168dffc 100644 --- a/packages/next/build/entries.ts +++ b/packages/next/build/entries.ts @@ -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' diff --git a/packages/next/build/index.ts b/packages/next/build/index.ts index a1ea6bc2bcc22..89cc94663989c 100644 --- a/packages/next/build/index.ts +++ b/packages/next/build/index.ts @@ -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' diff --git a/packages/next/build/output/log.ts b/packages/next/build/output/log.ts index 9bbe2d26117b5..9220fe1834e36 100644 --- a/packages/next/build/output/log.ts +++ b/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') + ' -', diff --git a/packages/next/build/webpack/loaders/next-serverless-loader/utils.ts b/packages/next/build/webpack/loaders/next-serverless-loader/utils.ts index 28b1ce0953142..2ab3106b90c70 100644 --- a/packages/next/build/webpack/loaders/next-serverless-loader/utils.ts +++ b/packages/next/build/webpack/loaders/next-serverless-loader/utils.ts @@ -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' @@ -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' diff --git a/packages/next/export/index.ts b/packages/next/export/index.ts index 36b5d17e0317f..36d6930318ad4 100644 --- a/packages/next/export/index.ts +++ b/packages/next/export/index.ts @@ -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' diff --git a/packages/next/lib/chalk.ts b/packages/next/lib/chalk.ts new file mode 100644 index 0000000000000..d6150d2dcf3e9 --- /dev/null +++ b/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 diff --git a/packages/next/lib/load-custom-routes.ts b/packages/next/lib/load-custom-routes.ts index 87765abc4267e..05afa09b9c94a 100644 --- a/packages/next/lib/load-custom-routes.ts +++ b/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' diff --git a/packages/next/lib/web/chalk.ts b/packages/next/lib/web/chalk.ts new file mode 100644 index 0000000000000..eb4be7f9bd5ea --- /dev/null +++ b/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 diff --git a/packages/next/server/api-utils.ts b/packages/next/server/api-utils.ts index fab3277976969..a8bc956f4f6bf 100644 --- a/packages/next/server/api-utils.ts +++ b/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' @@ -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') { diff --git a/packages/next/server/base-http.ts b/packages/next/server/base-http.ts index b353df2d09683..e53d2ef811325 100644 --- a/packages/next/server/base-http.ts +++ b/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, diff --git a/packages/next/server/base-server.ts b/packages/next/server/base-server.ts index 2a62379e53c59..e2280e87f4b6c 100644 --- a/packages/next/server/base-server.ts +++ b/packages/next/server/base-server.ts @@ -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 { @@ -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' @@ -274,6 +273,8 @@ export default abstract class Server { onWarning?: (warning: Error) => void }): Promise + protected abstract loadEnvConfig(params: { dev: boolean }): void + public constructor({ dir = '.', quiet = false, @@ -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 @@ -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 { diff --git a/packages/next/server/config.ts b/packages/next/server/config.ts index 01f6b902027f4..fd91abc117e1e 100644 --- a/packages/next/server/config.ts +++ b/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' @@ -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'] ) { diff --git a/packages/next/server/lib/find-page-file.ts b/packages/next/server/lib/find-page-file.ts index 8baf2725ed12a..a8bb85406e6ac 100644 --- a/packages/next/server/lib/find-page-file.ts +++ b/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' diff --git a/packages/next/server/next-server.ts b/packages/next/server/next-server.ts index 5b04e41695e6e..4bcc035503841 100644 --- a/packages/next/server/next-server.ts +++ b/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' @@ -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, @@ -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' @@ -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')) } diff --git a/packages/next/server/send-payload.ts b/packages/next/server/send-payload.ts index 138e154080ad3..ccc702b69e1c7 100644 --- a/packages/next/server/send-payload.ts +++ b/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 } diff --git a/packages/next/server/utils.ts b/packages/next/server/utils.ts index e9e4cb9a66e2d..2448f8d399eff 100644 --- a/packages/next/server/utils.ts +++ b/packages/next/server/utils.ts @@ -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 +}