diff --git a/.changeset/great-geese-compare.md b/.changeset/great-geese-compare.md new file mode 100644 index 00000000000..bfc0cf917cd --- /dev/null +++ b/.changeset/great-geese-compare.md @@ -0,0 +1,9 @@ +--- +"@remix-run/react": minor +"@remix-run/dev": patch +--- + +Faster server export removal for routes when `unstable_dev` is enabled. + +Also, only render modulepreloads on SSR. +Do not render modulepreloads when hydrated. diff --git a/packages/remix-dev/compiler/js/compiler.ts b/packages/remix-dev/compiler/js/compiler.ts index d55e9ff98f8..7cc89714ff8 100644 --- a/packages/remix-dev/compiler/js/compiler.ts +++ b/packages/remix-dev/compiler/js/compiler.ts @@ -8,7 +8,6 @@ import { type Manifest } from "../../manifest"; import { getAppDependencies } from "../../dependencies"; import { loaders } from "../utils/loaders"; import { browserRouteModulesPlugin } from "./plugins/routes"; -import { browserRouteModulesPlugin as browserRouteModulesPlugin_v2 } from "./plugins/routes_unstable"; import { cssFilePlugin } from "../plugins/cssImports"; import { absoluteCssUrlsPlugin } from "../plugins/absoluteCssUrlsPlugin"; import { deprecatedRemixPackagePlugin } from "../plugins/deprecatedRemixPackage"; @@ -78,29 +77,12 @@ const createEsbuildConfig = ( "entry.client": ctx.config.entryClientFilePath, }; - let routeModulePaths = new Map(); for (let id of Object.keys(ctx.config.routes)) { entryPoints[id] = ctx.config.routes[id].file; - if (ctx.config.future.unstable_dev) { - // In V2 we are doing AST transforms to remove server code, this means we - // have to re-map all route modules back to the same module in the graph - // otherwise we will have duplicate modules in the graph. We have to resolve - // the path as we get the relative for the entrypoint and absolute for imports - // from other modules. - routeModulePaths.set( - ctx.config.routes[id].file, - ctx.config.routes[id].file - ); - routeModulePaths.set( - path.resolve(ctx.config.appDirectory, ctx.config.routes[id].file), - ctx.config.routes[id].file - ); - } else { - // All route entry points are virtual modules that will be loaded by the - // browserEntryPointsPlugin. This allows us to tree-shake server-only code - // that we don't want to run in the browser (i.e. action & loader). - entryPoints[id] += "?browser"; - } + // All route entry points are virtual modules that will be loaded by the + // browserEntryPointsPlugin. This allows us to tree-shake server-only code + // that we don't want to run in the browser (i.e. action & loader). + entryPoints[id] += "?browser"; } if ( @@ -133,16 +115,18 @@ const createEsbuildConfig = ( } let plugins: esbuild.Plugin[] = [ + browserRouteModulesPlugin(ctx, /\?browser$/), deprecatedRemixPackagePlugin(ctx), cssModulesPlugin(ctx, { outputCss: false }), vanillaExtractPlugin(ctx, { outputCss: false }), - cssSideEffectImportsPlugin(ctx), + cssSideEffectImportsPlugin(ctx, { + hmr: + ctx.options.mode === "development" && + ctx.config.future.unstable_dev !== false, + }), cssFilePlugin(ctx), absoluteCssUrlsPlugin(), externalPlugin(/^https?:\/\//, { sideEffects: false }), - ctx.config.future.unstable_dev - ? browserRouteModulesPlugin_v2(ctx, routeModulePaths) - : browserRouteModulesPlugin(ctx, /\?browser$/), mdxPlugin(ctx), emptyModulesPlugin(ctx, /\.server(\.[jt]sx?)?$/), NodeModulesPolyfillPlugin(), diff --git a/packages/remix-dev/compiler/plugins/cssSideEffectImports.ts b/packages/remix-dev/compiler/plugins/cssSideEffectImports.ts index 9478841b51f..aa4862c180d 100644 --- a/packages/remix-dev/compiler/plugins/cssSideEffectImports.ts +++ b/packages/remix-dev/compiler/plugins/cssSideEffectImports.ts @@ -6,9 +6,9 @@ import { parse, type ParserOptions } from "@babel/parser"; import traverse from "@babel/traverse"; import generate from "@babel/generator"; -import type { RemixConfig } from "../../config"; -import type { Options } from "../options"; import { getPostcssProcessor } from "../utils/postcss"; +import { applyHMR } from "../js/plugins/hmr"; +import type { Context } from "../context"; const pluginName = "css-side-effects-plugin"; const namespace = `${pluginName}-ns`; @@ -44,17 +44,14 @@ const loaderForExtension: Record = { * to the CSS bundle. This is primarily designed to support packages that * import plain CSS files directly within JS files. */ -export const cssSideEffectImportsPlugin = ({ - config, - options, -}: { - config: RemixConfig; - options: Options; -}): Plugin => { +export const cssSideEffectImportsPlugin = ( + ctx: Context, + { hmr = false } = {} +): Plugin => { return { name: pluginName, setup: async (build) => { - let postcssProcessor = await getPostcssProcessor({ config }); + let postcssProcessor = await getPostcssProcessor(ctx); build.onLoad( { filter: allJsFilesFilter, namespace: "file" }, @@ -69,6 +66,15 @@ export const cssSideEffectImportsPlugin = ({ let loader = loaderForExtension[path.extname(args.path) as Extension]; let contents = addSuffixToCssSideEffectImports(loader, code); + if (hmr) { + contents = await applyHMR( + contents, + args, + ctx.config, + !!build.initialOptions.sourcemap + ); + } + return { contents, loader, @@ -94,7 +100,7 @@ export const cssSideEffectImportsPlugin = ({ } return { - path: path.relative(config.rootDirectory, resolvedPath), + path: path.relative(ctx.config.rootDirectory, resolvedPath), namespace, }; } @@ -108,7 +114,7 @@ export const cssSideEffectImportsPlugin = ({ await postcssProcessor.process(contents, { from: args.path, to: args.path, - map: options.sourcemap, + map: ctx.options.sourcemap, }) ).css; } diff --git a/packages/remix-react/components.tsx b/packages/remix-react/components.tsx index 89fa1b7e9ab..cd5fbf8e8a9 100644 --- a/packages/remix-react/components.tsx +++ b/packages/remix-react/components.tsx @@ -1087,13 +1087,8 @@ import(${JSON.stringify(manifest.entry.module)});`; let preloads = isHydrated ? [] : manifest.entry.imports.concat(routePreloads); - return ( + return isHydrated ? null : ( <> - ))} - {!isHydrated && initialScripts} - {!isHydrated && deferredScripts} + {initialScripts} + {deferredScripts} ); } diff --git a/packages/remix-server-runtime/serialize.ts b/packages/remix-server-runtime/serialize.ts index d418bc07288..7e2f9c98f71 100644 --- a/packages/remix-server-runtime/serialize.ts +++ b/packages/remix-server-runtime/serialize.ts @@ -46,7 +46,11 @@ type SerializeObject = { // prettier-ignore type SerializeDeferred> = { - [k in keyof T as T[k] extends Promise ? k : T[k] extends NonJsonPrimitive ? never : k]: + [k in keyof T as + T[k] extends Promise ? k : + T[k] extends NonJsonPrimitive ? never : + k + ]: T[k] extends Promise ? Promise> extends never ? "wtf" : Promise> : Serialize extends never ? k : Serialize;