@docsector/docsector-reader 0.3.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/package.json +2 -1
- package/src/components/DMenu.vue +1 -4
- package/src/components/DMenuItem.vue +3 -11
- package/src/components/DMermaidDiagram.vue +103 -0
- package/src/components/DPageSection.vue +15 -0
- package/src/pages/guide/i18n-and-markdown.overview.en-US.md +11 -0
- package/src/pages/guide/i18n-and-markdown.overview.pt-BR.md +11 -0
- package/src/pages/index.js +16 -0
- package/src/pages/manual/components/d-mermaid-diagram.overview.en-US.md +31 -0
- package/src/pages/manual/components/d-mermaid-diagram.overview.pt-BR.md +29 -0
- package/src/pages/manual/components/d-mermaid-diagram.showcase.en-US.md +33 -0
- package/src/pages/manual/components/d-mermaid-diagram.showcase.pt-BR.md +33 -0
- package/src/quasar.factory.js +75 -3
package/README.md
CHANGED
|
@@ -21,6 +21,7 @@ Transform Markdown content into beautiful, navigable documentation sites — wit
|
|
|
21
21
|
## ✨ Features
|
|
22
22
|
|
|
23
23
|
- 📝 **Markdown Rendering** — Write docs in Markdown, rendered with syntax highlighting (Prism.js)
|
|
24
|
+
- 🧩 **Mermaid Diagrams** — Native support for fenced ` ```mermaid ` blocks, with automatic dark/light theme switching
|
|
24
25
|
- 🌍 **Internationalization (i18n)** — Multi-language support with HJSON locale files and per-page translations
|
|
25
26
|
- 🌗 **Dark/Light Mode** — Automatic theme switching with Quasar Dark Plugin
|
|
26
27
|
- 🔗 **Anchor Navigation** — Right-side Table of Contents tree with scroll tracking
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docsector/docsector-reader",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "A documentation rendering engine built with Vue 3, Quasar v2 and Vite. Transform Markdown into beautiful, navigable documentation sites.",
|
|
5
5
|
"productName": "Docsector Reader",
|
|
6
6
|
"author": "Rodrigo de Araujo Vieira",
|
|
@@ -70,6 +70,7 @@
|
|
|
70
70
|
"hjson": "^3.2.2",
|
|
71
71
|
"markdown-it": "^13.0.1",
|
|
72
72
|
"markdown-it-attrs": "^4.1.6",
|
|
73
|
+
"mermaid": "^11.0.0",
|
|
73
74
|
"prismjs": "^1.27.0",
|
|
74
75
|
"q-colorize-mixin": "^2.0.0-alpha.5"
|
|
75
76
|
},
|
package/src/components/DMenu.vue
CHANGED
|
@@ -100,10 +100,7 @@ const getMenuItemHeaderLabel = (meta) => {
|
|
|
100
100
|
const label = meta.menu.header.label
|
|
101
101
|
if (label[0] === '.') { // Node path
|
|
102
102
|
const path = `_.${meta.type}${label}._`
|
|
103
|
-
|
|
104
|
-
return t(path)
|
|
105
|
-
}
|
|
106
|
-
return t(path, 'en-US')
|
|
103
|
+
return t(path)
|
|
107
104
|
}
|
|
108
105
|
return label // String raw
|
|
109
106
|
}
|
|
@@ -29,7 +29,7 @@ const props = defineProps({
|
|
|
29
29
|
|
|
30
30
|
const $q = useQuasar()
|
|
31
31
|
const $route = useRoute()
|
|
32
|
-
const { t
|
|
32
|
+
const { t } = useI18n()
|
|
33
33
|
|
|
34
34
|
const getMenuItemHeaderBackground = () => {
|
|
35
35
|
return $q.dark.isActive ? 'background-color: #1D1D1D !important' : 'background-color: #f5f5f5 !important'
|
|
@@ -37,22 +37,14 @@ const getMenuItemHeaderBackground = () => {
|
|
|
37
37
|
|
|
38
38
|
const getMenuItemLabel = (item, index) => {
|
|
39
39
|
const path = `_${item.path.replace(/_$/, '').replace(/\//g, '.')}._`
|
|
40
|
-
|
|
41
|
-
return t(path)
|
|
42
|
-
} else {
|
|
43
|
-
return t(path, 'en-US')
|
|
44
|
-
}
|
|
40
|
+
return t(path)
|
|
45
41
|
}
|
|
46
42
|
|
|
47
43
|
const getMenuItemSubheader = (meta) => {
|
|
48
44
|
const subheader = meta.menu.subheader
|
|
49
45
|
const path = `_.${meta.type}${subheader}._`
|
|
50
46
|
|
|
51
|
-
|
|
52
|
-
return t(path)
|
|
53
|
-
} else {
|
|
54
|
-
return t(path, 'en-US')
|
|
55
|
-
}
|
|
47
|
+
return t(path)
|
|
56
48
|
}
|
|
57
49
|
|
|
58
50
|
const getPageStatusText = (status) => {
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref, onMounted, watch } from 'vue'
|
|
3
|
+
import { useQuasar } from 'quasar'
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
content: {
|
|
7
|
+
type: String,
|
|
8
|
+
required: true
|
|
9
|
+
}
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
const $q = useQuasar()
|
|
13
|
+
|
|
14
|
+
let _counter = 0
|
|
15
|
+
const uid = `mermaid-${++_counter}-${Math.random().toString(36).slice(2, 7)}`
|
|
16
|
+
|
|
17
|
+
const svg = ref('')
|
|
18
|
+
const error = ref('')
|
|
19
|
+
|
|
20
|
+
async function render () {
|
|
21
|
+
error.value = ''
|
|
22
|
+
svg.value = ''
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
const mermaid = (await import('mermaid')).default
|
|
26
|
+
|
|
27
|
+
mermaid.initialize({
|
|
28
|
+
startOnLoad: false,
|
|
29
|
+
theme: $q.dark.isActive ? 'dark' : 'default'
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const decoded = props.content
|
|
33
|
+
.replace(/{/g, '{')
|
|
34
|
+
.replace(/}/g, '}')
|
|
35
|
+
.replace(/&/g, '&')
|
|
36
|
+
|
|
37
|
+
const { svg: rendered } = await mermaid.render(uid, decoded)
|
|
38
|
+
svg.value = rendered
|
|
39
|
+
} catch (e) {
|
|
40
|
+
error.value = e?.message || 'Mermaid render error'
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
onMounted(render)
|
|
45
|
+
|
|
46
|
+
watch(() => $q.dark.isActive, render)
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<template>
|
|
50
|
+
<div class="d-mermaid-diagram">
|
|
51
|
+
<div
|
|
52
|
+
v-if="svg"
|
|
53
|
+
class="d-mermaid-diagram__svg"
|
|
54
|
+
v-html="svg"
|
|
55
|
+
/>
|
|
56
|
+
<div
|
|
57
|
+
v-else-if="error"
|
|
58
|
+
class="d-mermaid-diagram__error"
|
|
59
|
+
>
|
|
60
|
+
<pre>{{ error }}</pre>
|
|
61
|
+
<pre class="d-mermaid-diagram__source">{{ content }}</pre>
|
|
62
|
+
</div>
|
|
63
|
+
<div
|
|
64
|
+
v-else
|
|
65
|
+
class="d-mermaid-diagram__loading"
|
|
66
|
+
/>
|
|
67
|
+
</div>
|
|
68
|
+
</template>
|
|
69
|
+
|
|
70
|
+
<style lang="sass">
|
|
71
|
+
.d-mermaid-diagram
|
|
72
|
+
margin: 1rem 0
|
|
73
|
+
display: flex
|
|
74
|
+
justify-content: center
|
|
75
|
+
|
|
76
|
+
&__svg
|
|
77
|
+
svg
|
|
78
|
+
max-width: 100%
|
|
79
|
+
height: auto
|
|
80
|
+
|
|
81
|
+
&__error
|
|
82
|
+
width: 100%
|
|
83
|
+
padding: 0.75rem 1rem
|
|
84
|
+
border-left: 3px solid #e53935
|
|
85
|
+
background: rgba(229, 57, 53, 0.08)
|
|
86
|
+
font-size: 0.85em
|
|
87
|
+
pre
|
|
88
|
+
margin: 0
|
|
89
|
+
|
|
90
|
+
&__loading
|
|
91
|
+
width: 100%
|
|
92
|
+
min-height: 80px
|
|
93
|
+
opacity: 0.3
|
|
94
|
+
background: currentColor
|
|
95
|
+
border-radius: 4px
|
|
96
|
+
animation: mermaid-pulse 1.2s ease-in-out infinite
|
|
97
|
+
|
|
98
|
+
@keyframes mermaid-pulse
|
|
99
|
+
0%, 100%
|
|
100
|
+
opacity: 0.15
|
|
101
|
+
50%
|
|
102
|
+
opacity: 0.3
|
|
103
|
+
</style>
|
|
@@ -11,6 +11,7 @@ import DH4 from './DH4.vue'
|
|
|
11
11
|
import DH5 from './DH5.vue'
|
|
12
12
|
import DH6 from './DH6.vue'
|
|
13
13
|
import DPageSourceCode from './DPageSourceCode.vue'
|
|
14
|
+
import DMermaidDiagram from './DMermaidDiagram.vue'
|
|
14
15
|
|
|
15
16
|
const props = defineProps({
|
|
16
17
|
id: {
|
|
@@ -82,6 +83,15 @@ const tokenized = computed(() => {
|
|
|
82
83
|
case 'fence': {
|
|
83
84
|
const info = element.info.split(' ')
|
|
84
85
|
const language = info[0]
|
|
86
|
+
|
|
87
|
+
if (language === 'mermaid') {
|
|
88
|
+
tokens.push({
|
|
89
|
+
tag: 'mermaid',
|
|
90
|
+
content: element.content
|
|
91
|
+
})
|
|
92
|
+
break
|
|
93
|
+
}
|
|
94
|
+
|
|
85
95
|
const filename = info[1] ? info[1].replace('filename=', '').replace(/"/g, '') : ''
|
|
86
96
|
|
|
87
97
|
tokens.push({
|
|
@@ -229,6 +239,11 @@ const tokenized = computed(() => {
|
|
|
229
239
|
:language="token.info"
|
|
230
240
|
:filename="token.filename"
|
|
231
241
|
/>
|
|
242
|
+
|
|
243
|
+
<d-mermaid-diagram
|
|
244
|
+
v-else-if="token.tag === 'mermaid'"
|
|
245
|
+
:content="token.content"
|
|
246
|
+
/>
|
|
232
247
|
</template>
|
|
233
248
|
</section>
|
|
234
249
|
</template>
|
|
@@ -54,6 +54,17 @@ Fenced code blocks support syntax highlighting via Prism.js:
|
|
|
54
54
|
- `html` — HTML markup
|
|
55
55
|
- `javascript` — JavaScript code
|
|
56
56
|
|
|
57
|
+
### Mermaid Diagrams
|
|
58
|
+
|
|
59
|
+
You can render Mermaid diagrams using fenced blocks with the `mermaid` language indicator. The diagrams automatically adapt to light and dark modes.
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
```mermaid
|
|
63
|
+
flowchart TD
|
|
64
|
+
A[Start] --> B[End]
|
|
65
|
+
```
|
|
66
|
+
```
|
|
67
|
+
|
|
57
68
|
### Custom Attributes
|
|
58
69
|
|
|
59
70
|
The `markdown-it-attrs` plugin enables custom attributes using `:attr;` syntax:
|
|
@@ -54,6 +54,17 @@ Blocos de código cercados suportam syntax highlighting via Prism.js:
|
|
|
54
54
|
- `html` — Markup HTML
|
|
55
55
|
- `javascript` — Código JavaScript
|
|
56
56
|
|
|
57
|
+
### Diagramas Mermaid
|
|
58
|
+
|
|
59
|
+
Você pode renderizar diagramas Mermaid usando blocos de código com o indicador de linguagem `mermaid`. Os diagramas se adaptam automaticamente aos modos claro e escuro.
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
```mermaid
|
|
63
|
+
flowchart TD
|
|
64
|
+
A[Início] --> B[Fim]
|
|
65
|
+
```
|
|
66
|
+
```
|
|
67
|
+
|
|
57
68
|
### Atributos Customizados
|
|
58
69
|
|
|
59
70
|
O plugin `markdown-it-attrs` permite atributos customizados usando sintaxe `:attr;`:
|
package/src/pages/index.js
CHANGED
|
@@ -239,6 +239,22 @@ export default {
|
|
|
239
239
|
}
|
|
240
240
|
},
|
|
241
241
|
|
|
242
|
+
'/components/d-mermaid-diagram': {
|
|
243
|
+
config: {
|
|
244
|
+
icon: 'account_tree',
|
|
245
|
+
status: 'done',
|
|
246
|
+
type: 'manual',
|
|
247
|
+
menu: {},
|
|
248
|
+
subpages: {
|
|
249
|
+
showcase: true
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
data: {
|
|
253
|
+
'en-US': { title: 'DMermaidDiagram' },
|
|
254
|
+
'pt-BR': { title: 'DMermaidDiagram' }
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
|
|
242
258
|
'/components/d-page-blockquote': {
|
|
243
259
|
config: {
|
|
244
260
|
icon: 'format_quote',
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
## Overview
|
|
2
|
+
|
|
3
|
+
`DMermaidDiagram` is an internal component responsible for rendering **Mermaid** diagrams. It intercepts code blocks fenced with the `mermaid` language indicator and renders them as SVG visuals instead of formatted text.
|
|
4
|
+
|
|
5
|
+
The component uses lazy-loading — the `mermaid` library is only fetched when a diagram is present on the page, keeping the initial bundle size small.
|
|
6
|
+
|
|
7
|
+
## Props
|
|
8
|
+
|
|
9
|
+
| Prop | Type | Required | Default | Description |
|
|
10
|
+
|------|------|----------|---------|-------------|
|
|
11
|
+
| `content` | `String` | Yes | — | The raw Mermaid definition syntax |
|
|
12
|
+
|
|
13
|
+
## Features
|
|
14
|
+
|
|
15
|
+
### Direct Rendering
|
|
16
|
+
|
|
17
|
+
Diagrams are parsed and rendered directly into SVGs via the official `mermaid.render()` API. The SVGs are fully responsive.
|
|
18
|
+
|
|
19
|
+
### Dark/Light Mode Aware
|
|
20
|
+
|
|
21
|
+
The diagrams inherit their theme dynamically. When `$q.dark.isActive` toggles, `DMermaidDiagram` detects the change, re-initializes Mermaid with the new theme context, and entirely redraws the instance to match Docsector's overall appearance.
|
|
22
|
+
|
|
23
|
+
### Error Handling
|
|
24
|
+
|
|
25
|
+
If the provided syntax is invalid, the component gracefully catches the parsing error and displays a structured error block along with the raw source code.
|
|
26
|
+
|
|
27
|
+
This guarantees the page will not break and aids during development.
|
|
28
|
+
|
|
29
|
+
### HTML Entity Decoding
|
|
30
|
+
|
|
31
|
+
Curly braces `{` and `}` are properly decoded before rendering, ensuring compatibility with Vue's i18n interpolation requirements while allowing Mermaid logic to function intact.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
## Visão geral
|
|
2
|
+
|
|
3
|
+
O `DMermaidDiagram` é um componente interno responsável por renderizar diagramas **Mermaid**. Ele intercepta os blocos de código marcados com o indicador de linguagem `mermaid` e os renderiza como elementos SVG ao invés de texto puro.
|
|
4
|
+
|
|
5
|
+
O componente utiliza _lazy-loading_ — a biblioteca `mermaid` apenas é baixada quando de fato existe um diagrama na página, mantendo o tamanho inicial do site otimizado.
|
|
6
|
+
|
|
7
|
+
## Props
|
|
8
|
+
|
|
9
|
+
| Prop | Tipo | Obrigatório | Valor padrão | Descrição |
|
|
10
|
+
|------|------|----------|---------|-------------|
|
|
11
|
+
| `content` | `String` | Sim | — | A sintaxe pura da definição do Mermaid |
|
|
12
|
+
|
|
13
|
+
## Funcionalidades
|
|
14
|
+
|
|
15
|
+
### Renderização Direta
|
|
16
|
+
|
|
17
|
+
Os diagramas são lidos e renderizados diretamente em SVGs pela API oficial `mermaid.render()`. Os SVGs gerados são totalmente responsivos.
|
|
18
|
+
|
|
19
|
+
### Adaptação aos Modos Claro/Escuro
|
|
20
|
+
|
|
21
|
+
Os diagramas herdam a temática que você desejar. Quando o indicador `$q.dark.isActive` for alternado, O `DMermaidDiagram` rastreará tal mudança, re-inicializará um Mermaid com o novo contexto de tema e irá redesenhar toda a instância para espelhar a aparência visual geral do Docsector.
|
|
22
|
+
|
|
23
|
+
### Tratamento de Falhas
|
|
24
|
+
|
|
25
|
+
Se a sintaxe fornecida estiver incorreta, o componente elegantemente detecta a falha sem que a aplicação se quebre. Exibindo na tela, apenas para si, um bloco com erro e o código original abaixo com dicas do erro em desenvolvimento.
|
|
26
|
+
|
|
27
|
+
### Decodificação de Entidades HTML
|
|
28
|
+
|
|
29
|
+
Chaves numéricas de texto `{` e `}` tem seus devidos caracteres tratados antes do envio de renderização, garantindo harmonia entre os requisitos de visualização na extensão i18n padrão do Vue junto da estabilidade do código original desenhado para Mermaid em tempo-real.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
## Flowchart
|
|
2
|
+
|
|
3
|
+
```mermaid
|
|
4
|
+
flowchart TD
|
|
5
|
+
A[Christmas] -->|Get money| B(Go shopping)
|
|
6
|
+
B --> C{Let me think}
|
|
7
|
+
C -->|One| D[Laptop]
|
|
8
|
+
C -->|Two| E[iPhone]
|
|
9
|
+
C -->|Three| F[fa:fa-car Car]
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Sequence Diagram
|
|
13
|
+
|
|
14
|
+
```mermaid
|
|
15
|
+
sequenceDiagram
|
|
16
|
+
Alice->>+John: Hello John, how are you?
|
|
17
|
+
Alice->>+John: John, can you hear me?
|
|
18
|
+
John-->>-Alice: Hi Alice, I can hear you!
|
|
19
|
+
John-->>-Alice: I feel great!
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## State Diagram
|
|
23
|
+
|
|
24
|
+
```mermaid
|
|
25
|
+
stateDiagram-v2
|
|
26
|
+
[*] --> Still
|
|
27
|
+
Still --> [*]
|
|
28
|
+
|
|
29
|
+
Still --> Moving
|
|
30
|
+
Moving --> Still
|
|
31
|
+
Moving --> Crash
|
|
32
|
+
Crash --> [*]
|
|
33
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
## Fluxograma
|
|
2
|
+
|
|
3
|
+
```mermaid
|
|
4
|
+
flowchart TD
|
|
5
|
+
A[Natal] -->|Ganha dinheiro| B(Ir às compras)
|
|
6
|
+
B --> C{Deixe-me pensar}
|
|
7
|
+
C -->|Um| D[Notebook]
|
|
8
|
+
C -->|Dois| E[iPhone]
|
|
9
|
+
C -->|Três| F[fa:fa-car Carro]
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Diagrama de Sequência
|
|
13
|
+
|
|
14
|
+
```mermaid
|
|
15
|
+
sequenceDiagram
|
|
16
|
+
Alice->>+John: Olá John, como você está?
|
|
17
|
+
Alice->>+John: John, consegue me ouvir?
|
|
18
|
+
John-->>-Alice: Oi Alice, consigo sim!
|
|
19
|
+
John-->>-Alice: Estou ótimo!
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Diagrama de Estado
|
|
23
|
+
|
|
24
|
+
```mermaid
|
|
25
|
+
stateDiagram-v2
|
|
26
|
+
[*] --> Parado
|
|
27
|
+
Parado --> [*]
|
|
28
|
+
|
|
29
|
+
Parado --> Movendo
|
|
30
|
+
Movendo --> Parado
|
|
31
|
+
Movendo --> Colisão
|
|
32
|
+
Colisão --> [*]
|
|
33
|
+
```
|
package/src/quasar.factory.js
CHANGED
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
* @param {Function} [options.extendViteConf] - Additional Vite config extension
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import { readFileSync, existsSync } from 'fs'
|
|
26
|
+
import { readFileSync, existsSync, rmSync } from 'fs'
|
|
27
|
+
import { createHash } from 'crypto'
|
|
27
28
|
import { resolve } from 'path'
|
|
28
29
|
import HJSON from 'hjson'
|
|
29
30
|
|
|
@@ -57,6 +58,46 @@ function getPackageRoot (projectRoot) {
|
|
|
57
58
|
return projectRoot
|
|
58
59
|
}
|
|
59
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Create a Vite plugin that watches consumer content files (pages/index.js,
|
|
63
|
+
* i18n languages, etc.) and forces the Vite dep optimizer to re-run when
|
|
64
|
+
* they change.
|
|
65
|
+
*
|
|
66
|
+
* Why: The router module (`routes.js`) imports consumer content via the
|
|
67
|
+
* `pages` alias. Vite's dep optimizer pre-bundles the router with the
|
|
68
|
+
* consumer content inlined, but the optimizer cache hash is based on config
|
|
69
|
+
* and lockfile only — NOT on consumer source files. So when pages/index.js
|
|
70
|
+
* changes during development, the optimizer serves stale pre-bundled code
|
|
71
|
+
* until the cache is manually cleared.
|
|
72
|
+
*
|
|
73
|
+
* Fix: When pages/index.js changes, the watcher plugin clears the dep cache,
|
|
74
|
+
* sets an env flag, and restarts the server. On restart, the config reads the
|
|
75
|
+
* flag and sets `optimizeDeps.force = true`, which makes Vite generate a new
|
|
76
|
+
* browserHash — effectively busting the browser module cache.
|
|
77
|
+
*/
|
|
78
|
+
function createPagesWatchPlugin (projectRoot) {
|
|
79
|
+
const pagesIndex = resolve(projectRoot, 'src', 'pages', 'index.js')
|
|
80
|
+
return {
|
|
81
|
+
name: 'docsector-pages-watch',
|
|
82
|
+
configureServer (server) {
|
|
83
|
+
server.watcher.on('change', (changedPath) => {
|
|
84
|
+
if (changedPath === pagesIndex) {
|
|
85
|
+
server.config.logger.info(
|
|
86
|
+
'\\x1b[36m[docsector]\\x1b[0m pages/index.js changed — clearing dep cache and restarting...',
|
|
87
|
+
{ timestamp: true }
|
|
88
|
+
)
|
|
89
|
+
// Signal the restarted config to force a new optimizer hash
|
|
90
|
+
process.env.__DOCSECTOR_FORCE_OPTIMIZE = '1'
|
|
91
|
+
// Delete the stale optimizer cache
|
|
92
|
+
const cacheDir = resolve(projectRoot, 'node_modules', '.q-cache')
|
|
93
|
+
rmSync(cacheDir, { recursive: true, force: true })
|
|
94
|
+
server.restart()
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
60
101
|
/**
|
|
61
102
|
* Create the HJSON Vite plugin for loading .hjson files as ES modules.
|
|
62
103
|
*/
|
|
@@ -145,6 +186,7 @@ export function createQuasarConfig (options = {}) {
|
|
|
145
186
|
|
|
146
187
|
vitePlugins: [
|
|
147
188
|
createHjsonPlugin(),
|
|
189
|
+
createPagesWatchPlugin(projectRoot),
|
|
148
190
|
...vitePlugins
|
|
149
191
|
],
|
|
150
192
|
|
|
@@ -152,6 +194,32 @@ export function createQuasarConfig (options = {}) {
|
|
|
152
194
|
viteConf.resolve = viteConf.resolve || {}
|
|
153
195
|
viteConf.resolve.alias = viteConf.resolve.alias || {}
|
|
154
196
|
|
|
197
|
+
// When the pages watcher plugin triggers a restart, it sets this env
|
|
198
|
+
// flag so we force Vite to generate a fresh browserHash. This busts
|
|
199
|
+
// the browser's module cache for pre-bundled deps whose content changed.
|
|
200
|
+
viteConf.optimizeDeps = viteConf.optimizeDeps || {}
|
|
201
|
+
if (process.env.__DOCSECTOR_FORCE_OPTIMIZE) {
|
|
202
|
+
delete process.env.__DOCSECTOR_FORCE_OPTIMIZE
|
|
203
|
+
viteConf.optimizeDeps.force = true
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Include a hash of pages/index.js in the optimizer config so that
|
|
207
|
+
// Vite's configHash (and thus browserHash) changes whenever page
|
|
208
|
+
// definitions change. This prevents the browser from serving stale
|
|
209
|
+
// pre-bundled router modules from its module cache.
|
|
210
|
+
const pagesFile = resolve(projectRoot, 'src', 'pages', 'index.js')
|
|
211
|
+
if (existsSync(pagesFile)) {
|
|
212
|
+
const pagesHash = createHash('sha256')
|
|
213
|
+
.update(readFileSync(pagesFile))
|
|
214
|
+
.digest('hex')
|
|
215
|
+
.slice(0, 8)
|
|
216
|
+
viteConf.optimizeDeps.esbuildOptions = viteConf.optimizeDeps.esbuildOptions || {}
|
|
217
|
+
viteConf.optimizeDeps.esbuildOptions.define = {
|
|
218
|
+
...(viteConf.optimizeDeps.esbuildOptions.define || {}),
|
|
219
|
+
__DOCSECTOR_PAGES_HASH__: JSON.stringify(pagesHash)
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
155
223
|
// Deduplicate Vue ecosystem packages to prevent dual-instance issues.
|
|
156
224
|
// When the package is installed from NPM, Vue, vue-router, vuex, etc.
|
|
157
225
|
// can end up duplicated (one copy in consumer's node_modules, another
|
|
@@ -177,14 +245,18 @@ export function createQuasarConfig (options = {}) {
|
|
|
177
245
|
...(viteConf.optimizeDeps.include || []),
|
|
178
246
|
'vue', 'vue-router', 'vuex', 'vue-i18n',
|
|
179
247
|
'prismjs', 'markdown-it', 'markdown-it-attrs',
|
|
180
|
-
'hjson', 'q-colorize-mixin'
|
|
248
|
+
'hjson', 'q-colorize-mixin', 'mermaid'
|
|
181
249
|
]
|
|
182
250
|
|
|
183
|
-
// Exclude boot files from pre-bundling.
|
|
251
|
+
// Exclude boot files and the router from pre-bundling.
|
|
184
252
|
// Boot files (especially boot/i18n) import the consumer's src/i18n/index.js
|
|
185
253
|
// which uses import.meta.glob — a compile-time Vite directive that only
|
|
186
254
|
// works in source files. If pre-bundled, the glob calls become dead code
|
|
187
255
|
// and no i18n messages are loaded.
|
|
256
|
+
// The router is excluded because routes.js imports consumer content via
|
|
257
|
+
// the `pages` alias. If pre-bundled, consumer content gets embedded in
|
|
258
|
+
// the optimizer cache whose hash doesn't track source file changes,
|
|
259
|
+
// causing stale routes after editing pages/index.js.
|
|
188
260
|
viteConf.optimizeDeps.exclude = [
|
|
189
261
|
...(viteConf.optimizeDeps.exclude || []),
|
|
190
262
|
'boot/i18n', 'boot/store', 'boot/QZoom', 'boot/axios'
|