Skip to content

Commit

Permalink
feat(react-server): style
Browse files Browse the repository at this point in the history
  • Loading branch information
hi-ogawa committed Apr 28, 2024
1 parent 6c896f7 commit 6b4a4ed
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 2 deletions.
89 changes: 89 additions & 0 deletions examples/react-server/src/features/bootstrap/css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import type { DevEnvironment, PluginOption } from "vite";
import { $__global } from "../../global";
import { createVirtualPlugin } from "../utils/plugin";

//
// environment api port of
// https://github.com/hi-ogawa/vite-plugins/tree/main/packages/ssr-css
//

export const SSR_CSS_ENTRY = "virtual:ssr-css.css";

export function vitePluginSsrCss(): PluginOption {
return [
{
name: vitePluginSsrCss.name + ":invalidate",
configureServer(server) {
server.middlewares.use((req, _res, next) => {
if (req.url === `/@id/__x00__${SSR_CSS_ENTRY}`) {
const { moduleGraph } = $__global.server.environments["client"];
const mod = moduleGraph.getModuleById(`\0${SSR_CSS_ENTRY}?direct`);
if (mod) {
moduleGraph.invalidateModule(mod);
}
}
next();
});
},
},
createVirtualPlugin("ssr-css.css?direct", async () => {
const styles = await Promise.all([
`/****** react-server ********/`,
collectStyle($__global.server.environments["react-server"], [
"/src/entry-react-server",
]),
`/****** client **************/`,
collectStyle($__global.server.environments["client"], [
"/src/entry-client",
]),
]);
return styles.join("\n\n");
}),
];
}

async function collectStyle(server: DevEnvironment, entries: string[]) {
const urls = await collectStyleUrls(server, entries);
const codes = await Promise.all(
urls.map(async (url) => {
const res = await server.transformRequest(url + "?direct");
return [`/*** ${url} ***/`, res?.code];
}),
);
return codes.flat().filter(Boolean).join("\n\n");
}

async function collectStyleUrls(
server: DevEnvironment,
entries: string[],
): Promise<string[]> {
const visited = new Set<string>();

async function traverse(url: string) {
const [, id] = await server.moduleGraph.resolveUrl(url);
if (visited.has(id)) {
return;
}
visited.add(id);
const mod = server.moduleGraph.getModuleById(id);
if (!mod) {
return;
}
await Promise.all(
[...mod.importedModules].map((childMod) => traverse(childMod.url)),
);
}

// ensure vite's import analysis is ready _only_ for top entries to not go too aggresive
await Promise.all(entries.map((e) => server.transformRequest(e)));

// traverse
await Promise.all(entries.map((url) => traverse(url)));

// filter
return [...visited].filter((url) => url.match(CSS_LANGS_RE));
}

// cf. https://github.com/vitejs/vite/blob/d6bde8b03d433778aaed62afc2be0630c8131908/packages/vite/src/node/constants.ts#L49C23-L50
const CSS_LANGS_RE =
/\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(?:$|\?)/;
10 changes: 8 additions & 2 deletions examples/react-server/src/features/bootstrap/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { tinyassert, typedBoolean } from "@hiogawa/utils";
import type { Manifest, PluginOption, ViteDevServer } from "vite";
import { $__global } from "../../global";
import { createVirtualPlugin } from "../utils/plugin";
import { SSR_CSS_ENTRY, vitePluginSsrCss } from "./css";

export const ENTRY_CLIENT_BOOTSTRAP = "virtual:entry-client-bootstrap";

Expand Down Expand Up @@ -31,7 +32,11 @@ export function vitePluginEntryBootstrap(): PluginOption {
createVirtualPlugin("ssr-assets", async () => {
let ssrAssets: SsrAssets;
if ($__global.server) {
const { head } = await getIndexHtmlTransform($__global.server);
let { head } = await getIndexHtmlTransform($__global.server);
head = [
head,
`<link rel="stylesheet" href="/@id/__x00__${SSR_CSS_ENTRY}" />`,
].join("\n");
ssrAssets = {
head,
bootstrapModules: ["/@id/__x00__" + ENTRY_CLIENT_BOOTSTRAP],
Expand All @@ -56,12 +61,13 @@ export function vitePluginEntryBootstrap(): PluginOption {
...js.map((href) => `<link rel="modulepreload" href="/${href}" />`),
].join("\n");
ssrAssets = {
bootstrapModules: [`/${entry.file}`],
head,
bootstrapModules: [`/${entry.file}`],
};
}
return `export default ${JSON.stringify(ssrAssets)}`;
}),
vitePluginSsrCss(),
];
}

Expand Down
6 changes: 6 additions & 0 deletions examples/react-server/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ export default defineConfig((_env) => ({

environments: {
client: {
dev: {
optimizeDeps: {
// [feedback] no optimizeDeps.entries for initial scan?
// entries: []
},
},
build: {
outDir: "dist/client",
minify: false,
Expand Down

0 comments on commit 6b4a4ed

Please sign in to comment.