diff --git a/packages/next/amp.js b/packages/next/amp.js index 9c3c257022..882ccb7998 100644 --- a/packages/next/amp.js +++ b/packages/next/amp.js @@ -1 +1,4 @@ -module.exports = require('./dist/shared/lib/amp') +module.exports = + process.env.NEXT_RUNTIME === 'edge' + ? require('./dist/esm/shared/lib/amp') + : require('./dist/shared/lib/amp') diff --git a/packages/next/app.js b/packages/next/app.js index 5437bb67cc..b51ec15930 100644 --- a/packages/next/app.js +++ b/packages/next/app.js @@ -1 +1,4 @@ -module.exports = require('./dist/pages/_app') +module.exports = + process.env.NEXT_RUNTIME === 'edge' + ? require('./dist/esm/pages/_app') + : require('./dist/pages/_app') diff --git a/packages/next/build/entries.ts b/packages/next/build/entries.ts index 6b0a6e0a39..2419462029 100644 --- a/packages/next/build/entries.ts +++ b/packages/next/build/entries.ts @@ -219,6 +219,7 @@ export function getAppEntry(opts: { appDir: string appPaths: string[] | null pageExtensions: string[] + nextRuntime: string }) { return { import: `next-app-loader?${stringify(opts)}!`, @@ -455,6 +456,7 @@ export async function createEntrypoints(params: CreateEntrypointsParams) { appDir, appPaths: matchedAppPaths, pageExtensions, + nextRuntime: 'nodejs', }) } else if (isTargetLikeServerless(target)) { if (page !== '/_app' && page !== '/_document') { @@ -479,6 +481,7 @@ export async function createEntrypoints(params: CreateEntrypointsParams) { appDir: appDir!, appPaths: matchedAppPaths, pageExtensions, + nextRuntime: 'edge', }).import } diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 2b1b48aa25..83a06739b6 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -180,11 +180,9 @@ export function getDefineEnv({ }), // TODO: enforce `NODE_ENV` on `process.env`, and add a test: 'process.env.NODE_ENV': JSON.stringify(dev ? 'development' : 'production'), - ...((isNodeServer || isEdgeServer) && { - 'process.env.NEXT_RUNTIME': JSON.stringify( - isEdgeServer ? 'edge' : 'nodejs' - ), - }), + 'process.env.NEXT_RUNTIME': JSON.stringify( + isEdgeServer ? 'edge' : isNodeServer ? 'nodejs' : undefined + ), 'process.env.__NEXT_MIDDLEWARE_MATCHERS': JSON.stringify( middlewareMatchers || [] ), @@ -795,7 +793,7 @@ export default async function getBaseWebpackConfig( return prev }, [] as string[]) : []), - 'next/dist/pages/_app.js', + isEdgeServer ? 'next/dist/esm/pages/_app.js' : 'next/dist/pages/_app.js', ] customAppAliases[`${PAGES_DIR_ALIAS}/_error`] = [ ...(pagesDir @@ -804,7 +802,9 @@ export default async function getBaseWebpackConfig( return prev }, [] as string[]) : []), - 'next/dist/pages/_error.js', + isEdgeServer + ? 'next/dist/esm/pages/_error.js' + : 'next/dist/pages/_error.js', ] customDocumentAliases[`${PAGES_DIR_ALIAS}/_document`] = [ ...(pagesDir @@ -813,7 +813,9 @@ export default async function getBaseWebpackConfig( return prev }, [] as string[]) : []), - `next/dist/pages/_document.js`, + isEdgeServer + ? `next/dist/esm/pages/_document.js` + : `next/dist/pages/_document.js`, ] } diff --git a/packages/next/build/webpack/loaders/next-app-loader.ts b/packages/next/build/webpack/loaders/next-app-loader.ts index 473ded8310..dd6cb13134 100644 --- a/packages/next/build/webpack/loaders/next-app-loader.ts +++ b/packages/next/build/webpack/loaders/next-app-loader.ts @@ -120,8 +120,9 @@ const nextAppLoader: webpack.LoaderDefinitionFunction<{ appDir: string appPaths: string[] | null pageExtensions: string[] + nextRuntime: string }> = async function nextAppLoader() { - const { name, appDir, appPaths, pagePath, pageExtensions } = + const { name, appDir, appPaths, pagePath, pageExtensions, nextRuntime } = this.getOptions() || {} const buildInfo = getModuleBuildInfo((this as any)._module) @@ -179,23 +180,24 @@ const nextAppLoader: webpack.LoaderDefinitionFunction<{ resolveParallelSegments, }) + const rootDistFolder = nextRuntime === 'edge' ? 'next/dist/esm' : 'next/dist' const result = ` export ${treeCode} - export const AppRouter = require('next/dist/client/components/app-router.client.js').default - export const LayoutRouter = require('next/dist/client/components/layout-router.client.js').default - export const RenderFromTemplateContext = require('next/dist/client/components/render-from-template-context.client.js').default + export const AppRouter = require('${rootDistFolder}/client/components/app-router.client.js').default + export const LayoutRouter = require('${rootDistFolder}/client/components/layout-router.client.js').default + export const RenderFromTemplateContext = require('${rootDistFolder}/client/components/render-from-template-context.client.js').default export const HotReloader = ${ // Disable HotReloader component in production this.mode === 'development' - ? `require('next/dist/client/components/hot-reloader.client.js').default` + ? `require('${rootDistFolder}/client/components/hot-reloader.client.js').default` : 'null' } - export const staticGenerationAsyncStorage = require('next/dist/client/components/static-generation-async-storage.js').staticGenerationAsyncStorage - export const requestAsyncStorage = require('next/dist/client/components/request-async-storage.js').requestAsyncStorage + export const staticGenerationAsyncStorage = require('${rootDistFolder}/client/components/static-generation-async-storage.js').staticGenerationAsyncStorage + export const requestAsyncStorage = require('${rootDistFolder}/client/components/request-async-storage.js').requestAsyncStorage - export const serverHooks = require('next/dist/client/components/hooks-server-context.js') + export const serverHooks = require('${rootDistFolder}/client/components/hooks-server-context.js') export const renderToReadableStream = require('next/dist/compiled/react-server-dom-webpack/writer.browser.server').renderToReadableStream export const __next_app_webpack_require__ = __webpack_require__ diff --git a/packages/next/build/webpack/loaders/next-edge-ssr-loader/index.ts b/packages/next/build/webpack/loaders/next-edge-ssr-loader/index.ts index a04f5c9979..19d649f508 100644 --- a/packages/next/build/webpack/loaders/next-edge-ssr-loader/index.ts +++ b/packages/next/build/webpack/loaders/next-edge-ssr-loader/index.ts @@ -18,6 +18,18 @@ export type EdgeSSRLoaderQuery = { hasFontLoaders: boolean } +/* +For pages SSR'd at the edge, we bundle them with the ESM version of Next in order to +benefit from the better tree-shaking and thus, smaller bundle sizes. + +The absolute paths for _app, _error and _document, used in this loader, link to the regular CJS modules. +They are generated in `createPagesMapping` where we don't have access to `isEdgeRuntime`, +so we have to do it here. It's not that bad because it keeps all references to ESM modules magic in this place. +*/ +function swapDistFolderWithEsmDistFolder(path: string) { + return path.replace('next/dist/pages', 'next/dist/esm/pages') +} + export default async function edgeSSRLoader(this: any) { const { dev, @@ -54,9 +66,18 @@ export default async function edgeSSRLoader(this: any) { } const stringifiedPagePath = stringifyRequest(this, absolutePagePath) - const stringifiedAppPath = stringifyRequest(this, absoluteAppPath) - const stringifiedErrorPath = stringifyRequest(this, absoluteErrorPath) - const stringifiedDocumentPath = stringifyRequest(this, absoluteDocumentPath) + const stringifiedAppPath = stringifyRequest( + this, + swapDistFolderWithEsmDistFolder(absoluteAppPath) + ) + const stringifiedErrorPath = stringifyRequest( + this, + swapDistFolderWithEsmDistFolder(absoluteErrorPath) + ) + const stringifiedDocumentPath = stringifyRequest( + this, + swapDistFolderWithEsmDistFolder(absoluteDocumentPath) + ) const stringified500Path = absolute500Path ? stringifyRequest(this, absolute500Path) : null @@ -67,8 +88,8 @@ export default async function edgeSSRLoader(this: any) { )}` const transformed = ` - import { adapter, enhanceGlobals } from 'next/dist/server/web/adapter' - import { getRender } from 'next/dist/build/webpack/loaders/next-edge-ssr-loader/render' + import { adapter, enhanceGlobals } from 'next/dist/esm/server/web/adapter' + import { getRender } from 'next/dist/esm/build/webpack/loaders/next-edge-ssr-loader/render' enhanceGlobals() @@ -77,7 +98,7 @@ export default async function edgeSSRLoader(this: any) { isAppDir ? ` const Document = null - const appRenderToHTML = require('next/dist/server/app-render').renderToHTMLOrFlight + const appRenderToHTML = require('next/dist/esm/server/app-render').renderToHTMLOrFlight const pagesRenderToHTML = null const pageMod = require(${JSON.stringify(pageModPath)}) const appMod = null @@ -87,7 +108,7 @@ export default async function edgeSSRLoader(this: any) { : ` const Document = require(${stringifiedDocumentPath}).default const appRenderToHTML = null - const pagesRenderToHTML = require('next/dist/server/render').renderToHTML + const pagesRenderToHTML = require('next/dist/esm/server/render').renderToHTML const pageMod = require(${stringifiedPagePath}) const appMod = require(${stringifiedAppPath}) const errorMod = require(${stringifiedErrorPath}) diff --git a/packages/next/build/webpack/loaders/next-edge-ssr-loader/render.ts b/packages/next/build/webpack/loaders/next-edge-ssr-loader/render.ts index 23c175a5a7..6210f458c7 100644 --- a/packages/next/build/webpack/loaders/next-edge-ssr-loader/render.ts +++ b/packages/next/build/webpack/loaders/next-edge-ssr-loader/render.ts @@ -1,4 +1,5 @@ import type { NextConfig } from '../../../../server/config-shared' + import type { DocumentType, AppType } from '../../../../shared/lib/utils' import type { BuildManifest } from '../../../../server/get-page-files' import type { ReactLoadableManifest } from '../../../../server/load-components' diff --git a/packages/next/build/webpack/plugins/flight-client-entry-plugin.ts b/packages/next/build/webpack/plugins/flight-client-entry-plugin.ts index e308354789..16d60c3a0b 100644 --- a/packages/next/build/webpack/plugins/flight-client-entry-plugin.ts +++ b/packages/next/build/webpack/plugins/flight-client-entry-plugin.ts @@ -307,9 +307,19 @@ export class FlightClientEntryPlugin { modules: clientComponentImports, server: false, } - const clientLoader = `next-flight-client-entry-loader?${stringify( - loaderOptions - )}!` + + // For the client entry, we always use the CJS build of Next.js. If the + // server is using the ESM build (when using the Edge runtime), we need to + // replace them. + const clientLoader = `next-flight-client-entry-loader?${stringify({ + modules: this.isEdgeServer + ? clientComponentImports.map((importPath) => + importPath.replace('next/dist/esm/', 'next/dist/') + ) + : clientComponentImports, + server: false, + })}!` + const clientSSRLoader = `next-flight-client-entry-loader?${stringify({ ...loaderOptions, server: true, diff --git a/packages/next/build/webpack/plugins/flight-manifest-plugin.ts b/packages/next/build/webpack/plugins/flight-manifest-plugin.ts index fe8f55fb22..fb09198806 100644 --- a/packages/next/build/webpack/plugins/flight-manifest-plugin.ts +++ b/packages/next/build/webpack/plugins/flight-manifest-plugin.ts @@ -56,6 +56,9 @@ export type FlightManifest = { __ssr_module_mapping__: { [moduleId: string]: ManifestNode } + __edge_ssr_module_mapping__: { + [moduleId: string]: ManifestNode + } } & { [modulePath: string]: ManifestNode } @@ -141,6 +144,7 @@ export class FlightManifestPlugin { ) { const manifest: FlightManifest = { __ssr_module_mapping__: {}, + __edge_ssr_module_mapping__: {}, } const dev = this.dev const fontLoaderTargets = this.fontLoaderTargets @@ -196,6 +200,7 @@ export class FlightManifestPlugin { const moduleExports = manifest[resource] || {} const moduleIdMapping = manifest.__ssr_module_mapping__ + const edgeModuleIdMapping = manifest.__edge_ssr_module_mapping__ // Note that this isn't that reliable as webpack is still possible to assign // additional queries to make sure there's no conflict even using the `named` @@ -304,10 +309,25 @@ export class FlightManifestPlugin { ...moduleExports[name], id: ssrNamedModuleId, } + + edgeModuleIdMapping[id] = edgeModuleIdMapping[id] || {} + edgeModuleIdMapping[id][name] = { + ...moduleExports[name], + id: ssrNamedModuleId.replace(/\/next\/dist\//, '/next/dist/esm/'), + } }) manifest[resource] = moduleExports + + // The client compiler will always use the CJS Next.js build, so here we + // also add the mapping for the ESM build (Edge runtime) to consume. + if (/\/next\/dist\//.test(resource)) { + manifest[resource.replace(/\/next\/dist\//, '/next/dist/esm/')] = + moduleExports + } + manifest.__ssr_module_mapping__ = moduleIdMapping + manifest.__edge_ssr_module_mapping__ = edgeModuleIdMapping } chunkGroup.chunks.forEach((chunk: webpack.Chunk) => { diff --git a/packages/next/build/webpack/plugins/telemetry-plugin.ts b/packages/next/build/webpack/plugins/telemetry-plugin.ts index 2580ba8a41..d81e7e64cf 100644 --- a/packages/next/build/webpack/plugins/telemetry-plugin.ts +++ b/packages/next/build/webpack/plugins/telemetry-plugin.ts @@ -110,11 +110,15 @@ function findFeatureInModule(module: Module): Feature | undefined { * dependency. */ function findUniqueOriginModulesInConnections( - connections: Connection[] + connections: Connection[], + originModule: Module ): Set { const originModules = new Set() for (const connection of connections) { - if (!originModules.has(connection.originModule)) { + if ( + !originModules.has(connection.originModule) && + connection.originModule !== originModule + ) { originModules.add(connection.originModule) } } @@ -161,8 +165,10 @@ export class TelemetryPlugin implements webpack.WebpackPluginInstance { const connections = ( compilation as any ).moduleGraph.getIncomingConnections(module) - const originModules = - findUniqueOriginModulesInConnections(connections) + const originModules = findUniqueOriginModulesInConnections( + connections, + module + ) this.usageTracker.get(feature)!.invocationCount = originModules.size } diff --git a/packages/next/client.js b/packages/next/client.js index ff71a4ae0c..3f049f0bd0 100644 --- a/packages/next/client.js +++ b/packages/next/client.js @@ -1 +1,4 @@ -module.exports = require('./dist/client/index') +module.exports = + process.env.NEXT_RUNTIME === 'edge' + ? require('./dist/esm/client/index') + : require('./dist/client/index') diff --git a/packages/next/config.js b/packages/next/config.js index 2da980d8b0..bc591fa891 100644 --- a/packages/next/config.js +++ b/packages/next/config.js @@ -1 +1,4 @@ -module.exports = require('./dist/shared/lib/runtime-config') +module.exports = + process.env.NEXT_RUNTIME === 'edge' + ? require('./dist/esm/shared/lib/runtime-config') + : require('./dist/shared/lib/runtime-config') diff --git a/packages/next/constants.js b/packages/next/constants.js index 6e69010993..cea2032c0f 100644 --- a/packages/next/constants.js +++ b/packages/next/constants.js @@ -1 +1,4 @@ -module.exports = require('./dist/shared/lib/constants') +module.exports = + process.env.NEXT_RUNTIME === 'edge' + ? require('./dist/esm/shared/lib/constants') + : require('./dist/shared/lib/constants') diff --git a/packages/next/document.js b/packages/next/document.js index 5741035f38..22296a77bb 100644 --- a/packages/next/document.js +++ b/packages/next/document.js @@ -1 +1,4 @@ -module.exports = require('./dist/pages/_document') +module.exports = + process.env.NEXT_RUNTIME === 'edge' + ? require('./dist/esm/pages/_document') + : require('./dist/pages/_document') diff --git a/packages/next/dynamic.js b/packages/next/dynamic.js index e2956e5f40..e9848e7f0d 100644 --- a/packages/next/dynamic.js +++ b/packages/next/dynamic.js @@ -1 +1,4 @@ -module.exports = require('./dist/shared/lib/dynamic') +module.exports = + process.env.NEXT_RUNTIME === 'edge' + ? require('./dist/esm/shared/lib/dynamic') + : require('./dist/shared/lib/dynamic') diff --git a/packages/next/error.js b/packages/next/error.js index 899cd04662..653e9316b7 100644 --- a/packages/next/error.js +++ b/packages/next/error.js @@ -1 +1,4 @@ -module.exports = require('./dist/pages/_error') +module.exports = + process.env.NEXT_RUNTIME === 'edge' + ? require('./dist/esm/pages/_error') + : require('./dist/pages/_error') diff --git a/packages/next/head.js b/packages/next/head.js index 71758fdbea..69e6800ae1 100644 --- a/packages/next/head.js +++ b/packages/next/head.js @@ -1 +1,4 @@ -module.exports = require('./dist/shared/lib/head') +module.exports = + process.env.NEXT_RUNTIME === 'edge' + ? require('./dist/esm/shared/lib/head') + : require('./dist/shared/lib/head') diff --git a/packages/next/image.js b/packages/next/image.js index a1de5ad698..eae3690cd1 100644 --- a/packages/next/image.js +++ b/packages/next/image.js @@ -1 +1,4 @@ -module.exports = require('./dist/client/image') +module.exports = + process.env.NEXT_RUNTIME === 'edge' + ? require('./dist/esm/client/image') + : require('./dist/client/image') diff --git a/packages/next/link.js b/packages/next/link.js index a37307be2e..d3c35c1ca5 100644 --- a/packages/next/link.js +++ b/packages/next/link.js @@ -1 +1,4 @@ -module.exports = require('./dist/client/link') +module.exports = + process.env.NEXT_RUNTIME === 'edge' + ? require('./dist/esm/client/link') + : require('./dist/client/link') diff --git a/packages/next/pages/_app.tsx b/packages/next/pages/_app.tsx index c646d0842f..4d83e27592 100644 --- a/packages/next/pages/_app.tsx +++ b/packages/next/pages/_app.tsx @@ -1,6 +1,6 @@ import React from 'react' -import { - loadGetInitialProps, + +import type { AppContextType, AppInitialProps, AppPropsType, @@ -9,6 +9,8 @@ import { } from '../shared/lib/utils' import type { Router } from '../client/router' +import { loadGetInitialProps } from '../shared/lib/utils' + export { AppInitialProps, AppType } export { NextWebVitalsMetric } diff --git a/packages/next/router.js b/packages/next/router.js index afdc8f9ad2..9b8d7bbbe2 100644 --- a/packages/next/router.js +++ b/packages/next/router.js @@ -1 +1,4 @@ -module.exports = require('./dist/client/router') +module.exports = + process.env.NEXT_RUNTIME === 'edge' + ? require('./dist/esm/client/router') + : require('./dist/client/router') diff --git a/packages/next/script.js b/packages/next/script.js index 4e0f885ac6..6d257fa56f 100644 --- a/packages/next/script.js +++ b/packages/next/script.js @@ -1 +1,4 @@ -module.exports = require('./dist/client/script') +module.exports = + process.env.NEXT_RUNTIME === 'edge' + ? require('./dist/esm/client/script') + : require('./dist/client/script') diff --git a/packages/next/server/app-render.tsx b/packages/next/server/app-render.tsx index 5b8d910235..df2c0bf075 100644 --- a/packages/next/server/app-render.tsx +++ b/packages/next/server/app-render.tsx @@ -258,7 +258,10 @@ function useFlightResponse( const [renderStream, forwardStream] = readableStreamTee(req) const res = createFromReadableStream(renderStream, { - moduleMap: serverComponentManifest.__ssr_module_mapping__, + moduleMap: + process.env.NEXT_RUNTIME === 'edge' + ? serverComponentManifest.__edge_ssr_module_mapping__ + : serverComponentManifest.__ssr_module_mapping__, }) flightResponseRef.current = res @@ -270,7 +273,7 @@ function useFlightResponse( ? `` writer.write(encodeText(scripts)) - process() + read() } }) } - process() + read() return res } diff --git a/packages/next/server/dev/hot-reloader.ts b/packages/next/server/dev/hot-reloader.ts index cdf1c7c009..6a92fe1a1d 100644 --- a/packages/next/server/dev/hot-reloader.ts +++ b/packages/next/server/dev/hot-reloader.ts @@ -626,6 +626,7 @@ export default class HotReloader { ), appDir: this.appDir!, pageExtensions: this.config.pageExtensions, + nextRuntime: 'edge', }).import : undefined @@ -705,6 +706,7 @@ export default class HotReloader { ), appDir: this.appDir!, pageExtensions: this.config.pageExtensions, + nextRuntime: 'nodejs', }) : relativeRequest, appDir: this.config.experimental.appDir, diff --git a/packages/next/taskfile-swc.js b/packages/next/taskfile-swc.js index bf61332c31..ea4bcf40dd 100644 --- a/packages/next/taskfile-swc.js +++ b/packages/next/taskfile-swc.js @@ -18,6 +18,7 @@ module.exports = function (task) { stripExtension, keepImportAssertions = false, interopClientDefaultExport = false, + esm = false, } = {} ) { // Don't compile .d.ts @@ -28,7 +29,7 @@ module.exports = function (task) { /** @type {import('@swc/core').Options} */ const swcClientOptions = { module: { - type: 'commonjs', + type: esm ? 'es6' : 'commonjs', ignoreDynamic: true, }, jsc: { @@ -59,7 +60,7 @@ module.exports = function (task) { /** @type {import('@swc/core').Options} */ const swcServerOptions = { module: { - type: 'commonjs', + type: esm ? 'es6' : 'commonjs', ignoreDynamic: true, }, env: { @@ -126,7 +127,7 @@ module.exports = function (task) { } if (output.map) { - if (interopClientDefaultExport) { + if (interopClientDefaultExport && !esm) { output.code += ` if ((typeof exports.default === 'function' || (typeof exports.default === 'object' && exports.default !== null)) && typeof exports.default.__esModule === 'undefined') { Object.defineProperty(exports.default, '__esModule', { value: true }); diff --git a/packages/next/taskfile.js b/packages/next/taskfile.js index a34f69e525..d2c8b5defe 100644 --- a/packages/next/taskfile.js +++ b/packages/next/taskfile.js @@ -1946,16 +1946,23 @@ export async function compile(task, opts) { 'cli', 'bin', 'server', + 'server_esm', 'nextbuild', 'nextbuildjest', 'nextbuildstatic', + 'nextbuild_esm', 'pages', + 'pages_esm', 'lib', + 'lib_esm', 'client', + 'client_esm', 'telemetry', 'trace', 'shared', + 'shared_esm', 'shared_re_exported', + 'shared_re_exported_esm', 'server_wasm', // we compile this each time so that fresh runtime data is pulled // before each publish @@ -1990,6 +1997,14 @@ export async function lib(task, opts) { notify('Compiled lib files') } +export async function lib_esm(task, opts) { + await task + .source(opts.src || 'lib/**/*.+(js|ts|tsx)') + .swc('server', { dev: opts.dev, esm: true }) + .target('dist/esm/lib') + notify('Compiled lib files') +} + export async function server(task, opts) { await task .source(opts.src || 'server/**/*.+(js|ts|tsx)') @@ -2004,6 +2019,14 @@ export async function server(task, opts) { notify('Compiled server files') } +export async function server_esm(task, opts) { + await task + .source(opts.src || 'server/**/*.+(js|ts|tsx)') + .swc('server', { dev: opts.dev, esm: true }) + .target('dist/esm/server') + notify('Compiled server files to ESM') +} + export async function nextbuild(task, opts) { await task .source(opts.src || 'build/**/*.+(js|ts|tsx)', { @@ -2014,6 +2037,16 @@ export async function nextbuild(task, opts) { notify('Compiled build files') } +export async function nextbuild_esm(task, opts) { + await task + .source(opts.src || 'build/**/*.+(js|ts|tsx)', { + ignore: ['**/fixture/**', '**/tests/**', '**/jest/**'], + }) + .swc('server', { dev: opts.dev, esm: true }) + .target('dist/esm/build') + notify('Compiled build files to ESM') +} + export async function nextbuildjest(task, opts) { await task .source(opts.src || 'build/jest/**/*.+(js|ts|tsx)', { @@ -2032,6 +2065,14 @@ export async function client(task, opts) { notify('Compiled client files') } +export async function client_esm(task, opts) { + await task + .source(opts.src || 'client/**/*.+(js|ts|tsx)') + .swc('client', { dev: opts.dev, esm: true }) + .target('dist/esm/client') + notify('Compiled client files to ESM') +} + // export is a reserved keyword for functions export async function nextbuildstatic(task, opts) { await task @@ -2062,10 +2103,38 @@ export async function pages_document(task, opts) { .target('dist/pages') } +export async function pages_app_esm(task, opts) { + await task + .source('pages/_app.tsx') + .swc('client', { dev: opts.dev, keepImportAssertions: true, esm: true }) + .target('dist/esm/pages') +} + +export async function pages_error_esm(task, opts) { + await task + .source('pages/_error.tsx') + .swc('client', { dev: opts.dev, keepImportAssertions: true, esm: true }) + .target('dist/esm/pages') +} + +export async function pages_document_esm(task, opts) { + await task + .source('pages/_document.tsx') + .swc('server', { dev: opts.dev, keepImportAssertions: true, esm: true }) + .target('dist/esm/pages') +} + export async function pages(task, opts) { await task.parallel(['pages_app', 'pages_error', 'pages_document'], opts) } +export async function pages_esm(task, opts) { + await task.parallel( + ['pages_app_esm', 'pages_error_esm', 'pages_document_esm'], + opts + ) +} + export async function telemetry(task, opts) { await task .source(opts.src || 'telemetry/**/*.+(js|ts|tsx)') @@ -2093,11 +2162,15 @@ export default async function (task) { await task.watch('bin/*', 'bin', opts) await task.watch('pages/**/*.+(js|ts|tsx)', 'pages', opts) await task.watch('server/**/*.+(js|ts|tsx)', 'server', opts) + await task.watch('server/**/*.+(js|ts|tsx)', 'server_esm', opts) await task.watch('build/**/*.+(js|ts|tsx)', 'nextbuild', opts) + await task.watch('build/**/*.+(js|ts|tsx)', 'nextbuild_esm', opts) await task.watch('build/jest/**/*.+(js|ts|tsx)', 'nextbuildjest', opts) await task.watch('export/**/*.+(js|ts|tsx)', 'nextbuildstatic', opts) await task.watch('client/**/*.+(js|ts|tsx)', 'client', opts) + await task.watch('client/**/*.+(js|ts|tsx)', 'client_esm', opts) await task.watch('lib/**/*.+(js|ts|tsx)', 'lib', opts) + await task.watch('lib/**/*.+(js|ts|tsx)', 'lib_esm', opts) await task.watch('cli/**/*.+(js|ts|tsx)', 'cli', opts) await task.watch('telemetry/**/*.+(js|ts|tsx)', 'telemetry', opts) await task.watch('trace/**/*.+(js|ts|tsx)', 'trace', opts) @@ -2111,6 +2184,16 @@ export default async function (task) { 'shared', opts ) + await task.watch( + 'shared/**/!(amp|config|constants|dynamic|head).+(js|ts|tsx)', + 'shared_esm', + opts + ) + await task.watch( + 'shared/lib/{amp,config,constants,dynamic,head}.+(js|ts|tsx)', + 'shared_re_exported_esm', + opts + ) await task.watch('server/**/*.+(wasm)', 'server_wasm', opts) await task.watch( '../react-dev-overlay/dist/**/*.js', @@ -2130,6 +2213,16 @@ export async function shared(task, opts) { notify('Compiled shared files') } +export async function shared_esm(task, opts) { + await task + .source( + opts.src || 'shared/**/!(amp|config|constants|dynamic|head).+(js|ts|tsx)' + ) + .swc('client', { dev: opts.dev, esm: true }) + .target('dist/esm/shared') + notify('Compiled shared files to ESM') +} + export async function shared_re_exported(task, opts) { await task .source( @@ -2141,6 +2234,19 @@ export async function shared_re_exported(task, opts) { notify('Compiled shared re-exported files') } +export async function shared_re_exported_esm(task, opts) { + await task + .source( + opts.src || 'shared/**/{amp,config,constants,dynamic,head}.+(js|ts|tsx)' + ) + .swc('client', { + dev: opts.dev, + esm: true, + }) + .target('dist/esm/shared') + notify('Compiled shared re-exported files as ESM') +} + export async function server_wasm(task, opts) { await task.source(opts.src || 'server/**/*.+(wasm)').target('dist/server') notify('Moved server wasm files')