Repository navigation
fix(vite-plugin): keep server page css dependencies in vinext/RSC builds - #747
Merged
Merged
Conversation
…css once Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Contributor
Changepacks@devup-ui/wasm@1.0.82 → 1.0.83 - bindings/devup-ui-wasm/package.jsonPatch
@devup-ui/bun-plugin@1.0.21 → 1.0.22 - packages/bun-plugin/package.jsonPatch
@devup-ui/components@0.1.59 → 0.1.60 - packages/components/package.jsonPatch
@devup-ui/eslint-plugin@1.0.21 → 1.0.22 - packages/eslint-plugin/package.jsonPatch
@devup-ui/next-plugin@1.0.89 → 1.0.90 - packages/next-plugin/package.jsonPatch
@devup-ui/plugin-utils@1.0.16 → 1.0.17 - packages/plugin-utils/package.jsonPatch
@devup-ui/rsbuild-plugin@1.0.66 → 1.0.67 - packages/rsbuild-plugin/package.jsonPatch
@devup-ui/vite-plugin@1.0.72 → 1.0.73 - packages/vite-plugin/package.jsonPatch
@devup-ui/webpack-plugin@1.0.70 → 1.0.71 - packages/webpack-plugin/package.jsonPatch
|
Codecov Report✅ All modified and coverable lines are covered by tests.
🚀 New features to boost your workflow:
|
This was referenced Oct 4, 2026
owjs3901
added a commit
that referenced
this pull request
Oct 8, 2026
Restore pinned main 11790be's parked-forwarded CSS and post-restoration plugin pair, full vinext RSC fixture, both-mode CI job, root script and resolver lock after the unchanged-tree ours merge4473674c skipped #747 content. Preserve all #763 shorthand normalization, JSX-source, StyleX, type and lint intent. Local restored RSC e2e29/29 passed under6GiB; all packages built serially and Bun6071/0fail passed. Refs #763 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs 사용자 버그 리포트 (2026-10-03, lottolegend-front
apps/adminVinext/RSC 프로덕션 빌드). 독립 PR이며 다른 PR에 쌓여 있지 않습니다. 먼저 병합해 patch 릴리스로 내보낼 수 있습니다.요약
Vinext/RSC 프로덕션 빌드에서
@devup-ui/vite-plugin이 서버 페이지가 필요로 하는 공통 컴포넌트 CSS를 로딩 목록에서 빠뜨리던 문제를 고칩니다.원인은
generateBundle이 "중복 emit 방지"와 "CSS 의존성 삭제"를 한 동작으로 처리한 것입니다. 클라이언트가 이미 내보낸 CSS를 서버 번들의output.viteMetadata.importedCss에서 지웠는데,@vitejs/plugin-rsc는 같은importedCss를 서버 페이지의 CSS 의존성(serverResources)으로도 읽습니다. 이제importedCss는 그대로 두고, 실제로 일어나는 중복 emit(FILE_NAME_CONFLICT)만 막습니다.정확한 원인
@vitejs/plugin-rsc0.5.35rsc:virtual:vite-rsc/assets-manifest의generateBundle(클라이언트 환경,dist/plugin-CLvIS10V.js1163~1218행)은 한 훅 안에서 같은importedCss를 두 번 읽습니다.importedCss ∪ importedAssets를 모아 클라이언트로emitFile합니다 (이미 클라이언트에 같은 이름이 있으면 FILE_NAME_CONFLICT).1191행:1854행,collectAssetDeps(rscBundle)(1826collectAssetDepsInner가v.viteMetadata?.importedCss를 모읍니다)로serverResources[key].css를 만듭니다.Devup UI는
enforce: 'pre'라서 클라이언트generateBundle에서 plugin-rsc보다 먼저 실행되고, 거기서 겹치는 파일을 RSC 번들의importedCss에서 지웠습니다. 그래서 2번에서serverResources가 비었습니다.누락 지점 추적 (재현 앱, 수정 전)
임시 진단 플러그인(
order: 'pre', Devup 바로 뒤enforce: 'pre',order: 'post'세 지점)으로 클라이언트generateBundle전후의 RSC 번들importedCss와 plugin-rsc가 만든 manifest를 찍었습니다. (원문 로그: 작업 디렉터리diag-unfixed.log)수정 후에는 같은 지점에서 다음처럼 의존성이 남습니다.
사용자가 확인한 현상과도 맞습니다. 클라이언트 페이지(
'use client'편집 페이지)의clientReferenceDeps에는 CSS가 있어서 그 페이지를 prefetch하는 목록만 정상이고, 나머지 서버 페이지의<link rel="stylesheet">는 아예 만들어지지 않았습니다 (수정 전notice/index.html에는 stylesheet 링크가 0개).동작 (변경 내용)
packages/vite-plugin/src/plugin.tsimportedCss를 더 이상 수정하지 않습니다. 서버·클라이언트가 공유하는 CSS 의존성은 서버/클라이언트 모두 그대로입니다.generateBundle(plugin-rsc보다 앞)에서, 클라이언트가 이미 가진 CSS를 서버 번들이 참조하면 plugin-rsc가 들고 있는 서버 번들의 그 assetfileName을 임시 이름(<file>.devup-forwarded)으로 바꿉니다. plugin-rsc는emitFile에 그fileName을 쓰므로 실제 파일은 한 번만 emit되고 충돌이 없습니다.devup-ui:restore-forwarded-css(generateBundle,order: 'post')가 plugin-rsc 이후fileName을 되돌리고 임시 파일을 출력에서 지웁니다.DevupUI()는 이제 플러그인 두 개의 배열을 반환합니다 (PluginOption타입은 그대로이고plugins: [DevupUI()]에서는 그대로 쓸 수 있습니다).rsc:minimal플러그인의api.manager.bundles에서 가져옵니다. 훅에 전달되는bundle은 플러그인마다 별개의 뷰라서, Devup UI가 받은 서버 번들의 asset을 고쳐도 plugin-rsc에는 반영되지 않습니다 (직접 확인했습니다).importedCssSet은 공유 객체라 이전 방식이 작동했을 뿐입니다.devup-ui(-N).css)만 다뤘습니다. 이제 클라이언트에 이미 있는 어떤 CSS든 같은 방식으로 한 번만 emit됩니다. 이름에 해시가 들어 있어 같은 이름이면 내용이 같습니다.대안으로 검토했다가 버린 것: 겹침을
importedCss에서 지우지 않고 중복 emit을 그냥 두는 방법은 실제로 manifest가 달라집니다 (plugin-rsc의 emit이 클라이언트 asset을 덮어써서.vite/manifest.json에서_devup-ui*.css항목이 사라집니다). 그래서 이름만 바꿔 한 번만 emit하게 했습니다.새로 생기는 오류
없습니다.
호환성
rsc:minimal플러그인이 없으면 아무것도 하지 않습니다 (getRscServerBundles가 빈 배열). 일반 Vite 빌드, Storybook, 라이브러리 모드는 동작이 같습니다.devup-ui.css)인 경우에도 같은 경로를 탑니다. 재현 앱에서 per-file/singleCss 둘 다 검증했습니다.apply: 'build'이고 변경된 훅은 빌드의generateBundle뿐이라 dev 동작은 같습니다.enforce: 'pre')는 plugin-rsc 앞, 복원 플러그인은order: 'post'로 plugin-rsc 뒤, Vite의 manifest 플러그인 앞에서 실행됩니다. 따라서.vite/manifest.json의 CSS 항목도 유지됩니다.importedCss는 항상 온전하므로 CSS가 사라지는 일은 없고, 최악의 경우 이전의 FILE_NAME_CONFLICT 경고로 돌아갑니다.남는 한계
rsc:minimal플러그인의api.manager.bundles(@experimental)에 기대고 있습니다. plugin-rsc 업스트림이emitFile전에 클라이언트 번들을 확인하게 되면 이 우회는 필요 없어집니다.검증
재현 앱
apps/vinext-rsc-css-repro(vite 8.3.1, vinext 1.0.0, @vitejs/plugin-rsc 0.5.35 고정. 리포트와 같은 버전이며 워크스페이스에서 허용됩니다. apps/landing은 vinext 1.0.0-beta.12 / vite 8.3.0). 공통PageTitle(Flex/Box/Text, align-items, justify-content: space-between, gap, margin-bottom, 단순<button>)을 서버 목록 페이지 3개(/notice/,/admins/,/users/)와'use client'편집 페이지(/users/edit/)가 공유하고,/users/만 편집 페이지로 링크합니다.output: 'export',trailingSlash: true, 기본 CSS 분리와DEVUP_SINGLE_CSS=1.Playwright(
bun run test:e2e:rsc-css)는 정적 빌드에서 새 브라우저 컨텍스트로 각 경로 직접 진입 + 새로고침(4건), 4개 경로의 모든 진입 순서 24가지, 편집 페이지(1건)를 검사합니다. 편집 페이지로의 prefetch 요청은 차단해서 서버가 렌더한 정보만으로 스타일이 있어야 하게 했습니다. 헤더는data-page-title로 찾고,getComputedStyle로display: flex,justify-content: space-between,align-items: center,margin-bottom: 20px, 안쪽 그룹gap: 12px를,getBoundingClientRect로 제목이 시작에, 오른쪽 슬롯이 끝에 붙는지를 확인합니다. 또 헤더가 쓰는 모든 클래스에 대해 실제 로드된<link>스타일시트에 규칙이 있는지 확인합니다. 파일 번호·해시·클래스명은 어디에도 쓰지 않습니다.수정 전 플러그인(origin/main)에서:
(통과한 2건은 클라이언트 페이지인 편집 페이지 자신의 두 테스트입니다.)
수정 후:
수정 후 빌드에는
FILE_NAME_CONFLICT가 없고,dist에.devup-forwarded임시 파일이 남지 않으며,.vite/manifest.json에_devup-ui*.css항목이 유지됩니다.단위 테스트(
packages/vite-plugin/src/__tests__/plugin.test.ts): 서버importedCss가 그대로이고 plugin-rsc가 emit하는 이름이 클라이언트와 겹치지 않으며(per-file, singleCss), 복원 후 임시 파일이 사라지고fileName이 돌아오는 것, 클라이언트가 내보내지 않는 CSS는 건드리지 않는 것, asset이 아닌 항목·클라이언트 번들·plugin-rsc 정보 없음·no-write 번들을 건드리지 않는 것. 기존의importedCss를 지우는 전제의 테스트 3건(서버 CSS 전달 안 함, no-write 번들, 다른 출력 이름)은 이 변경과 모순이라 새 동작 기준으로 바꿨고, 나머지 기존 테스트는 그대로입니다.게이트:
cargo fmt,cargo +1.99 clippy --workspace --all-targets -- -D warnings,cargo test --workspace,bun run build,bun test(100% 커버리지, 5482 pass, 0 fail),bun run lint(기존 경고 2건뿐), landing 빌드 후 기존 landing e2e(build-integrity, computed-styles, routes 20건) 통과.main에 있는 Rust 1.99 clippy 대응(assert!(x.is_empty())계열)도 테스트 코드에서만 함께 고쳤습니다. 패키지 동작에는 영향이 없어 changepack은 vite-plugin Patch만 추가했습니다.CI:
publish.yml에vinext-rsc-css-e2e잡(캐시,timeout-minutes: 30)을 추가해 per-file과 singleCss 두 빌드에서 위 테스트를 실행합니다.패치 릴리스:
.changepacks/changepack_log_vite_rsc_shared_css.json(packages/vite-plugin/package.json: Patch). 병합하면 CI가 배포합니다.