fix(frontend): each shared <style src> sheet sits at one block index everywhere, so vite build cannot depend on transform order (#4988)
CI & Build / Plugin hooks (push) Successful in 15s
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 56s
CI & Build / integration (push) Successful in 1m40s
CI & Build / Python tests (push) Successful in 2m37s
CI & Build / Build & push image (push) Successful in 56s

Run 8271 failed in the image build: "[vite:vue] Cannot read properties of undefined (reading 'scoped')" on moments-shared.css. plugin-vue caches one descriptor per src file and answers ?index=N from whichever component registered it last. RuleEditorSlideOver had moments-shared at block 2, while its other two importers have it at block 1. Step 2's new imports changed the transform order and exposed the bug.

- RuleEditorSlideOver: moments-shared is now loaded with an @import instead of a third <style src>.
- rules-shared.css sat at block 0 in the five panes and at block 1 in LessonDetailView, LessonEditorView and RuleEditorSlideOver, which is the same latent hazard. The three move to block 0.
- tests/test_frontend_shared_styles.py: a guard that every <style src> sheet sits at one index, plus a test that the guard can fail. vue-tsc cannot see this hazard, and vite build only runs after every test has passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-06 09:58:41 -04:00
co-authored by Claude Opus 5.5
parent 07d2542479
commit 1774ee3696
4 changed files with 77 additions and 13 deletions
+5 -4
View File
@@ -459,6 +459,11 @@ onMounted(() => {
</div>
</template>
<!-- `.rule-chip-preference` marks a preference among the rules offered, as it
does everywhere else a rule's kind is shown.
Block 0, as in every pane that loads it: a shared src must sit at
one index everywhere (tests/test_frontend_shared_styles.py). -->
<style src="@/assets/rules-shared.css" />
<style scoped>
.lesson-editor {
max-width: 820px;
@@ -606,7 +611,3 @@ onMounted(() => {
.le-small { padding: 0.2rem 0.7rem; font-size: var(--fs-size-label); }
.le-ghost:disabled { opacity: var(--fs-disabled-opacity); cursor: default; }
</style>
<!-- `.rule-chip-preference` marks a preference among the rules offered, as it
does everywhere else a rule's kind is shown. -->
<style src="@/assets/rules-shared.css" />