From 077239bc64b7c9d2e384531e4f67429f2bfdb879 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Thu, 9 Nov 2023 13:40:08 +0900 Subject: [PATCH 1/6] fix(remix-dev/vite): resolve code split assets from vite manifest --- packages/remix-dev/vite/plugin.ts | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/packages/remix-dev/vite/plugin.ts b/packages/remix-dev/vite/plugin.ts index e26661e26e9..4da64976e0f 100644 --- a/packages/remix-dev/vite/plugin.ts +++ b/packages/remix-dev/vite/plugin.ts @@ -139,19 +139,45 @@ const resolveBuildAssetPaths = ( ); } + let keys = resolveViteManifestDepChunks(manifest, manifestKey); + let entries = [...keys].map((key) => manifest[key]); + return { module: `${pluginConfig.publicPath}${manifestEntry.file}`, imports: - manifestEntry.imports?.map((imported) => { + dedupe(entries.flatMap((e) => e.imports ?? [])).map((imported) => { return `${pluginConfig.publicPath}${manifest[imported].file}`; }) ?? [], css: - manifestEntry.css?.map((href) => { + dedupe(entries.flatMap((e) => e.css ?? [])).map((href) => { return `${pluginConfig.publicPath}${href}`; }) ?? [], }; }; +function resolveViteManifestDepChunks(manifest: ViteManifest, base: string) { + let keys = new Set(); + + function dfs(key: string) { + if (keys.has(key)) { + return; + } + keys.add(key); + let chunk = manifest[key]; + for (let next of chunk.imports ?? []) { + dfs(next); + } + } + dfs(base); + + return keys; +} + +// common utils? +function dedupe(array: any[]) { + return [...new Set(array)]; +} + const writeFileSafe = async (file: string, contents: string): Promise => { await fs.mkdir(path.dirname(file), { recursive: true }); await fs.writeFile(file, contents); From afd47ddceb77bc5d7d60bc47ae0f9db21e824c6b Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Thu, 9 Nov 2023 14:24:55 +0900 Subject: [PATCH 2/6] test: add test --- integration/vite-build-test.ts | 50 +++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/integration/vite-build-test.ts b/integration/vite-build-test.ts index 3972460e382..e0fdcd92909 100644 --- a/integration/vite-build-test.ts +++ b/integration/vite-build-test.ts @@ -107,7 +107,7 @@ test.describe("Vite build", () => { import { useEffect, useState } from "react"; import { json } from "@remix-run/node"; import { useLoaderData } from "@remix-run/react"; - + import { serverOnly1, serverOnly2 } from "../utils.server"; export const loader = () => { @@ -138,6 +138,32 @@ test.describe("Vite build", () => { `, + "app/routes/code-split1.tsx": js` + import { CodeSplitComponent } from "../code-split-component"; + + export default function CodeSplit1Route() { + return
; + } + `, + "app/routes/code-split2.tsx": js` + import { CodeSplitComponent } from "../code-split-component"; + + export default function CodeSplit2Route() { + return
; + } + `, + "app/code-split-component.tsx": js` + import classes from "./code-split.module.css"; + + export function CodeSplitComponent() { + return ok + } + `, + "app/code-split.module.css": js` + .test { + background-color: rgb(255, 170, 0); + } + `, }, }); @@ -206,4 +232,26 @@ test.describe("Vite build", () => { expect(pageErrors).toEqual([]); }); + + test.only("supports code-split css", async ({ page }) => { + let pageErrors: unknown[] = []; + page.on("pageerror", (error) => pageErrors.push(error)); + + let app = new PlaywrightFixture(appFixture, page); + await app.goto("/code-split1"); + expect( + await page + .locator("#code-split1 span") + .evaluate((e) => window.getComputedStyle(e).backgroundColor) + ).toBe("rgb(255, 170, 0)"); + + await app.goto("/code-split2"); + expect( + await page + .locator("#code-split2 span") + .evaluate((e) => window.getComputedStyle(e).backgroundColor) + ).toBe("rgb(255, 170, 0)"); + + expect(pageErrors).toEqual([]); + }); }); From a674d00029eedf890c1e28836afcc9a8d2729762 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Thu, 9 Nov 2023 14:28:29 +0900 Subject: [PATCH 3/6] test: remove "test.only" --- integration/vite-build-test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration/vite-build-test.ts b/integration/vite-build-test.ts index e0fdcd92909..df13c3d8513 100644 --- a/integration/vite-build-test.ts +++ b/integration/vite-build-test.ts @@ -233,7 +233,7 @@ test.describe("Vite build", () => { expect(pageErrors).toEqual([]); }); - test.only("supports code-split css", async ({ page }) => { + test("supports code-split css", async ({ page }) => { let pageErrors: unknown[] = []; page.on("pageerror", (error) => pageErrors.push(error)); From 4b18b60c846109dda1a4cc1619ea81f66af23874 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Thu, 9 Nov 2023 14:29:49 +0900 Subject: [PATCH 4/6] chore: changeset --- .changeset/itchy-rabbits-fly.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/itchy-rabbits-fly.md diff --git a/.changeset/itchy-rabbits-fly.md b/.changeset/itchy-rabbits-fly.md new file mode 100644 index 00000000000..d3db2998ed6 --- /dev/null +++ b/.changeset/itchy-rabbits-fly.md @@ -0,0 +1,5 @@ +--- +"@remix-run/dev": patch +--- + +fix: include css from code-split assets when "build" From 4b18db3476996d0ac6ac021e2f44cf13b6e8b1c9 Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Fri, 10 Nov 2023 09:28:23 +1100 Subject: [PATCH 5/6] update changeset --- .changeset/itchy-rabbits-fly.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/itchy-rabbits-fly.md b/.changeset/itchy-rabbits-fly.md index d3db2998ed6..c88e6e0f8be 100644 --- a/.changeset/itchy-rabbits-fly.md +++ b/.changeset/itchy-rabbits-fly.md @@ -2,4 +2,4 @@ "@remix-run/dev": patch --- -fix: include css from code-split assets when "build" +Attach CSS from shared chunks to routes in Vite build From 134a248688e42522f6eb74aa5bfe3a7b18ed82ef Mon Sep 17 00:00:00 2001 From: Mark Dalgleish Date: Fri, 10 Nov 2023 09:28:46 +1100 Subject: [PATCH 6/6] refactor --- packages/remix-dev/vite/plugin.ts | 50 +++++++++++++++++-------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/packages/remix-dev/vite/plugin.ts b/packages/remix-dev/vite/plugin.ts index 4fc9642ed75..9f401b7b01c 100644 --- a/packages/remix-dev/vite/plugin.ts +++ b/packages/remix-dev/vite/plugin.ts @@ -7,6 +7,7 @@ import { type Connect, type Plugin as VitePlugin, type Manifest as ViteManifest, + type ManifestChunk, type ResolvedConfig as ResolvedViteConfig, type ViteDevServer, type UserConfig as ViteUserConfig, @@ -120,7 +121,7 @@ const getHash = (source: BinaryLike, maxLength?: number): string => { const resolveBuildAssetPaths = ( pluginConfig: ResolvedRemixVitePluginConfig, - manifest: ViteManifest, + viteManifest: ViteManifest, absoluteFilePath: string ): Manifest["entry"] & { css: string[] } => { let rootRelativeFilePath = path.relative( @@ -128,10 +129,10 @@ const resolveBuildAssetPaths = ( absoluteFilePath ); let manifestKey = normalizePath(rootRelativeFilePath); - let manifestEntry = manifest[manifestKey]; + let entryChunk = viteManifest[manifestKey]; - if (!manifestEntry) { - let knownManifestKeys = Object.keys(manifest) + if (!entryChunk) { + let knownManifestKeys = Object.keys(viteManifest) .map((key) => '"' + key + '"') .join(", "); throw new Error( @@ -139,42 +140,47 @@ const resolveBuildAssetPaths = ( ); } - let keys = resolveViteManifestDepChunks(manifest, manifestKey); - let entries = [...keys].map((key) => manifest[key]); + let chunks = resolveDependantChunks(viteManifest, entryChunk); return { - module: `${pluginConfig.publicPath}${manifestEntry.file}`, + module: `${pluginConfig.publicPath}${entryChunk.file}`, imports: - dedupe(entries.flatMap((e) => e.imports ?? [])).map((imported) => { - return `${pluginConfig.publicPath}${manifest[imported].file}`; + dedupe(chunks.flatMap((e) => e.imports ?? [])).map((imported) => { + return `${pluginConfig.publicPath}${viteManifest[imported].file}`; }) ?? [], css: - dedupe(entries.flatMap((e) => e.css ?? [])).map((href) => { + dedupe(chunks.flatMap((e) => e.css ?? [])).map((href) => { return `${pluginConfig.publicPath}${href}`; }) ?? [], }; }; -function resolveViteManifestDepChunks(manifest: ViteManifest, base: string) { - let keys = new Set(); +function resolveDependantChunks( + viteManifest: ViteManifest, + entryChunk: ManifestChunk +): ManifestChunk[] { + let chunks = new Set(); - function dfs(key: string) { - if (keys.has(key)) { + function walk(chunk: ManifestChunk) { + if (chunks.has(chunk)) { return; } - keys.add(key); - let chunk = manifest[key]; - for (let next of chunk.imports ?? []) { - dfs(next); + + if (chunk.imports) { + for (let importKey of chunk.imports) { + walk(viteManifest[importKey]); + } } + + chunks.add(chunk); } - dfs(base); - return keys; + walk(entryChunk); + + return Array.from(chunks); } -// common utils? -function dedupe(array: any[]) { +function dedupe(array: T[]): T[] { return [...new Set(array)]; }