@@ -3,6 +3,7 @@ import type { SFCDescriptor } from 'vue/compiler-sfc'
33import type { ResolvedOptions } from '../src/index'
44import { resolveCompiler } from '../src/compiler'
55import { transformMain } from '../src/main'
6+ import { clearScriptCache , resolveScript } from '../src/script'
67import { transformTemplateAsModule } from '../src/template'
78import { createDescriptor } from '../src/utils/descriptorCache'
89
@@ -18,6 +19,15 @@ function createOptions(): ResolvedOptions {
1819 } as ResolvedOptions
1920}
2021
22+ function createForcedVaporOptions ( ) : ResolvedOptions {
23+ return {
24+ ...createOptions ( ) ,
25+ features : {
26+ vapor : true ,
27+ } ,
28+ }
29+ }
30+
2131function parseDescriptor (
2232 filename : string ,
2333 source : string ,
@@ -126,3 +136,221 @@ describe.todo('template-only vapor __multiRoot', () => {
126136 expect ( result ?. code ) . not . toContain ( 'multiRoot as _sfc_multiRoot' )
127137 } )
128138} )
139+
140+ // TODO: remove todo in v3.6
141+ describe . todo ( 'features.vapor' , ( ) => {
142+ it ( 'forces a template-only Vue SFC to compile in vapor mode' , async ( ) => {
143+ const filename = '/root/Forced.vue'
144+ const source = '<template><div /><div /></template>'
145+ const options = createForcedVaporOptions ( )
146+
147+ const result = await transformMain (
148+ source ,
149+ filename ,
150+ options ,
151+ createPluginContext ( ) ,
152+ false ,
153+ false ,
154+ )
155+
156+ expect ( result ?. code ) . toContain ( 'const _sfc_main = { __vapor: true }' )
157+ expect ( result ?. code ) . toContain ( '_sfc_main.__multiRoot = true' )
158+ } )
159+
160+ it ( 'forces external template modules to compile in vapor mode' , async ( ) => {
161+ const filename = '/root/ForcedExternal.vue'
162+ const source = '<template lang="pug">div\ndiv</template>'
163+ const options = createForcedVaporOptions ( )
164+ const descriptor = parseDescriptor ( filename , source , options )
165+
166+ const mainResult = await transformMain (
167+ source ,
168+ filename ,
169+ options ,
170+ createPluginContext ( ) ,
171+ false ,
172+ false ,
173+ )
174+ const templateResult = await transformTemplateAsModule (
175+ descriptor . template ! . content ,
176+ filename ,
177+ descriptor ,
178+ options ,
179+ createPluginContext ( ) ,
180+ false ,
181+ false ,
182+ )
183+
184+ expect ( mainResult ?. code ) . toContain (
185+ 'import { render as _sfc_render, multiRoot as _sfc_multiRoot }' ,
186+ )
187+ expect ( mainResult ?. code ) . toContain ( '_sfc_main.__multiRoot = _sfc_multiRoot' )
188+ expect ( templateResult . code ) . toContain ( 'export const multiRoot = true' )
189+ } )
190+
191+ it ( 'passes forced vapor mode to compileScript' , ( ) => {
192+ const filename = '/root/ForcedScript.vue'
193+ const options = createForcedVaporOptions ( )
194+ const descriptor = parseDescriptor (
195+ filename ,
196+ '<script setup>const msg = "hi"</script><template>{{ msg }}</template>' ,
197+ options ,
198+ )
199+ const compileScript = vi . fn ( ( ) => ( {
200+ ...descriptor . scriptSetup ! ,
201+ content : 'const _sfc_main = {}' ,
202+ } ) )
203+
204+ clearScriptCache ( )
205+ resolveScript (
206+ descriptor ,
207+ {
208+ ...options ,
209+ compiler : {
210+ ...compiler ,
211+ compileScript,
212+ } ,
213+ } ,
214+ false ,
215+ false ,
216+ )
217+
218+ expect ( compileScript ) . toHaveBeenCalledWith (
219+ descriptor ,
220+ expect . objectContaining ( {
221+ vapor : true ,
222+ templateOptions : expect . objectContaining ( {
223+ vapor : true ,
224+ } ) ,
225+ } ) ,
226+ )
227+ } )
228+
229+ it ( 'does not force normal script SFCs into vapor mode' , async ( ) => {
230+ const filename = '/root/NormalScript.vue'
231+ const source = `
232+ <script>
233+ export default {
234+ props: {
235+ href: String
236+ }
237+ }
238+ </script>
239+ <template><a :href="href"><slot /></a></template>
240+ `
241+ const options = createForcedVaporOptions ( )
242+ const compileScript = vi . fn ( compiler . compileScript )
243+ const compileTemplate = vi . fn ( compiler . compileTemplate )
244+
245+ const result = await transformMain (
246+ source ,
247+ filename ,
248+ {
249+ ...options ,
250+ compiler : {
251+ ...compiler ,
252+ compileScript,
253+ compileTemplate,
254+ } ,
255+ } ,
256+ createPluginContext ( ) ,
257+ false ,
258+ false ,
259+ )
260+
261+ expect ( result ?. code ) . not . toContain ( '__vapor: true' )
262+ expect ( result ?. code ) . not . toContain ( 'template as _template' )
263+ expect ( compileScript ) . toHaveBeenCalledWith (
264+ expect . anything ( ) ,
265+ expect . objectContaining ( {
266+ vapor : false ,
267+ templateOptions : expect . objectContaining ( {
268+ vapor : false ,
269+ } ) ,
270+ } ) ,
271+ )
272+ expect ( compileTemplate ) . toHaveBeenCalledWith (
273+ expect . objectContaining ( {
274+ vapor : false ,
275+ } ) ,
276+ )
277+ } )
278+
279+ it ( 'forces SFCs with both normal script and script setup into vapor mode' , async ( ) => {
280+ const filename = '/root/ScriptAndSetup.vue'
281+ const source = `
282+ <script>
283+ export default {
284+ props: {
285+ href: String
286+ }
287+ }
288+ </script>
289+ <script setup>
290+ const msg = 'hi'
291+ </script>
292+ <template><a :href="href">{{ msg }}</a></template>
293+ `
294+ const options = createForcedVaporOptions ( )
295+ const compileScript = vi . fn ( compiler . compileScript )
296+
297+ await transformMain (
298+ source ,
299+ filename ,
300+ {
301+ ...options ,
302+ compiler : {
303+ ...compiler ,
304+ compileScript,
305+ } ,
306+ } ,
307+ createPluginContext ( ) ,
308+ false ,
309+ false ,
310+ )
311+
312+ expect ( compileScript ) . toHaveBeenCalledWith (
313+ expect . anything ( ) ,
314+ expect . objectContaining ( {
315+ vapor : true ,
316+ templateOptions : expect . objectContaining ( {
317+ vapor : true ,
318+ } ) ,
319+ } ) ,
320+ )
321+ } )
322+
323+ it ( 'continues to force VitePress markdown SFCs into vapor mode' , async ( ) => {
324+ const filename = '/root/index.md'
325+ const source = `
326+ <script >
327+ export const __pageData = JSON.parse("{\\"title\\":\\"Hello\\",\\"description\\":\\"\\",\\"frontmatter\\":{},\\"headers\\":[],\\"relativePath\\":\\"index.md\\",\\"filePath\\":\\"index.md\\"}")
328+ export default {name:"index.md",__vapor:true}
329+ </script>
330+ <template><div><h1 id="hello" tabindex="-1">Hello</h1></div></template>
331+ `
332+ const options = createForcedVaporOptions ( )
333+ const compileTemplate = vi . fn ( compiler . compileTemplate )
334+
335+ await transformMain (
336+ source ,
337+ filename ,
338+ {
339+ ...options ,
340+ compiler : {
341+ ...compiler ,
342+ compileTemplate,
343+ } ,
344+ } ,
345+ createPluginContext ( ) ,
346+ false ,
347+ false ,
348+ )
349+
350+ expect ( compileTemplate ) . toHaveBeenCalledWith (
351+ expect . objectContaining ( {
352+ vapor : true ,
353+ } ) ,
354+ )
355+ } )
356+ } )
0 commit comments