Repository: remix-run/remix
Pull request #4841 (2022-12-12 23:03:56)

feat(remix-dev): deprecate `serverBuildTarget`
As discussed in the second roadmap livestream

---

Closes #3556

changeset-bot[bot]: ###  ⚠️  No Changeset found

Latest commit: 60d523ba44fac673a9f1db0c1716093b5fd5b6ae

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**

<details><summary>This PR includes no changesets</summary>

  When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

</details>

[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/master/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/MichaelDeBoey/remix/new/deprecate-serverBuildTarget?filename=.changeset/giant-seahorses-shake.md&value=---%0A%22remix%22%3A%20patch%0A%22%40remix-run%2Fdev%22%3A%20patch%0A---%0A%0Afeat(remix-dev)%3A%20deprecate%20%60serverBuildTarget%60%0A)


jenseng: Between this and #4842 are we missing anything? I see there are some places where we key off of this in the compiler (e.g. [here](https://github.com/remix-run/remix/blob/3832d457b34d7a62633bf86a2606971263e710cb/packages/remix-dev/compiler/plugins/serverBareModulesPlugin.ts#L24)), do we need additional config to support this behavior?
MichaelDeBoey: @jenseng Good call!
That's indeed something we need to figure out in some other way 🤔

Listing all the usages:

- https://github.com/remix-run/remix/blob/6a6fa5911e09667c1788451512956ba636aca043/packages/remix-dev/compiler/compilerServer.ts#L45-L48
- https://github.com/remix-run/remix/blob/6a6fa5911e09667c1788451512956ba636aca043/packages/remix-dev/compiler/plugins/serverBareModulesPlugin.ts#L24
- https://github.com/remix-run/remix/blob/6a6fa5911e09667c1788451512956ba636aca043/packages/remix-dev/compiler/plugins/serverBareModulesPlugin.ts#L95-L101
- https://github.com/remix-run/remix/blob/6a6fa5911e09667c1788451512956ba636aca043/packages/remix-dev/compiler/plugins/serverBareModulesPlugin.ts#L116-L117
MichaelDeBoey: @Harmony7 mentioned the same problem in #4860 regarding not being able to fully deprecate `serverBuildtarget`

> This PR is necessary because, except for the first two subitems in the list above, these behaviors cannot be set through `remix.config.js`.
mcansh: bundling everything should be achievable using `serverDependenciesToBundle: /.*/`
MichaelDeBoey: @mcansh So how do you think that would that look like?
Creating new `serverConditions`, `serverMinify` & `serverMainFields` config options?
mjackson: > new serverConditions, serverMinify & serverMainFields config options

Yeah, @MichaelDeBoey. I think we will need these.

> If so, I would suggest to go with a server object instead, to not pollute the global config namespace.

No, let's keep the config object as flat as possible.
MichaelDeBoey: @mjackson I introduced the `serverConditions`, `serverMinify` & `serverMainFields` config options and updated `serverDependenciesToBundle` so that it can also receive `"all"` as value.

The only places where we're now still using `serverBuildTarget` is in `serverBareModulesPlugin`:
- https://github.com/remix-run/remix/blob/6a6fa5911e09667c1788451512956ba636aca043/packages/remix-dev/compiler/plugins/serverBareModulesPlugin.ts#L24-L37
- https://github.com/remix-run/remix/blob/6a6fa5911e09667c1788451512956ba636aca043/packages/remix-dev/compiler/plugins/serverBareModulesPlugin.ts#L116-L117

Can't think of a good way to remove usage here though 🤔

Patch:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 3743151e3..c5ecd3f44 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -21,7 +21,7 @@ jobs:
       !contains(github.ref, 'nightly')
     runs-on: ubuntu-latest
     outputs:
-      published_packages: ${{ steps.changesets.outputs.published_packages }}
+      published_packages: ${{ steps.changesets.outputs.publishedPackages }}
       published: ${{ steps.changesets.outputs.published }}
     steps:
       - name: 🛑 Cancel Previous Runs
@@ -90,8 +90,8 @@ jobs:
           package_version=$(node ./scripts/release/find-release-from-changeset.js)
           echo "package_version=${package_version}" >> $GITHUB_OUTPUT
         env:
-          package_version_to_follow: "remix"
-          published_packages: ${{ needs.release.outputs.published_packages }}
+          PACKAGE_VERSION_TO_FOLLOW: "remix"
+          PUBLISHED_PACKAGES: ${{ needs.release.outputs.published_packages }}
 
   comment:
     name: 📝 Comment on related issues and pull requests
diff --git a/docs/file-conventions/remix-config.md b/docs/file-conventions/remix-config.md
index a37bc5b1b..3a975ed16 100644
--- a/docs/file-conventions/remix-config.md
+++ b/docs/file-conventions/remix-config.md
@@ -19,7 +19,6 @@ module.exports = {
     });
   },
   serverBuildPath: "build/index.js",
-  serverBuildTarget: "node-cjs",
 };
 ```
 
@@ -103,7 +102,8 @@ either a `.js` or `.ts` file extension.
 ## serverBuildDirectory
 
 <docs-warning>This option is deprecated and will likely be removed in a future
-stable release. Use [`serverBuildPath`][server-build-path] instead.</docs-warning>
+stable release. Use [`serverBuildPath`][server-build-path]
+instead.</docs-warning>
 
 The path to the server build, relative to `remix.config.js`. Defaults to
 "build". This needs to be deployed to your server.
@@ -111,13 +111,19 @@ The path to the server build, relative to `remix.config.js`. Defaults to
 ## serverBuildPath
 
 The path to the server build file, relative to `remix.config.js`. This file
-should end in a `.js` extension and should be deployed to your server.
-
-If omitted, the default build path will be based on your
-[`serverBuildTarget`][server-build-target].
+should end in a `.js` extension and should be deployed to your server. Defaults
+to `"build/index.js"`.
 
 ## serverBuildTarget
 
+<docs-warning>This option is deprecated and will likely be removed in a future
+stable release. Use a combination of [`publicPath`][public-path],
+[`serverBuildPath`][server-build-path], [`serverConditions`][server-conditions],
+[`serverDependenciesToBundle`][server-dependencies-to-bundle]
+[`serverMainFields`][server-main-fields], [`serverMinify`][server-minify],
+[`serverModuleFormat`][server-module-format] and/or
+[`serverPlatform`][server-platform] instead.</docs-warning>
+
 The target of the server build. Defaults to `"node-cjs"`.
 
 The `serverBuildTarget` can be one of the following:
@@ -130,11 +136,22 @@ The `serverBuildTarget` can be one of the following:
 - [`"node-cjs"`][node-cjs]
 - [`"vercel"`][vercel]
 
+## serverConditions
+
+The order of conditions to use when resolving server dependencies' `exports`
+field in `package.json`.
+
 ## serverDependenciesToBundle
 
-A list of regex patterns that determines if a module is transpiled and included in the server bundle. This can be useful when consuming ESM only packages in a CJS build, or when consuming packages with [CSS side-effect imports][css-side-effect-imports].
+A list of regex patterns that determines if a module is transpiled and included
+in the server bundle. This can be useful when consuming ESM only packages in a
+CJS build, or when consuming packages with [CSS side effect
+imports][css-side-effect-imports].
 
-For example, the `unified` ecosystem is all ESM-only. Let's also say we're using a `@sindresorhus/slugify` which is ESM-only as well. Here's how you would be able to consume those packages in a CJS app without having to use dynamic imports:
+For example, the `unified` ecosystem is all ESM-only. Let's also say we're using
+a `@sindresorhus/slugify` which is ESM-only as well. Here's how you would be
+able to consume those packages in a CJS app without having to use dynamic
+imports:
 
 ```ts filename=remix.config.js lines=[8-13]
 /** @type {import('@remix-run/dev').AppConfig} */
@@ -153,6 +170,29 @@ module.exports = {
 };
 ```
 
+If you want to bundle all server dependencies, you can set
+`serverDependenciesToBundle` to `"all"`.
+
+## serverMainFields
+
+The order of main fields to use when resolving server dependencies. Defaults to
+`["main", "module"]` when `serverModuleFormat` is set to `"cjs"`. Defaults to
+`["module", "main"]` when `serverModuleFormat` is set to `"esm"`.
+
+## serverMinify
+
+Whether to minify the server build in production or not. Defaults to `false`.
+
+## serverModuleFormat
+
+The output format of the server build, which can either be `"cjs"` or `"esm"`.
+Defaults to `"cjs"`.
+
+## serverPlatform
+
+The platform the server build is targeting, which can either be `"neutral"` or
+`"node"`. Defaults to `"node"`.
+
 ## watchPaths
 
 An array, string, or async function that defines custom directories, relative to the project root, to watch while running [remix dev][remix-dev]. These directories are in addition to [`appDirectory`][app-directory].
@@ -173,8 +213,14 @@ There are a few conventions that Remix uses you should be aware of.
 <docs-info>[Dilum Sanjaya][dilum-sanjaya] made [an awesome visualization][an-awesome-visualization] of how routes in the file system map to the URL in your app that might help you understand these conventions.</docs-info>
 
 [minimatch]: https://www.npmjs.com/package/minimatch
+[public-path]: #publicpath
 [server-build-path]: #serverbuildpath
-[server-build-target]: #serverbuildtarget
+[server-conditions]: #serverconditions
+[server-dependencies-to-bundle]: #serverdependenciestobundle
+[server-main-fields]: #servermainfields
+[server-minify]: #serverminify
+[server-module-format]: #servermoduleformat
+[server-platform]: #serverplatform
 [arc]: https://arc.codes
 [cloudflare-pages]: https://pages.cloudflare.com
 [cloudflare-workers]: https://workers.cloudflare.com
diff --git a/packages/remix-dev/compiler/compilerServer.ts b/packages/remix-dev/compiler/compilerServer.ts
index d0b995b2b..01bb2f1e2 100644
--- a/packages/remix-dev/compiler/compilerServer.ts
+++ b/packages/remix-dev/compiler/compilerServer.ts
@@ -45,11 +45,6 @@ const createEsbuildConfig = (
     };
   }
 
-  let isCloudflareRuntime = ["cloudflare-pages", "cloudflare-workers"].includes(
-    config.serverBuildTarget ?? ""
-  );
-  let isDenoRuntime = config.serverBuildTarget === "deno";
-
   let { mode } = options;
   let outputCss = false;
 
@@ -83,11 +78,7 @@ const createEsbuildConfig = (
     stdin,
     entryPoints,
     outfile: config.serverBuildPath,
-    conditions: isCloudflareRuntime
-      ? ["worker"]
-      : isDenoRuntime
-      ? ["deno", "worker"]
-      : undefined,
+    conditions: config.serverConditions,
     platform: config.serverPlatform,
     format: config.serverModuleFormat,
     treeShaking: true,
@@ -99,12 +90,8 @@ const createEsbuildConfig = (
     // PR makes dev mode behave closer to production in terms of dead
     // code elimination / tree shaking is concerned.
     minifySyntax: true,
-    minify: options.mode === "production" && isCloudflareRuntime,
-    mainFields: isCloudflareRuntime
-      ? ["browser", "module", "main"]
-      : config.serverModuleFormat === "esm"
-      ? ["module", "main"]
-      : ["main", "module"],
+    minify: options.mode === "production" && config.serverMinify,
+    mainFields: config.serverMainFields,
     target: options.target,
     loader: loaders,
     bundle: true,
diff --git a/packages/remix-dev/compiler/plugins/serverBareModulesPlugin.ts b/packages/remix-dev/compiler/plugins/serverBareModulesPlugin.ts
index e2c840cd8..8aaaa390d 100644
--- a/packages/remix-dev/compiler/plugins/serverBareModulesPlugin.ts
+++ b/packages/remix-dev/compiler/plugins/serverBareModulesPlugin.ts
@@ -22,12 +22,10 @@ export function serverBareModulesPlugin(
   remixConfig: RemixConfig,
   onWarning?: (warning: string, key: string) => void
 ): Plugin {
-  let isDenoRuntime = remixConfig.serverBuildTarget === "deno";
-
   // Resolve paths according to tsconfig paths property
-  let matchPath = isDenoRuntime
-    ? undefined
-    : createMatchPath(remixConfig.tsconfigPath);
+  let matchPath = remixConfig.tsconfigPath
+    ? createMatchPath(remixConfig.tsconfigPath)
+    : undefined;
   function resolvePath(id: string) {
     if (!matchPath) {
       return id;
@@ -103,12 +101,8 @@ export function serverBareModulesPlugin(
           }
         }
 
-        switch (remixConfig.serverBuildTarget) {
-          // Always bundle everything for cloudflare.
-          case "cloudflare-pages":
-          case "cloudflare-workers":
-          case "deno":
-            return undefined;
+        if (remixConfig.serverDependenciesToBundle === "all") {
+          return undefined;
         }
 
         for (let pattern of remixConfig.serverDependenciesToBundle) {
@@ -124,8 +118,7 @@ export function serverBareModulesPlugin(
           onWarning &&
           !isNodeBuiltIn(packageName) &&
           kind !== "dynamic-import" &&
-          (!remixConfig.serverBuildTarget ||
-            remixConfig.serverBuildTarget === "node-cjs")
+          remixConfig.serverPlatform === "node"
         ) {
           warnOnceIfEsmOnlyPackage(packageName, path, onWarning);
         }
diff --git a/packages/remix-dev/config.ts b/packages/remix-dev/config.ts
index 701e7a114..118f3cb6d 100644
--- a/packages/remix-dev/config.ts
+++ b/packages/remix-dev/config.ts
@@ -76,23 +76,6 @@ export interface AppConfig {
     defineRoutes: DefineRoutesFunction
   ) => Promise<ReturnType<DefineRoutesFunction>>;
 
-  /**
-   * The path to the server build, relative to `remix.config.js`. Defaults to
-   * "build".
-   *
-   * @deprecated Use {@link ServerConfig.serverBuildPath} instead.
-   */
-  serverBuildDirectory?: string;
-
-  /**
-   * The path to the server build file, relative to `remix.config.js`. This file
-   * should end in a `.js` extension and should be deployed to your server.
-   *
-   * If omitted, the default build path will be based on your
-   * {@link ServerConfig.serverBuildTarget}.
-   */
-  serverBuildPath?: string;
-
   /**
    * The path to the browser build, relative to `remix.config.js`. Defaults to
    * "public/build".
@@ -103,7 +86,7 @@ export interface AppConfig {
    * The path to the browser build, relative to remix.config.js. Defaults to
    * "public/build".
    *
-   * @deprecated Use `{@link ServerConfig.assetsBuildDirectory}` instead
+   * @deprecated Use `{@link AppConfig.assetsBuildDirectory}` instead
    */
   browserBuildDirectory?: string;
 
@@ -130,45 +113,79 @@ export interface AppConfig {
   mdx?: RemixMdxConfig | RemixMdxConfigFunction;
 
   /**
-   * The output format of the server build. Defaults to "cjs".
-   *
-   * @deprecated Use {@link ServerConfig.serverBuildTarget} instead.
+   * A server entrypoint, relative to the root directory that becomes your
+   * server's main module. If specified, Remix will compile this file along with
+   * your application into a single file to be deployed to your server. This
+   * file can use either a `.js` or `.ts` file extension.
    */
-  serverModuleFormat?: ServerModuleFormat;
+  server?: string;
 
   /**
-   * The platform the server build is targeting. Defaults to "node".
+   * The path to the server build, relative to `remix.config.js`. Defaults to
+   * "build".
    *
-   * @deprecated Use {@link ServerConfig.serverBuildTarget} instead.
+   * @deprecated Use {@link AppConfig.serverBuildPath} instead.
    */
-  serverPlatform?: ServerPlatform;
+  serverBuildDirectory?: string;
 
   /**
-   * The target of the server build. Defaults to "node-cjs".
+   * The path to the server build file, relative to `remix.config.js`. This file
+   * should end in a `.js` extension and should be deployed to your server.
    */
-  serverBuildTarget?: ServerBuildTarget;
+  serverBuildPath?: string;
 
   /**
-   * A server entrypoint, relative to the root directory that becomes your
-   * server's main module. If specified, Remix will compile this file along with
-   * your application into a single file to be deployed to your server. This
-   * file can use either a `.js` or `.ts` file extension.
+   * The target of the server build. Defaults to "node-cjs".
+   *
+   * @deprecated Use a combination of `{@link AppConfig.publicPath}`, `{@link AppConfig.serverBuildPath}`, `{@link AppConfig.serverConditions}`, `{@link AppConfig.serverDependenciesToBundle}`, `{@link AppConfig.serverMainFields}`, `{@link AppConfig.serverMinify}`, `{@link AppConfig.serverModuleFormat}` and/or `{@link AppConfig.serverPlatform}` instead.
    */
-  server?: string;
+  serverBuildTarget?: ServerBuildTarget;
 
   /**
-   * A list of filenames or a glob patterns to match files in the `app/routes`
-   * directory that Remix will ignore. Matching files will not be recognized as
-   * routes.
+   * The order of conditions to use when resolving server dependencies'
+   * `exports` field in `package.json`.
+   *
+   * For more information, see: https://esbuild.github.io/api/#conditions
    */
-  ignoredRouteFiles?: string[];
+  serverConditions?: string[];
 
   /**
    * A list of patterns that determined if a module is transpiled and included
    * in the server bundle. This can be useful when consuming ESM only packages
    * in a CJS build.
    */
-  serverDependenciesToBundle?: Array<string | RegExp>;
+  serverDependenciesToBundle?: "all" | Array<string | RegExp>;
+
+  /**
+   * The order of main fields to use when resolving server dependencies.
+   * Defaults to `["main", "module"]`.
+   *
+   * For more information, see: https://esbuild.github.io/api/#main-fields
+   */
+  serverMainFields?: string[];
+
+  /**
+   * Whether to minify the server build in production or not.
+   * Defaults to `false`.
+   */
+  serverMinify?: boolean;
+
+  /**
+   * The output format of the server build. Defaults to "cjs".
+   */
+  serverModuleFormat?: ServerModuleFormat;
+
+  /**
+   * The platform the server build is targeting. Defaults to "node".
+   */
+  serverPlatform?: ServerPlatform;
+
+  /**
+   * A list of filenames or a glob patterns to match files in the `app/routes`
+   * directory that Remix will ignore. Matching files will not be recognized as
+   * routes.
+   */
+  ignoredRouteFiles?: string[];
 
   /**
    * A function for defining custom directories to watch while running `remix dev`, in addition to `appDirectory`.
@@ -215,12 +232,6 @@ export interface RemixConfig {
    */
   routes: RouteManifest;
 
-  /**
-   * The path to the server build file. This file should end in a `.js`. Defaults
-   * are based on {@link ServerConfig.serverBuildTarget}.
-   */
-  serverBuildPath: string;
-
   /**
    * The absolute path to the assets build directory.
    */
@@ -236,11 +247,6 @@ export interface RemixConfig {
    */
   publicPath: string;
 
-  /**
-   * The mode to use to run the server.
-   */
-  serverMode: ServerMode;
-
   /**
    * The port number to use for the dev (asset) server.
    */
@@ -257,36 +263,71 @@ export interface RemixConfig {
   mdx?: RemixMdxConfig | RemixMdxConfigFunction;
 
   /**
-   * The output format of the server build. Defaults to "cjs".
-   */
-  serverModuleFormat: ServerModuleFormat;
-
-  /**
-   * The platform the server build is targeting. Defaults to "node".
+   * The path to the server build file. This file should end in a `.js`.
    */
-  serverPlatform: ServerPlatform;
+  serverBuildPath: string;
 
   /**
-   * The target of the server build.
-   */
+   * The target of the server build. Defaults to "node-cjs".
+   *
+   * @deprecated Use a combination of `{@link AppConfig.publicPath}`, `{@link AppConfig.serverBuildPath}`, `{@link AppConfig.serverConditions}`, `{@link AppConfig.serverDependenciesToBundle}`, `{@link AppConfig.serverMainFields}`, `{@link AppConfig.serverMinify}`, `{@link AppConfig.serverModuleFormat}` and/or `{@link AppConfig.serverPlatform}` instead.   */
   serverBuildTarget?: ServerBuildTarget;
 
   /**
-   * The default entry module for the server build if a {@see RemixConfig.customServer} is not provided.
+   * The default entry module for the server build if a {@see AppConfig.server}
+   * is not provided.
    */
   serverBuildTargetEntryModule: string;
 
   /**
-   * A server entrypoint relative to the root directory that becomes your server's main module.
+   * The order of conditions to use when resolving server dependencies'
+   * `exports` field in `package.json`.
+   *
+   * For more information, see: https://esbuild.github.io/api/#conditions
    */
-  serverEntryPoint?: string;
+  serverConditions?: string[];
 
   /**
    * A list of patterns that determined if a module is transpiled and included
    * in the server bundle. This can be useful when consuming ESM only packages
    * in a CJS build.
    */
-  serverDependenciesToBundle: Array<string | RegExp>;
+  serverDependenciesToBundle: "all" | Array<string | RegExp>;
+
+  /**
+   * A server entrypoint relative to the root directory that becomes your
+   * server's main module.
+   */
+  serverEntryPoint?: string;
+
+  /**
+   * The order of main fields to use when resolving server dependencies.
+   * Defaults to `["main", "module"]`.
+   *
+   * For more information, see: https://esbuild.github.io/api/#main-fields
+   */
+  serverMainFields: string[];
+
+  /**
+   * Whether to minify the server build in production or not.
+   * Defaults to `false`.
+   */
+  serverMinify: boolean;
+
+  /**
+   * The mode to use to run the server.
+   */
+  serverMode: ServerMode;
+
+  /**
+   * The output format of the server build. Defaults to "cjs".
+   */
+  serverModuleFormat: ServerModuleFormat;
+
+  /**
+   * The platform the server build is targeting. Defaults to "node".
+   */
+  serverPlatform: ServerPlatform;
 
   /**
    * A list of directories to watch.
@@ -342,20 +383,41 @@ export async function readConfig(
     }
   }
 
-  let customServerEntryPoint = appConfig.server;
-  let serverBuildTarget: ServerBuildTarget | undefined =
-    appConfig.serverBuildTarget;
-  let serverModuleFormat: ServerModuleFormat =
-    appConfig.serverModuleFormat || "cjs";
-  let serverPlatform: ServerPlatform = appConfig.serverPlatform || "node";
-  switch (appConfig.serverBuildTarget) {
-    case "cloudflare-pages":
-    case "cloudflare-workers":
-    case "deno":
-      serverModuleFormat = "esm";
-      serverPlatform = "neutral";
-      break;
+  let isCloudflareRuntime = ["cloudflare-pages", "cloudflare-workers"].includes(
+    appConfig.serverBuildTarget ?? ""
+  );
+  let isDenoRuntime = appConfig.serverBuildTarget === "deno";
+
+  let serverBuildPath = resolveServerBuildPath(rootDirectory, appConfig);
+  let serverBuildTarget = appConfig.serverBuildTarget;
+  let serverBuildTargetEntryModule = `export * from ${JSON.stringify(
+    serverBuildVirtualModule.id
+  )};`;
+  let serverConditions = appConfig.serverConditions;
+  let serverDependenciesToBundle = appConfig.serverDependenciesToBundle || [];
+  let serverEntryPoint = appConfig.server;
+  let serverMainFields = appConfig.serverMainFields;
+  let serverMinify = appConfig.serverMinify;
+  let serverModuleFormat = appConfig.serverModuleFormat || "cjs";
+  let serverPlatform = appConfig.serverPlatform || "node";
+  if (isCloudflareRuntime) {
+    serverConditions ??= ["worker"];
+    serverDependenciesToBundle = "all";
+    serverMainFields ??= ["browser", "module", "main"];
+    serverMinify ??= true;
+    serverModuleFormat = "esm";
+    serverPlatform = "neutral";
   }
+  if (isDenoRuntime) {
+    serverConditions ??= ["deno", "worker"];
+    serverDependenciesToBundle = "all";
+    serverMainFields ??= ["module", "main"];
+    serverModuleFormat = "esm";
+    serverPlatform = "neutral";
+  }
+  serverMainFields ??=
+    serverModuleFormat === "esm" ? ["module", "main"] : ["main", "module"];
+  serverMinify ??= false;
 
   let mdx = appConfig.mdx;
 
@@ -379,35 +441,6 @@ export async function readConfig(
     throw new Error(`Missing "entry.server" file in ${appDirectory}`);
   }
 
-  let serverBuildPath = "build/index.js";
-  switch (serverBuildTarget) {
-    case "arc":
-      serverBuildPath = "server/index.js";
-      break;
-    case "cloudflare-pages":
-      serverBuildPath = "functions/[[path]].js";
-      break;
-    case "netlify":
-      serverBuildPath = ".netlify/functions-internal/server.js";
-      break;
-    case "vercel":
-      serverBuildPath = "api/index.js";
-      break;
-  }
-  serverBuildPath = path.resolve(rootDirectory, serverBuildPath);
-
-  // retain deprecated behavior for now
-  if (appConfig.serverBuildDirectory) {
-    serverBuildPath = path.resolve(
-      rootDirectory,
-      path.join(appConfig.serverBuildDirectory, "index.js")
-    );
-  }
-
-  if (appConfig.serverBuildPath) {
-    serverBuildPath = path.resolve(rootDirectory, appConfig.serverBuildPath);
-  }
-
   let assetsBuildDirectory =
     appConfig.assetsBuildDirectory ||
     appConfig.browserBuildDirectory ||
@@ -425,13 +458,8 @@ export async function readConfig(
   process.env.REMIX_DEV_SERVER_WS_PORT = `${devServerPort}`;
   let devServerBroadcastDelay = appConfig.devServerBroadcastDelay || 0;
 
-  let defaultPublicPath = "/build/";
-  switch (serverBuildTarget) {
-    case "arc":
-      defaultPublicPath = "/_static/build/";
-      break;
-  }
-
+  let defaultPublicPath =
+    appConfig.serverBuildTarget === "arc" ? "/_static/build/" : "/build/";
   let publicPath = addTrailingSlash(appConfig.publicPath || defaultPublicPath);
 
   let rootRouteFile = findEntry(appDirectory, "root");
@@ -477,12 +505,6 @@ export async function readConfig(
     );
   }
 
-  let serverBuildTargetEntryModule = `export * from ${JSON.stringify(
-    serverBuildVirtualModule.id
-  )};`;
-
-  let serverDependenciesToBundle = appConfig.serverDependenciesToBundle || [];
-
   // When tsconfigPath is undefined, the default "tsconfig.json" is not
   // found in the root directory.
   let tsconfigPath: string | undefined;
@@ -525,13 +547,16 @@ export async function readConfig(
     rootDirectory,
     routes,
     serverBuildPath,
-    serverMode,
-    serverModuleFormat,
-    serverPlatform,
     serverBuildTarget,
     serverBuildTargetEntryModule,
-    serverEntryPoint: customServerEntryPoint,
+    serverConditions,
     serverDependenciesToBundle,
+    serverEntryPoint,
+    serverMainFields,
+    serverMinify,
+    serverMode,
+    serverModuleFormat,
+    serverPlatform,
     mdx,
     watchPaths,
     tsconfigPath,
@@ -564,3 +589,36 @@ function findConfig(dir: string, basename: string): string | undefined {
 
   return undefined;
 }
+
+const resolveServerBuildPath = (
+  rootDirectory: string,
+  appConfig: AppConfig
+) => {
+  let serverBuildPath = "build/index.js";
+
+  switch (appConfig.serverBuildTarget) {
+    case "arc":
+      serverBuildPath = "server/index.js";
+      break;
+    case "cloudflare-pages":
+      serverBuildPath = "functions/[[path]].js";
+      break;
+    case "netlify":
+      serverBuildPath = ".netlify/functions-internal/server.js";
+      break;
+    case "vercel":
+      serverBuildPath = "api/index.js";
+      break;
+  }
+
+  // retain deprecated behavior for now
+  if (appConfig.serverBuildDirectory) {
+    serverBuildPath = path.join(appConfig.serverBuildDirectory, "index.js");
+  }
+
+  if (appConfig.serverBuildPath) {
+    serverBuildPath = appConfig.serverBuildPath;
+  }
+
+  return path.resolve(rootDirectory, serverBuildPath);
+};
diff --git a/scripts/release/find-release-from-changeset.js b/scripts/release/find-release-from-changeset.js
index 57fd0e6ef..a499ec59e 100644
--- a/scripts/release/find-release-from-changeset.js
+++ b/scripts/release/find-release-from-changeset.js
@@ -32,6 +32,6 @@ function findReleaseFromChangeset(publishedPackages, packageVersionToFollow) {
 }
 
 findReleaseFromChangeset(
-  process.env.published_packages,
-  process.env.package_version_to_follow
+  process.env.PUBLISHED_PACKAGES,
+  process.env.PACKAGE_VERSION_TO_FOLLOW
 );


Test patch:
diff --git a/packages/remix-dev/__tests__/readConfig-test.ts b/packages/remix-dev/__tests__/readConfig-test.ts
index 4e48ced91..7ca6e2616 100644
--- a/packages/remix-dev/__tests__/readConfig-test.ts
+++ b/packages/remix-dev/__tests__/readConfig-test.ts
@@ -67,8 +67,14 @@ describe("readConfig", () => {
         "serverBuildPath": Any<String>,
         "serverBuildTarget": undefined,
         "serverBuildTargetEntryModule": "export * from \\"@remix-run/dev/server-build\\";",
+        "serverConditions": undefined,
         "serverDependenciesToBundle": Array [],
         "serverEntryPoint": undefined,
+        "serverMainFields": Array [
+          "main",
+          "module",
+        ],
+        "serverMinify": false,
         "serverMode": "production",
         "serverModuleFormat": "cjs",
         "serverPlatform": "node",