diff --git a/lerna.json b/lerna.json index ee1bee6f310e7..338c40210a2df 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "13.1.5-canary.1" + "version": "13.1.5-canary.2" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 18974bcfec837..fe9b906a28941 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "13.1.5-canary.1", + "version": "13.1.5-canary.2", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index ea42910c49aa4..65f240b49c9fa 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "13.1.5-canary.1", + "version": "13.1.5-canary.2", "description": "ESLint configuration used by NextJS.", "main": "index.js", "license": "MIT", @@ -12,7 +12,7 @@ "test-pack": "cd ../../ && pnpm test-pack eslint-config-next" }, "dependencies": { - "@next/eslint-plugin-next": "13.1.5-canary.1", + "@next/eslint-plugin-next": "13.1.5-canary.2", "@rushstack/eslint-patch": "^1.1.3", "@typescript-eslint/parser": "^5.42.0", "eslint-import-resolver-node": "^0.3.6", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index 493db9498e7c5..ae41e133e8433 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "13.1.5-canary.1", + "version": "13.1.5-canary.2", "description": "ESLint plugin for NextJS.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 7eaaa70400a9b..0286d2b31f630 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "13.1.5-canary.1", + "version": "13.1.5-canary.2", "repository": { "url": "vercel/next.js", "directory": "packages/font" diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index 8f0d82463ab59..5134236ec139f 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "13.1.5-canary.1", + "version": "13.1.5-canary.2", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 98a02b07a83cc..54800dd2f3dbf 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "13.1.5-canary.1", + "version": "13.1.5-canary.2", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 35d641fb2115b..676cb9f95880a 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "13.1.5-canary.1", + "version": "13.1.5-canary.2", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 771aaad573bc8..760c7476b6ff7 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "13.1.5-canary.1", + "version": "13.1.5-canary.2", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index bf439d81b54f5..d75b6e6acfa09 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "13.1.5-canary.1", + "version": "13.1.5-canary.2", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index a0ab3276c5974..9c8a6a78af312 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "13.1.5-canary.1", + "version": "13.1.5-canary.2", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index 17478a9ade7c1..66529d601733c 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "13.1.5-canary.1", + "version": "13.1.5-canary.2", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 49fecae898f9a..74d02b3cbd347 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "13.1.5-canary.1", + "version": "13.1.5-canary.2", "private": true, "scripts": { "build-native": "napi build --platform -p next-swc-napi --cargo-name next_swc_napi --features plugin,rustls-tls --js false native", diff --git a/packages/next/package.json b/packages/next/package.json index d6006e071d501..f2057ea7edd06 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "13.1.5-canary.1", + "version": "13.1.5-canary.2", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -77,7 +77,7 @@ ] }, "dependencies": { - "@next/env": "13.1.5-canary.1", + "@next/env": "13.1.5-canary.2", "@swc/helpers": "0.4.14", "caniuse-lite": "^1.0.30001406", "postcss": "8.4.14", @@ -127,11 +127,11 @@ "@hapi/accept": "5.0.2", "@napi-rs/cli": "2.13.3", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "13.1.5-canary.1", - "@next/polyfill-nomodule": "13.1.5-canary.1", - "@next/react-dev-overlay": "13.1.5-canary.1", - "@next/react-refresh-utils": "13.1.5-canary.1", - "@next/swc": "13.1.5-canary.1", + "@next/polyfill-module": "13.1.5-canary.2", + "@next/polyfill-nomodule": "13.1.5-canary.2", + "@next/react-dev-overlay": "13.1.5-canary.2", + "@next/react-refresh-utils": "13.1.5-canary.2", + "@next/swc": "13.1.5-canary.2", "@segment/ajv-human-errors": "2.1.2", "@taskr/clear": "1.1.0", "@taskr/esnext": "1.1.0", diff --git a/packages/next/src/cli/next-dev.ts b/packages/next/src/cli/next-dev.ts index 7b08565af0381..dba4b2d5de814 100644 --- a/packages/next/src/cli/next-dev.ts +++ b/packages/next/src/cli/next-dev.ts @@ -35,7 +35,13 @@ const handleSessionStop = async () => { const { eventCliSession } = require('../telemetry/events/session-stopped') as typeof import('../telemetry/events/session-stopped') - const config = await loadConfig(PHASE_DEVELOPMENT_SERVER, dir) + const config = await loadConfig( + PHASE_DEVELOPMENT_SERVER, + dir, + undefined, + undefined, + true + ) let telemetry = (traceGlobals.get('telemetry') as InstanceType< @@ -493,7 +499,13 @@ If you cannot make the changes above, but still want to try out\nNext.js v13 wit cluster.settings.stdio = ['ipc', 'pipe', 'pipe'] setupFork() - config = await loadConfig(PHASE_DEVELOPMENT_SERVER, dir) + config = await loadConfig( + PHASE_DEVELOPMENT_SERVER, + dir, + undefined, + undefined, + true + ) const handleProjectDirRename = (newDir: string) => { clusterExitUnsub() diff --git a/packages/next/src/server/config.ts b/packages/next/src/server/config.ts index 6e07a66a74377..7d152df002e59 100644 --- a/packages/next/src/server/config.ts +++ b/packages/next/src/server/config.ts @@ -56,19 +56,22 @@ const experimentalWarning = execOnce( } ) -export function setHttpClientAndAgentOptions(config: { - httpAgentOptions?: NextConfig['httpAgentOptions'] - experimental?: { - enableUndici?: boolean - } -}) { +export function setHttpClientAndAgentOptions( + config: { + httpAgentOptions?: NextConfig['httpAgentOptions'] + experimental?: { + enableUndici?: boolean + } + }, + silent = false +) { if (isAboveNodejs16) { // Node.js 18 has undici built-in. if (config.experimental?.enableUndici && !isAboveNodejs18) { // When appDir is enabled undici is the default because of Response.clone() issues in node-fetch ;(globalThis as any).__NEXT_USE_UNDICI = config.experimental?.enableUndici } - } else if (config.experimental?.enableUndici) { + } else if (config.experimental?.enableUndici && !silent) { Log.warn( `\`enableUndici\` option requires Node.js v${NODE_16_VERSION} or greater. Falling back to \`node-fetch\`` ) @@ -130,14 +133,17 @@ export function warnOptionHasBeenMovedOutOfExperimental( config: NextConfig, oldKey: string, newKey: string, - configFileName: string + configFileName: string, + silent = false ) { if (config.experimental && oldKey in config.experimental) { - Log.warn( - `\`${oldKey}\` has been moved out of \`experimental\`` + - (newKey.includes('.') ? ` and into \`${newKey}\`` : '') + - `. Please update your ${configFileName} file accordingly.` - ) + if (!silent) { + Log.warn( + `\`${oldKey}\` has been moved out of \`experimental\`` + + (newKey.includes('.') ? ` and into \`${newKey}\`` : '') + + `. Please update your ${configFileName} file accordingly.` + ) + } let current = config const newKeys = newKey.split('.') @@ -152,9 +158,13 @@ export function warnOptionHasBeenMovedOutOfExperimental( return config } -function assignDefaults(dir: string, userConfig: { [key: string]: any }) { +function assignDefaults( + dir: string, + userConfig: { [key: string]: any }, + silent = false +) { const configFileName = userConfig.configFileName - if (typeof userConfig.exportTrailingSlash !== 'undefined') { + if (!silent && typeof userConfig.exportTrailingSlash !== 'undefined') { console.warn( chalk.yellow.bold('Warning: ') + `The "exportTrailingSlash" option has been renamed to "trailingSlash". Please update your ${configFileName}.` @@ -200,7 +210,7 @@ function assignDefaults(dir: string, userConfig: { [key: string]: any }) { } } - if (enabledExperiments.length > 0) { + if (!silent && enabledExperiments.length > 0) { experimentalWarning(configFileName, enabledExperiments) } } @@ -572,43 +582,52 @@ function assignDefaults(dir: string, userConfig: { [key: string]: any }) { result, 'relay', 'compiler.relay', - configFileName + configFileName, + silent ) warnOptionHasBeenMovedOutOfExperimental( result, 'styledComponents', 'compiler.styledComponents', - configFileName + configFileName, + silent ) warnOptionHasBeenMovedOutOfExperimental( result, 'emotion', 'compiler.emotion', - configFileName + configFileName, + silent ) warnOptionHasBeenMovedOutOfExperimental( result, 'reactRemoveProperties', 'compiler.reactRemoveProperties', - configFileName + configFileName, + silent ) warnOptionHasBeenMovedOutOfExperimental( result, 'removeConsole', 'compiler.removeConsole', - configFileName + configFileName, + silent ) if (result.experimental?.swcMinifyDebugOptions) { - Log.warn( - 'SWC minify debug option specified. This option is for debugging minifier issues and will be removed once SWC minifier is stable.' - ) + if (!silent) { + Log.warn( + 'SWC minify debug option specified. This option is for debugging minifier issues and will be removed once SWC minifier is stable.' + ) + } } if ((result.experimental as any).outputStandalone) { - Log.warn( - `experimental.outputStandalone has been renamed to "output: 'standalone'", please move the config.` - ) + if (!silent) { + Log.warn( + `experimental.outputStandalone has been renamed to "output: 'standalone'", please move the config.` + ) + } result.output = 'standalone' } @@ -616,19 +635,22 @@ function assignDefaults(dir: string, userConfig: { [key: string]: any }) { result, 'transpilePackages', 'transpilePackages', - configFileName + configFileName, + silent ) warnOptionHasBeenMovedOutOfExperimental( result, 'skipMiddlewareUrlNormalize', 'skipMiddlewareUrlNormalize', - configFileName + configFileName, + silent ) warnOptionHasBeenMovedOutOfExperimental( result, 'skipTrailingSlashRedirect', 'skipTrailingSlashRedirect', - configFileName + configFileName, + silent ) if ( @@ -638,19 +660,23 @@ function assignDefaults(dir: string, userConfig: { [key: string]: any }) { result.experimental.outputFileTracingRoot = resolve( result.experimental.outputFileTracingRoot ) - Log.warn( - `experimental.outputFileTracingRoot should be absolute, using: ${result.experimental.outputFileTracingRoot}` - ) + if (!silent) { + Log.warn( + `experimental.outputFileTracingRoot should be absolute, using: ${result.experimental.outputFileTracingRoot}` + ) + } } if (result.output === 'standalone' && !result.outputFileTracing) { - Log.warn( - `"output: 'standalone'" requires outputFileTracing not be disabled please enable it to leverage the standalone build` - ) + if (!silent) { + Log.warn( + `"output: 'standalone'" requires outputFileTracing not be disabled please enable it to leverage the standalone build` + ) + } result.output = undefined } - setHttpClientAndAgentOptions(result || defaultConfig) + setHttpClientAndAgentOptions(result || defaultConfig, silent) if (result.i18n) { const { i18n } = result @@ -668,7 +694,7 @@ function assignDefaults(dir: string, userConfig: { [key: string]: any }) { ) } - if (i18n.locales.length > 100) { + if (i18n.locales.length > 100 && !silent) { Log.warn( `Received ${i18n.locales.length} i18n.locales items which exceeds the recommended max of 100.\nSee more info here: https://nextjs.org/docs/advanced-features/i18n-routing#how-does-this-work-with-static-generation` ) @@ -700,7 +726,7 @@ function assignDefaults(dir: string, userConfig: { [key: string]: any }) { altItem.domain !== item.domain ) - if (defaultLocaleDuplicate) { + if (!silent && defaultLocaleDuplicate) { console.warn( `Both ${item.domain} and ${defaultLocaleDuplicate.domain} configured the defaultLocale ${item.defaultLocale} but only one can. Change one item's default locale to continue` ) @@ -830,9 +856,18 @@ export default async function loadConfig( phase: string, dir: string, customConfig?: object | null, - rawConfig?: boolean + rawConfig?: boolean, + silent?: boolean ): Promise { - await loadEnvConfig(dir, phase === PHASE_DEVELOPMENT_SERVER, Log) + const curLog = silent + ? { + warn: () => {}, + info: () => {}, + error: () => {}, + } + : Log + + await loadEnvConfig(dir, phase === PHASE_DEVELOPMENT_SERVER, curLog) if (!customConfig) { loadWebpackHook() @@ -841,11 +876,15 @@ export default async function loadConfig( let configFileName = 'next.config.js' if (customConfig) { - return assignDefaults(dir, { - configOrigin: 'server', - configFileName, - ...customConfig, - }) as NextConfigComplete + return assignDefaults( + dir, + { + configOrigin: 'server', + configFileName, + ...customConfig, + }, + silent + ) as NextConfigComplete } const path = await findUp(CONFIG_FILES, { cwd: dir }) @@ -872,7 +911,7 @@ export default async function loadConfig( return userConfigModule } } catch (err) { - Log.error( + curLog.error( `Failed to load ${configFileName}, see more info here https://nextjs.org/docs/messages/next-config-error` ) throw err @@ -884,8 +923,8 @@ export default async function loadConfig( const validateResult = validateConfig(userConfig) - if (validateResult.errors) { - Log.warn(`Invalid next.config.js options detected: `) + if (!silent && validateResult.errors) { + curLog.warn(`Invalid next.config.js options detected: `) // Only load @segment/ajv-human-errors when invalid config is detected const { AggregateAjvError } = @@ -903,7 +942,7 @@ export default async function loadConfig( } if (Object.keys(userConfig).length === 0) { - Log.warn( + curLog.warn( `Detected ${configFileName}, no exported configuration found. https://nextjs.org/docs/messages/empty-configuration` ) } @@ -924,12 +963,16 @@ export default async function loadConfig( : canonicalBase) || '' } - const completeConfig = assignDefaults(dir, { - configOrigin: relative(dir, path), - configFile: path, - configFileName, - ...userConfig, - }) as NextConfigComplete + const completeConfig = assignDefaults( + dir, + { + configOrigin: relative(dir, path), + configFile: path, + configFileName, + ...userConfig, + }, + silent + ) as NextConfigComplete setFontLoaderDefaults(completeConfig) return completeConfig } else { @@ -956,10 +999,11 @@ export default async function loadConfig( // reactRoot can be updated correctly even with no next.config.js const completeConfig = assignDefaults( dir, - defaultConfig + defaultConfig, + silent ) as NextConfigComplete completeConfig.configFileName = configFileName - setHttpClientAndAgentOptions(completeConfig) + setHttpClientAndAgentOptions(completeConfig, silent) setFontLoaderDefaults(completeConfig) return completeConfig } diff --git a/packages/next/src/telemetry/deteched-flush.ts b/packages/next/src/telemetry/detached-flush.ts similarity index 91% rename from packages/next/src/telemetry/deteched-flush.ts rename to packages/next/src/telemetry/detached-flush.ts index 2d66cd18e0bf8..591a3443d5b0a 100644 --- a/packages/next/src/telemetry/deteched-flush.ts +++ b/packages/next/src/telemetry/detached-flush.ts @@ -20,7 +20,13 @@ import { PHASE_DEVELOPMENT_SERVER } from '../shared/lib/constants' } dir = getProjectDir(dir) - const config = await loadConfig(PHASE_DEVELOPMENT_SERVER, dir) + const config = await loadConfig( + PHASE_DEVELOPMENT_SERVER, + dir, + undefined, + undefined, + true + ) const distDir = path.join(dir, config.distDir || '.next') const eventsPath = path.join(distDir, '_events.json') diff --git a/packages/next/src/telemetry/storage.ts b/packages/next/src/telemetry/storage.ts index e5281f1969b4d..c5645ea2ad6be 100644 --- a/packages/next/src/telemetry/storage.ts +++ b/packages/next/src/telemetry/storage.ts @@ -247,7 +247,7 @@ export class Telemetry { JSON.stringify(allEvents) ) - spawn(process.execPath, [require.resolve('./deteched-flush'), mode, dir], { + spawn(process.execPath, [require.resolve('./detached-flush'), mode, dir], { detached: !this.NEXT_TELEMETRY_DEBUG, windowsHide: true, shell: false, diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 6c4e3f0ce8732..64ae8a5103a40 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "13.1.5-canary.1", + "version": "13.1.5-canary.2", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index eda87ab091d82..863f1a3115279 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "13.1.5-canary.1", + "version": "13.1.5-canary.2", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ac85086a6d933..8e9a5f4204e86 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -442,7 +442,7 @@ importers: packages/eslint-config-next: specifiers: - '@next/eslint-plugin-next': 13.1.5-canary.1 + '@next/eslint-plugin-next': 13.1.5-canary.2 '@rushstack/eslint-patch': ^1.1.3 '@typescript-eslint/parser': ^5.42.0 eslint: ^7.23.0 || ^8.0.0 @@ -514,12 +514,12 @@ importers: '@hapi/accept': 5.0.2 '@napi-rs/cli': 2.13.3 '@napi-rs/triples': 1.1.0 - '@next/env': 13.1.5-canary.1 - '@next/polyfill-module': 13.1.5-canary.1 - '@next/polyfill-nomodule': 13.1.5-canary.1 - '@next/react-dev-overlay': 13.1.5-canary.1 - '@next/react-refresh-utils': 13.1.5-canary.1 - '@next/swc': 13.1.5-canary.1 + '@next/env': 13.1.5-canary.2 + '@next/polyfill-module': 13.1.5-canary.2 + '@next/polyfill-nomodule': 13.1.5-canary.2 + '@next/react-dev-overlay': 13.1.5-canary.2 + '@next/react-refresh-utils': 13.1.5-canary.2 + '@next/swc': 13.1.5-canary.2 '@segment/ajv-human-errors': 2.1.2 '@swc/helpers': 0.4.14 '@taskr/clear': 1.1.0 diff --git a/test/e2e/app-dir/app/index.test.ts b/test/e2e/app-dir/app/index.test.ts index 3df9b4b1a939e..b9ff9f6bba433 100644 --- a/test/e2e/app-dir/app/index.test.ts +++ b/test/e2e/app-dir/app/index.test.ts @@ -2,6 +2,7 @@ import { createNextDescribe } from 'e2e-utils' import crypto from 'crypto' import { check, getRedboxHeader, hasRedbox, waitFor } from 'next-test-utils' import cheerio from 'cheerio' +import stripAnsi from 'strip-ansi' createNextDescribe( 'app dir', @@ -15,6 +16,22 @@ createNextDescribe( }, }, ({ next, isNextDev: isDev, isNextStart, isNextDeploy }) => { + if (isDev) { + it('should not have duplicate config warnings', async () => { + await next.fetch('/') + expect( + stripAnsi(next.cliOutput).match( + /You have enabled experimental feature/g + ).length + ).toBe(1) + expect( + stripAnsi(next.cliOutput).match( + /Experimental features are not covered by semver/g + ).length + ).toBe(1) + }) + } + if (!isNextDeploy) { it('should not share edge workers', async () => { const controller1 = new AbortController()