Skip to content

Commit 6f4c4b7

Browse files
authored
custom q packing updates (#958)
- **working docs** - **config options - less mangling of classes/fcns** - **type massage for indexed question components** - **add names on custom components** - **rm sk-contributor...** - **update working doc** - **followups on rming sk-contributor** - **update standalone-ui readme**
2 parents 3d2045a + aebb83b commit 6f4c4b7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+1402
-2204
lines changed

.github/workflows/ci-pkg-cli.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,63 @@ jobs:
8585
# Clean up CouchDB
8686
yarn couchdb:stop
8787
88+
# Custom Questions Workflow Test
89+
- name: Create empty project for custom questions test
90+
working-directory: packages/cli
91+
run: yarn try:init:empty
92+
93+
- name: Start studio mode for custom questions workflow
94+
working-directory: packages/cli/testproject-empty
95+
run: |
96+
npm run studio --no-browser > studio.log 2>&1 &
97+
echo "Studio process started with PID: $!"
98+
sleep 2
99+
100+
- name: Wait for studio server to be ready
101+
working-directory: packages/cli/testproject-empty
102+
run: |
103+
echo "Giving studio 3 minutes to build and start..."
104+
sleep 180
105+
echo "Done waiting, checking studio log:"
106+
tail -20 studio.log || echo "No log file"
107+
108+
- name: Run custom questions studio mode tests
109+
working-directory: packages/cli
110+
run: yarn test:e2e:custom:studio:headless
111+
112+
- name: Shutdown studio mode
113+
if: always()
114+
run: |
115+
kill $(lsof -t -i:7174) || true
116+
kill $(lsof -t -i:3001) || true
117+
kill $(lsof -t -i:5985) || true
118+
119+
- name: Start dev mode for custom questions verification
120+
working-directory: packages/cli/testproject-empty
121+
run: |
122+
npm run dev &
123+
npx wait-on http://localhost:5173 --timeout 60000
124+
125+
- name: Run custom questions dev mode tests
126+
working-directory: packages/cli
127+
run: yarn test:e2e:custom:dev:headless
128+
129+
- name: Final cleanup
130+
if: always()
131+
run: |
132+
kill $(lsof -t -i:6173) || true
133+
kill $(lsof -t -i:7174) || true
134+
kill $(lsof -t -i:3001) || true
135+
kill $(lsof -t -i:5985) || true
136+
137+
- name: Upload studio log on failure
138+
uses: actions/upload-artifact@v4
139+
if: failure()
140+
with:
141+
name: studio-log
142+
path: packages/cli/testproject-empty/studio.log
143+
retention-days: 7
144+
88145
- name: Upload screenshots on failure
89146
uses: actions/upload-artifact@v4
90147
if: failure()

agent/BACKPORT_CHECKLIST.md

Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
# Backport Checklist for Scaffolding Templates
2+
3+
Changes tested in `/flutor` that need to be propagated to vue-skuilder template packages.
4+
5+
**Note:** This document is self-contained. All necessary code examples and rationale are included below.
6+
7+
## How to Use This Document
8+
9+
1. **Copy this file** to the vue-skuilder monorepo for reference
10+
2. **Apply changes 1-6** to the template packages (standalone-ui, sk-contributor)
11+
3. **Test** using the testing checklist at the bottom
12+
4. **Ignore** the "Infrastructure Changes" section - those are already in the monorepo
13+
14+
**Files to Update:**
15+
- `/packages/standalone-ui/vite.config.ts`
16+
- `/packages/standalone-ui/src/questions/index.ts`
17+
- `/packages/standalone-ui/src/main.ts`
18+
- `/packages/standalone-ui/src/questions/*QuestionView.vue` (all view components)
19+
- `/packages/sk-contributor/` (same files as above)
20+
- `/packages/standalone-ui/src/questions/README.md` (examples)
21+
22+
## Context
23+
24+
These fixes enable custom questions to work in both:
25+
- **Standalone mode** (`yarn dev`) - already worked
26+
- **Studio mode** (`yarn studio`) - now works after these fixes
27+
28+
The root cause was a combination of:
29+
1. Browser unable to resolve bare imports in dynamically loaded modules
30+
2. Missing view component names for runtime lookup
31+
3. Side-effect import not running (views array staying empty)
32+
4. Incorrect views export format for studio-ui consumption
33+
34+
## 1. Vite Config - External Dependencies & Terser
35+
**File:** `vite.config.ts`
36+
**Location:** Library build configuration
37+
**Change:**
38+
```typescript
39+
build: buildMode === 'library'
40+
? {
41+
// ...
42+
terserOptions: {
43+
keep_classnames: true,
44+
keep_fnames: true, // ADD: Preserve function names
45+
mangle: {
46+
properties: false, // ADD: Don't mangle static properties like seedData
47+
},
48+
},
49+
rollupOptions: {
50+
// CRITICAL: Do NOT externalize dependencies for studio mode
51+
// Browser cannot resolve bare imports without import maps
52+
external: [
53+
// Leave empty - bundle everything for browser compatibility
54+
],
55+
}
56+
}
57+
```
58+
**Why:**
59+
- Terser options prevent minification from mangling static properties (seedData, views, dataShapes)
60+
- Empty externals array bundles all dependencies so browser can load the module without import maps
61+
- Previously tried externalizing to avoid duplication, but browser can't resolve `import { X } from "@vue-skuilder/courseware"` at runtime
62+
**Affects:**
63+
- `/packages/standalone-ui/vite.config.ts`
64+
- CLI template generation for new projects
65+
66+
---
67+
68+
## 2. Question Index - Views Export Format
69+
**File:** `src/questions/index.ts`
70+
**Location:** `allCustomQuestions()` function
71+
**Change:**
72+
```typescript
73+
// OLD (broken):
74+
const views: ViewComponent[] = [];
75+
questionClasses.forEach((questionClass) => {
76+
if (questionClass.views) {
77+
questionClass.views.forEach((view) => {
78+
views.push(view);
79+
});
80+
}
81+
});
82+
83+
// NEW (working):
84+
const views: Array<{ name: string; component: ViewComponent }> = [];
85+
questionClasses.forEach((questionClass) => {
86+
if (questionClass.views) {
87+
questionClass.views.forEach((view) => {
88+
const viewName = (view as any).name || (view as any).__name;
89+
if (viewName) {
90+
if (!views.find((existing) => existing.name === viewName)) {
91+
views.push({ name: viewName, component: view });
92+
}
93+
} else {
94+
console.warn('[allCustomQuestions] View component missing name property:', view);
95+
}
96+
});
97+
}
98+
});
99+
```
100+
**Why:** Studio-ui expects `{ name, component }` format (see studio-ui/src/main.ts:183-189)
101+
**Affects:**
102+
- `/packages/standalone-ui/src/questions/index.ts`
103+
- `/packages/sk-contributor/src/questions/index.ts`
104+
105+
---
106+
107+
## 3. Question Index - TypeScript Interface
108+
**File:** `src/questions/index.ts`
109+
**Location:** `CustomQuestionsExport` interface
110+
**Change:**
111+
```typescript
112+
export interface CustomQuestionsExport {
113+
courses: CourseWare[];
114+
questionClasses: Array<typeof Question>;
115+
dataShapes: DataShape[];
116+
views: Array<{ name: string; component: ViewComponent }>; // CHANGED from ViewComponent[]
117+
inlineComponents: Record<string, any>;
118+
meta: { /* ... */ };
119+
}
120+
```
121+
**Why:** Matches runtime format
122+
**Affects:**
123+
- `/packages/standalone-ui/src/questions/index.ts`
124+
- `/packages/sk-contributor/src/questions/index.ts`
125+
126+
---
127+
128+
## 4. Main.ts - Import Questions Index
129+
**File:** `src/main.ts`
130+
**Location:** Before `allCourseWare.courses.push(exampleCourse)`
131+
**Change:**
132+
```typescript
133+
// Import allCourseWare singleton and exampleCourse
134+
import { allCourseWare } from '@vue-skuilder/courseware';
135+
// Import from index.ts to ensure view setup code runs
136+
import './questions/index'; // ADD THIS LINE
137+
import { exampleCourse } from './questions/exampleCourse';
138+
```
139+
**Why:** Ensures static view setup runs before course registration
140+
**Affects:**
141+
- `/packages/standalone-ui/src/main.ts`
142+
- `/packages/sk-contributor/src/main.ts`
143+
144+
---
145+
146+
## 5. Question Class - Direct Inline Views
147+
**File:** `src/questions/MyQuestion.ts`
148+
**Location:** Question class static properties
149+
**Change:**
150+
```typescript
151+
// Import at top
152+
import { markRaw } from 'vue';
153+
import MyQuestionView from './MyQuestionView.vue';
154+
155+
export class MyQuestion extends Question {
156+
public static dataShapes = [/* ... */];
157+
158+
// Direct inline registration - no external setup needed
159+
public static views = [markRaw(MyQuestionView)]; // CHANGED from empty array
160+
161+
// ...
162+
}
163+
```
164+
**Why:** Self-contained, works immediately, no fragile side-effects
165+
**Affects:**
166+
- Template examples in `/packages/standalone-ui/src/questions/README.md`
167+
- Template examples in `/packages/sk-contributor/src/questions/README.md`
168+
- Existing template questions (NumberRangeQuestion, etc.)
169+
170+
---
171+
172+
## 6. Vue Component - DefineOptions Name
173+
**File:** `src/questions/MyQuestionView.vue`
174+
**Location:** Script setup
175+
**Change:**
176+
```typescript
177+
<script setup lang="ts">
178+
import { defineOptions } from 'vue'; // ADD import
179+
180+
defineOptions({
181+
name: 'MyQuestionView' // ADD this block
182+
});
183+
184+
// rest of setup...
185+
```
186+
**Why:** Vue components need explicit names for runtime lookup
187+
**Affects:**
188+
- All template Vue view components
189+
- README examples
190+
191+
---
192+
193+
## 7. Remove Index.ts Side-Effects (Future)
194+
**File:** `src/questions/index.ts`
195+
**Location:** Top-level code
196+
**Change:**
197+
```typescript
198+
// REMOVE these lines (views should be set in question files directly):
199+
// import SustainedNoteQuestionView from './SustainedNoteQuestionView.vue';
200+
// SustainedNoteQuestion.views = [markRaw(SustainedNoteQuestionView)];
201+
```
202+
**Why:** Side-effects are fragile; prefer direct inline registration
203+
**Status:** Deferred until all templates use Pattern 1
204+
**Affects:**
205+
- `/packages/standalone-ui/src/questions/index.ts`
206+
207+
---
208+
209+
## Implementation Priority
210+
211+
### Phase 1 (Critical - Breaks studio mode)
212+
- [ ] #2: Fix views export format in index.ts
213+
- [ ] #3: Update TypeScript interface
214+
- [ ] #1: Add terser options to vite.config
215+
216+
### Phase 2 (Important - Breaks runtime)
217+
- [ ] #4: Add index.ts import to main.ts
218+
- [ ] #6: Add defineOptions to all template Vue components
219+
220+
### Phase 3 (Nice to have)
221+
- [ ] #5: Update documentation/examples to show direct inline pattern
222+
- [ ] #7: Remove side-effects from index.ts (future)
223+
224+
## Testing Checklist
225+
226+
After backporting, verify:
227+
- [ ] `yarn dev` works (standalone mode)
228+
- [ ] `yarn studio` works (studio mode)
229+
- [ ] Custom questions appear in studio CreateCardView
230+
- [ ] Card creation works with custom DataShapes
231+
- [ ] Seed data registration doesn't error
232+
- [ ] Cards render correctly in both modes
233+
- [ ] Custom inline markdown components work
234+
235+
## Infrastructure Changes (Already Done in Monorepo)
236+
237+
**⚠️ You do NOT need to apply these changes - they are already in the monorepo codebase.**
238+
239+
These were supporting infrastructure fixes made alongside the template changes:
240+
241+
### CLI - studio.ts
242+
**File:** `/packages/cli/src/commands/studio.ts`
243+
**What changed:** Config import path updated when copying to dist
244+
```typescript
245+
// Line ~1147
246+
configContent.importPath = '/assets/questions.mjs'; // Absolute path from root
247+
```
248+
**Why:** Ensures browser can find the bundled questions module
249+
250+
### Studio-UI - main.ts
251+
**File:** `/packages/studio-ui/src/main.ts`
252+
**What changed:**
253+
- Registers custom courses with `allCourseWare.courses.push(...customQuestions.courses)`
254+
- Added verbose debug logging for troubleshooting
255+
- Uses `/* @vite-ignore */` comment for dynamic import
256+
257+
**Why:** Studio-ui now properly integrates custom courses into the singleton
258+
259+
---
260+
261+
## Related Files
262+
263+
**Templates:**
264+
- `/packages/standalone-ui/src/questions/`
265+
- `/packages/sk-contributor/src/questions/`
266+
267+
**CLI Generation:**
268+
- `/packages/cli/src/utils/template.ts` (may need updates)
269+
- `/packages/cli/src/commands/scaffold.ts`
270+
271+
**Documentation:**
272+
- `/packages/standalone-ui/src/questions/README.md`
273+
- Main docs site (if applicable)

0 commit comments

Comments
 (0)