@@ -7,7 +7,7 @@ import * as parser from '../parser'
7
7
import { ResolvedSlidevOptions } from './options'
8
8
9
9
const regexId = / ^ \/ \@ s l i d e v \/ s l i d e \/ ( \d + ) \. ( m d | j s o n ) (?: \? i m p o r t ) ? $ /
10
- const regexIdQuery = / i d = ( \d + ?) \. ( m d | j s o n ) $ /
10
+ const regexIdQuery = / ( \d + ?) \. ( m d | j s o n ) $ /
11
11
12
12
export function getBodyJson ( req : Connect . IncomingMessage ) {
13
13
return new Promise < any > ( ( resolve , reject ) => {
@@ -34,15 +34,16 @@ export function sendHmrReload(server: ViteDevServer, modules: ModuleNode[]) {
34
34
type : 'update' ,
35
35
updates : modules . map < Update > ( m => ( {
36
36
acceptedPath : m . id || m . file ! ,
37
- path : m . id || m . file ! ,
37
+ path : m . file ! ,
38
38
timestamp,
39
39
type : 'js-update' ,
40
40
} ) ) ,
41
41
} )
42
42
}
43
43
44
44
export function createSlidesLoader ( { data, entry, clientRoot, themeRoot, userRoot } : ResolvedSlidevOptions ) : Plugin [ ] {
45
- let skipNext = false
45
+ const slidePrefix = '/@slidev/slides/'
46
+ const hmrNextModuleIds : string [ ] = [ ]
46
47
47
48
return [
48
49
{
@@ -65,19 +66,13 @@ export function createSlidesLoader({ data, entry, clientRoot, themeRoot, userRoo
65
66
if ( type === 'json' && req . method === 'POST' ) {
66
67
const body = await getBodyJson ( req )
67
68
Object . assign ( data . slides [ idx ] , body )
68
- skipNext = true
69
- await parser . save ( data , entry )
70
-
71
- sendHmrReload (
72
- server ,
73
- [
74
- `${ entry } ?id=${ idx } .md` ,
75
- `${ entry } ?id=${ idx } .json` ,
76
- ]
77
- . map ( id => server . moduleGraph . getModuleById ( id ) )
78
- . filter ( notNullish ) ,
69
+ hmrNextModuleIds . push (
70
+ `${ slidePrefix } ${ idx } .md` ,
71
+ `${ slidePrefix } ${ idx } .json` ,
79
72
)
80
73
74
+ await parser . save ( data , entry )
75
+
81
76
res . statusCode = 200
82
77
return res . end ( )
83
78
}
@@ -87,36 +82,54 @@ export function createSlidesLoader({ data, entry, clientRoot, themeRoot, userRoo
87
82
} ,
88
83
89
84
async handleHotUpdate ( ctx ) {
90
- if ( ctx . file === entry ) {
91
- if ( skipNext ) {
92
- skipNext = false
93
- return
94
- }
95
- const newData = await parser . load ( entry )
96
-
97
- if ( data . config . theme !== newData . config . theme )
98
- console . log ( 'Theme changed' )
99
- // TODO: restart the server
100
-
101
- const moduleEntries = [
102
- data . slides . length !== newData . slides . length && '/@slidev/routes' ,
103
- JSON . stringify ( data . config ) !== JSON . stringify ( newData . config ) && '/@slidev/configs' ,
104
- ...data . slides . map ( ( i , idx ) => `${ entry } ?id=${ idx } .md` ) ,
105
- ...data . slides . map ( ( i , idx ) => `${ entry } ?id=${ idx } .json` ) ,
106
- ]
107
- . filter ( isTruthy )
108
- . map ( id => ctx . server . moduleGraph . getModuleById ( id as string ) )
109
- . filter ( notNullish )
110
-
111
- data = newData
112
-
113
- moduleEntries . map ( m => ctx . server . moduleGraph . invalidateModule ( m ) )
114
- return moduleEntries
85
+ if ( ctx . file !== entry )
86
+ return
87
+
88
+ const newData = await parser . load ( entry )
89
+
90
+ if ( data . config . theme !== newData . config . theme )
91
+ console . log ( 'Theme changed' )
92
+ // TODO: restart the server
93
+
94
+ const moduleIds : ( string | false ) [ ] = [
95
+ ...hmrNextModuleIds ,
96
+ ]
97
+
98
+ hmrNextModuleIds . length = 0
99
+
100
+ if ( data . slides . length !== newData . slides . length )
101
+ moduleIds . push ( '/@slidev/routes' )
102
+
103
+ if ( JSON . stringify ( data . config ) !== JSON . stringify ( newData . config ) )
104
+ moduleIds . push ( '/@slidev/configs' )
105
+
106
+ const length = Math . max ( data . slides . length , newData . slides . length )
107
+
108
+ for ( let i = 0 ; i < length ; i ++ ) {
109
+ const a = data . slides [ i ]
110
+ const b = newData . slides [ i ]
111
+
112
+ if ( a ?. raw === b ?. raw )
113
+ continue
114
+
115
+ moduleIds . push (
116
+ `${ slidePrefix } ${ i } .md` ,
117
+ `${ slidePrefix } ${ i } .json` ,
118
+ )
115
119
}
120
+ const moduleEntries = moduleIds
121
+ . filter ( isTruthy )
122
+ . map ( id => ctx . server . moduleGraph . getModuleById ( id as string ) )
123
+ . filter ( notNullish )
124
+
125
+ data = newData
126
+
127
+ moduleEntries . map ( m => ctx . server . moduleGraph . invalidateModule ( m ) )
128
+ return moduleEntries
116
129
} ,
117
130
118
131
resolveId ( id ) {
119
- if ( id . startsWith ( entry ) || id . startsWith ( '/@slidev/' ) )
132
+ if ( id . startsWith ( slidePrefix ) || id . startsWith ( '/@slidev/' ) )
120
133
return id
121
134
return null
122
135
} ,
@@ -135,8 +148,8 @@ export function createSlidesLoader({ data, entry, clientRoot, themeRoot, userRoo
135
148
return `export default ${ JSON . stringify ( data . config ) } `
136
149
137
150
// pages
138
- if ( id . startsWith ( entry ) ) {
139
- const remaning = id . slice ( entry . length + 1 )
151
+ if ( id . startsWith ( slidePrefix ) ) {
152
+ const remaning = id . slice ( slidePrefix . length )
140
153
const match = remaning . match ( regexIdQuery )
141
154
if ( match ) {
142
155
const [ , no , type ] = match
@@ -149,11 +162,11 @@ export function createSlidesLoader({ data, entry, clientRoot, themeRoot, userRoo
149
162
} ,
150
163
} ,
151
164
{
152
- name : 'slidev:layout-transform' ,
153
- enforce : 'post ' ,
165
+ name : 'slidev:layout-transform:pre ' ,
166
+ enforce : 'pre ' ,
154
167
async transform ( code , id ) {
155
- if ( id . startsWith ( entry ) ) {
156
- const remaning = id . slice ( entry . length + 1 )
168
+ if ( id . startsWith ( slidePrefix ) ) {
169
+ const remaning = id . slice ( slidePrefix . length )
157
170
const match = remaning . match ( regexIdQuery )
158
171
if ( ! match )
159
172
return
@@ -162,26 +175,18 @@ export function createSlidesLoader({ data, entry, clientRoot, themeRoot, userRoo
162
175
if ( type !== 'md' )
163
176
return
164
177
165
- const layouts = await getLayouts ( )
166
178
const pageNo = parseInt ( no )
179
+ const layouts = await getLayouts ( )
167
180
const layoutName = data . slides [ pageNo ] . frontmatter ?. layout || ( pageNo === 0 ? 'cover' : 'default' )
168
181
if ( ! layouts [ layoutName ] )
169
182
throw new Error ( `Unknown layout "${ layoutName } "` )
170
183
171
- code = code . replace ( 'export default _sfc_main' , '' )
172
- code = `import __layout from "${ layouts [ layoutName ] } "\n${ code } `
173
- code = `import { h } from 'vue'\n${ code } `
174
- code += `\nexport default {
175
- name: "layout-${ layoutName } ",
176
- render: () => h(__layout, null, () => h(_sfc_main)),
177
- __file: __layout.__file,
178
- }`
179
-
184
+ code = code . replace ( / ( < s c r i p t s e t u p .* > ) / g, `$1\nimport InjectedLayout from "/@fs${ layouts [ layoutName ] } "` )
185
+ code = code . replace ( / < t e m p l a t e > ( [ \s \S ] * ?) < \/ t e m p l a t e > / mg, '<template><InjectedLayout v-bind="frontmatter">$1</InjectedLayout></template>' )
180
186
return code
181
187
}
182
188
} ,
183
189
} ,
184
-
185
190
]
186
191
187
192
async function getLayouts ( ) {
@@ -238,7 +243,7 @@ export function createSlidesLoader({ data, entry, clientRoot, themeRoot, userRoo
238
243
. map ( ( i , idx ) => {
239
244
if ( i . frontmatter ?. disabled )
240
245
return undefined
241
- imports . push ( `import n${ no } from '${ entry } ?id= ${ idx } .md'` )
246
+ imports . push ( `import n${ no } from '${ slidePrefix } ${ idx } .md'` )
242
247
const additions = {
243
248
slide : {
244
249
start : i . start ,
0 commit comments