Skip to content

Commit

Permalink
refactor(remix-dev/vite): move server bundle ID to build context (#8582)
Browse files Browse the repository at this point in the history
  • Loading branch information
markdalgleish committed Jan 23, 2024
1 parent a8fb7d8 commit 1d1d196
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 42 deletions.
31 changes: 16 additions & 15 deletions packages/remix-dev/vite/build.ts
Expand Up @@ -9,13 +9,13 @@ import {
type BuildManifest,
type ServerBundlesBuildManifest,
configRouteToBranchRoute,
getServerBuildDirectory,
getServerBuildRootDirectory,
} from "./plugin";
import type { ConfigRoute, RouteManifest } from "../config/routes";
import invariant from "../invariant";
import { preloadViteEsm } from "./import-vite-esm-sync";

async function extractConfig({
async function resolveViteConfig({
configFile,
mode,
root,
Expand All @@ -35,6 +35,10 @@ async function extractConfig({
"production" // default NODE_ENV
);

return viteConfig;
}

async function extractRemixConfig(viteConfig: Vite.ResolvedConfig) {
let remixConfig = viteConfig[
"__remixPluginResolvedConfig" as keyof typeof viteConfig
] as ResolvedVitePluginConfig | undefined;
Expand All @@ -43,7 +47,7 @@ async function extractConfig({
process.exit(1);
}

return { remixConfig, viteConfig };
return remixConfig;
}

function getAddressableRoutes(routes: RouteManifest): ConfigRoute[] {
Expand Down Expand Up @@ -110,7 +114,7 @@ async function getServerBuilds(remixConfig: ResolvedVitePluginConfig): Promise<{
rootDirectory,
appDirectory,
} = remixConfig;
let serverBuildDirectory = getServerBuildDirectory(remixConfig);
let serverBuildRootDirectory = getServerBuildRootDirectory(remixConfig);
if (!serverBundles) {
return {
serverBuilds: [{ ssr: true }],
Expand Down Expand Up @@ -160,7 +164,7 @@ async function getServerBuilds(remixConfig: ResolvedVitePluginConfig): Promise<{

let relativeServerBundleDirectory = path.relative(
rootDirectory,
path.join(serverBuildDirectory, serverBundleId)
path.join(serverBuildRootDirectory, serverBundleId)
);
let serverBuildConfig = serverBundleBuildConfigById.get(serverBundleId);
if (!serverBuildConfig) {
Expand Down Expand Up @@ -198,21 +202,21 @@ async function getServerBuilds(remixConfig: ResolvedVitePluginConfig): Promise<{
};
}

async function cleanServerBuildDirectory(
async function cleanServerBuildRootDirectory(
viteConfig: Vite.ResolvedConfig,
remixConfig: ResolvedVitePluginConfig
) {
let serverBuildDirectory = getServerBuildDirectory(remixConfig);
let serverBuildRootDirectory = getServerBuildRootDirectory(remixConfig);
let isWithinRoot = () => {
let relativePath = path.relative(
remixConfig.rootDirectory,
serverBuildDirectory
serverBuildRootDirectory
);
return !relativePath.startsWith("..") && !path.isAbsolute(relativePath);
};

if (viteConfig.build.emptyOutDir ?? isWithinRoot()) {
await fse.remove(serverBuildDirectory);
await fse.remove(serverBuildRootDirectory);
}
}

Expand Down Expand Up @@ -245,11 +249,8 @@ export async function build(
// so it can be accessed synchronously via `importViteEsmSync`
await preloadViteEsm();

let { remixConfig, viteConfig } = await extractConfig({
configFile,
mode,
root,
});
let viteConfig = await resolveViteConfig({ configFile, mode, root });
let remixConfig = await extractRemixConfig(viteConfig);

let vite = await import("vite");

Expand All @@ -275,7 +276,7 @@ export async function build(
// output directories, we need to clean the root server build directory
// ourselves rather than relying on Vite to do it, otherwise you can end up
// with stale server bundle directories in your build output
await cleanServerBuildDirectory(viteConfig, remixConfig);
await cleanServerBuildRootDirectory(viteConfig, remixConfig);

// Run the Vite client build first
await viteBuild({ ssr: false });
Expand Down
75 changes: 48 additions & 27 deletions packages/remix-dev/vite/plugin.ts
Expand Up @@ -197,7 +197,6 @@ export type ResolvedVitePluginConfig = Pick<
buildDirectory: string;
manifest: boolean;
serverBuildFile: string;
serverBundleId?: string;
serverBundles?: ServerBundlesFunction;
ssr: boolean;
};
Expand All @@ -207,6 +206,18 @@ export type ServerBundleBuildConfig = {
serverBundleId: string;
};

type BuildContext =
| {
isSsrBuild: false;
getBrowserManifest?: never;
serverBundleId?: never;
}
| {
isSsrBuild: true;
getBrowserManifest: () => Promise<BrowserManifest>;
serverBundleId: string | undefined;
};

let serverBuildId = VirtualModule.id("server-build");
let serverManifestId = VirtualModule.id("server-manifest");
let browserManifestId = VirtualModule.id("browser-manifest");
Expand Down Expand Up @@ -405,15 +416,20 @@ const getServerBundleBuildConfig = (
return viteUserConfig.__remixServerBundleBuildConfig as ServerBundleBuildConfig;
};

export let getServerBuildDirectory = (remixConfig: ResolvedVitePluginConfig) =>
let getServerBuildDirectory = (
remixConfig: ResolvedVitePluginConfig,
{ serverBundleId }: Pick<BuildContext, "serverBundleId">
) =>
path.join(
remixConfig.buildDirectory,
"server",
...(typeof remixConfig.serverBundleId === "string"
? [remixConfig.serverBundleId]
: [])
...(typeof serverBundleId === "string" ? [serverBundleId] : [])
);

export let getServerBuildRootDirectory = (
remixConfig: ResolvedVitePluginConfig
) => getServerBuildDirectory(remixConfig, { serverBundleId: undefined });

let getClientBuildDirectory = (remixConfig: ResolvedVitePluginConfig) =>
path.join(remixConfig.buildDirectory, "client");

Expand All @@ -424,9 +440,7 @@ export const remixVitePlugin: RemixVitePlugin = (remixUserConfig = {}) => {
let viteConfig: Vite.ResolvedConfig | undefined;

let cssModulesManifest: Record<string, string> = {};
let ssrBuildContext:
| { isSsrBuild: false }
| { isSsrBuild: true; getBrowserManifest: () => Promise<BrowserManifest> };
let buildContext: BuildContext;

let viteChildCompiler: Vite.ViteDevServer | null = null;

Expand Down Expand Up @@ -507,10 +521,8 @@ export const remixVitePlugin: RemixVitePlugin = (remixUserConfig = {}) => {

// For server bundle builds, override the relevant config. This lets us run
// multiple server builds with each one targeting a subset of routes.
let serverBundleId: string | undefined = undefined;
if (serverBundleBuildConfig) {
routes = serverBundleBuildConfig.routes;
serverBundleId = serverBundleBuildConfig.serverBundleId;
}

let resolvedRemixConfig: ResolvedVitePluginConfig = {
Expand All @@ -525,7 +537,6 @@ export const remixVitePlugin: RemixVitePlugin = (remixUserConfig = {}) => {
rootDirectory,
routes,
serverBuildFile,
serverBundleId,
serverBundles,
serverModuleFormat,
ssr,
Expand All @@ -534,6 +545,22 @@ export const remixVitePlugin: RemixVitePlugin = (remixUserConfig = {}) => {
return resolvedRemixConfig;
};

let resolveBuildContext = (viteConfigEnv: Vite.ConfigEnv): BuildContext => {
let buildContext: BuildContext =
viteConfigEnv.isSsrBuild && viteCommand === "build"
? {
isSsrBuild: true,
getBrowserManifest: createBrowserManifestForBuild,
serverBundleId:
getServerBundleBuildConfig(viteUserConfig)?.serverBundleId,
}
: {
isSsrBuild: false,
};

return buildContext;
};

let getServerEntry = async () => {
return `
import * as entryServer from ${JSON.stringify(
Expand Down Expand Up @@ -708,6 +735,7 @@ export const remixVitePlugin: RemixVitePlugin = (remixUserConfig = {}) => {
viteCommand = viteConfigEnv.command;

remixConfig = await resolvePluginConfig();
buildContext = resolveBuildContext(viteConfigEnv);

Object.assign(
process.env,
Expand Down Expand Up @@ -796,7 +824,7 @@ export const remixVitePlugin: RemixVitePlugin = (remixUserConfig = {}) => {
ssrEmitAssets: true,
copyPublicDir: false, // Assets in the public directory are only used by the client
manifest: true, // We need the manifest to detect SSR-only assets
outDir: getServerBuildDirectory(remixConfig),
outDir: getServerBuildDirectory(remixConfig, buildContext),
rollupOptions: {
...viteUserConfig.build?.rollupOptions,
preserveEntrySignatures: "exports-only",
Expand All @@ -816,16 +844,6 @@ export const remixVitePlugin: RemixVitePlugin = (remixUserConfig = {}) => {

viteConfig = resolvedViteConfig;

ssrBuildContext =
viteConfig.build.ssr && viteCommand === "build"
? {
isSsrBuild: true,
getBrowserManifest: createBrowserManifestForBuild,
}
: {
isSsrBuild: false,
};

// We load the same Vite config file again for the child compiler so
// that both parent and child compiler's plugins have independent state.
// If we re-used the `viteUserConfig.plugins` array for the child
Expand All @@ -846,7 +864,7 @@ export const remixVitePlugin: RemixVitePlugin = (remixUserConfig = {}) => {
{
command: viteConfig.command,
mode: viteConfig.mode,
isSsrBuild: ssrBuildContext.isSsrBuild,
isSsrBuild: buildContext.isSsrBuild,
},
viteConfig.configFile
);
Expand Down Expand Up @@ -1010,15 +1028,18 @@ export const remixVitePlugin: RemixVitePlugin = (remixUserConfig = {}) => {
// After the SSR build is finished, we inspect the Vite manifest for
// the SSR build and move server-only assets to client assets directory
async handler() {
if (!ssrBuildContext.isSsrBuild) {
if (!buildContext.isSsrBuild) {
return;
}

invariant(viteConfig);

let { serverBuildFile, rootDirectory } = remixConfig;
let serverBuildDirectory = getServerBuildDirectory(remixConfig);
let clientBuildDirectory = getClientBuildDirectory(remixConfig);
let serverBuildDirectory = getServerBuildDirectory(
remixConfig,
buildContext
);

let ssrViteManifest = await loadViteManifest(serverBuildDirectory);
let clientViteManifest = await loadViteManifest(clientBuildDirectory);
Expand Down Expand Up @@ -1105,8 +1126,8 @@ export const remixVitePlugin: RemixVitePlugin = (remixUserConfig = {}) => {
return await getServerEntry();
}
case VirtualModule.resolve(serverManifestId): {
let browserManifest = ssrBuildContext.isSsrBuild
? await ssrBuildContext.getBrowserManifest()
let browserManifest = buildContext.isSsrBuild
? await buildContext.getBrowserManifest()
: await getBrowserManifestForDev();

return `export default ${jsesc(browserManifest, { es6: true })};`;
Expand Down

0 comments on commit 1d1d196

Please sign in to comment.