1
1
import * as vscode from 'vscode' ;
2
- import { compile , NodeTypes } from '@vue/compiler-dom' ;
3
2
import * as path from 'path' ;
4
3
import * as fs from '../utils/fs' ;
5
4
import * as shared from '@volar/shared' ;
@@ -58,6 +57,59 @@ export async function register(context: vscode.ExtensionContext) {
58
57
59
58
const sfcs = new WeakMap < vscode . TextDocument , { version : number , sfc : SFCParseResult ; } > ( ) ;
60
59
60
+ class VueComponentPreview implements vscode . WebviewViewProvider {
61
+
62
+ public resolveWebviewView (
63
+ webviewView : vscode . WebviewView ,
64
+ _context : vscode . WebviewViewResolveContext ,
65
+ _token : vscode . CancellationToken ,
66
+ ) {
67
+ webviewView . webview . options = {
68
+ enableScripts : true ,
69
+ } ;
70
+ updateWebView ( ) ;
71
+
72
+ vscode . window . onDidChangeActiveTextEditor ( updateWebView ) ;
73
+ vscode . workspace . onDidChangeConfiguration ( updateWebView ) ;
74
+ vscode . workspace . onDidSaveTextDocument ( updateWebView ) ;
75
+
76
+ async function updateWebView ( ) {
77
+
78
+ if ( ! webviewView . visible )
79
+ return ;
80
+
81
+ if ( vscode . window . activeTextEditor ?. document . languageId !== 'vue' )
82
+ return ;
83
+
84
+ const fileName = vscode . window . activeTextEditor . document . fileName ;
85
+ let terminal = vscode . window . terminals . find ( terminal => terminal . name . startsWith ( 'volar-preview:' ) ) ;
86
+ let port : number ;
87
+
88
+ if ( terminal ) {
89
+ port = Number ( terminal . name . split ( ':' ) [ 1 ] ) ;
90
+ }
91
+ else {
92
+
93
+ const configFile = await getConfigFile ( fileName , 'vite' ) ;
94
+ if ( ! configFile )
95
+ return ;
96
+
97
+ const configDir = path . dirname ( configFile ) ;
98
+ const server = await startPreviewServer ( configDir , 'vite' ) ;
99
+ terminal = server . terminal ;
100
+ port = server . port ;
101
+ }
102
+
103
+ const bgPath = vscode . Uri . file ( path . join ( context . extensionPath , 'images' , 'preview-bg.png' ) ) ;
104
+ const bgSrc = webviewView . webview . asWebviewUri ( bgPath ) ;
105
+ const url = `http://localhost:${ port } /__preview#${ fileName } ` ;
106
+
107
+ webviewView . webview . html = '' ;
108
+ webviewView . webview . html = getWebviewContent ( url , undefined , bgSrc . toString ( ) ) ;
109
+ }
110
+ }
111
+ }
112
+
61
113
class FinderPanelSerializer implements vscode . WebviewPanelSerializer {
62
114
async deserializeWebviewPanel ( panel : vscode . WebviewPanel , state : PreviewState ) {
63
115
@@ -66,7 +118,7 @@ export async function register(context: vscode.ExtensionContext) {
66
118
return ; // don't create server because maybe user closed it intentionally
67
119
}
68
120
69
- const port = await openPreview ( PreviewType . Webview , state . fileName , '' , state . mode , panel ) ;
121
+ const port = await openPreview ( PreviewType . Webview , state . fileName , state . mode , panel ) ;
70
122
71
123
panel . webview . html = getWebviewContent ( `http://localhost:${ port } ` , state ) ;
72
124
}
@@ -83,15 +135,19 @@ export async function register(context: vscode.ExtensionContext) {
83
135
return ; // don't create server because maybe user closed it intentionally
84
136
}
85
137
86
- const port = await openPreview ( PreviewType . ComponentPreview , editor . document . fileName , editor . document . getText ( ) , state . mode , panel ) ;
138
+ const port = await openPreview ( PreviewType . ComponentPreview , editor . document . fileName , state . mode , panel ) ;
87
139
88
140
if ( port !== undefined ) {
89
- const previewQuery = createQuery ( editor . document ) ;
90
- updatePreviewPanel ( panel , state . fileName , previewQuery , port , state . mode ) ;
141
+ updatePreviewPanel ( panel , state . fileName , port , state . mode ) ;
91
142
}
92
143
}
93
144
}
94
145
146
+ vscode . window . registerWebviewViewProvider (
147
+ 'vueComponentPreview' ,
148
+ new VueComponentPreview ( ) ,
149
+ ) ;
150
+
95
151
context . subscriptions . push ( vscode . commands . registerCommand ( 'volar.action.vite' , async ( ) => {
96
152
97
153
const editor = vscode . window . activeTextEditor ;
@@ -118,7 +174,7 @@ export async function register(context: vscode.ExtensionContext) {
118
174
if ( select === undefined )
119
175
return ; // cancel
120
176
121
- openPreview ( select as PreviewType , editor . document . fileName , editor . document . getText ( ) , 'vite' ) ;
177
+ openPreview ( select as PreviewType , editor . document . fileName , 'vite' ) ;
122
178
} ) ) ;
123
179
context . subscriptions . push ( vscode . commands . registerCommand ( 'volar.action.nuxt' , async ( ) => {
124
180
@@ -141,7 +197,7 @@ export async function register(context: vscode.ExtensionContext) {
141
197
if ( select === undefined )
142
198
return ; // cancel
143
199
144
- openPreview ( select as PreviewType , editor . document . fileName , editor . document . getText ( ) , 'nuxt' ) ;
200
+ openPreview ( select as PreviewType , editor . document . fileName , 'nuxt' ) ;
145
201
} ) ) ;
146
202
context . subscriptions . push ( vscode . commands . registerCommand ( 'volar.action.selectElement' , ( ) => {
147
203
const panel = [ ...panels ] . find ( panel => panel . active ) ;
@@ -260,7 +316,7 @@ export async function register(context: vscode.ExtensionContext) {
260
316
}
261
317
}
262
318
263
- async function openPreview ( previewType : PreviewType , fileName : string , fileText : string , mode : 'vite' | 'nuxt' , _panel ?: vscode . WebviewPanel ) {
319
+ async function openPreview ( previewType : PreviewType , fileName : string , mode : 'vite' | 'nuxt' , _panel ?: vscode . WebviewPanel ) {
264
320
265
321
const configFile = await getConfigFile ( fileName , mode ) ;
266
322
if ( ! configFile )
@@ -329,42 +385,14 @@ export async function register(context: vscode.ExtensionContext) {
329
385
}
330
386
else if ( previewType === PreviewType . ComponentPreview ) {
331
387
332
- // const disposable_1 = vscode.window.onDidChangeActiveTextEditor(async e => {
333
- // if (e && e.document.languageId === 'vue' && e.document.fileName !== lastPreviewFile) {
334
- // _panel.dispose();
335
- // vscode.commands.executeCommand('volar.action.preview');
336
-
337
- // // TODO: not working
338
- // // const newQuery = createQuery(e.document.getText());
339
- // // const url = `http://localhost:${port}/__preview${newQuery}#${e.document.fileName}`;
340
- // // previewPanel?.webview.postMessage({ sender: 'volar', command: 'updateUrl', data: url });
341
-
342
- // // lastPreviewFile = e.document.fileName;
343
- // // lastPreviewQuery = newQuery;
344
- // }
345
- // });
346
- let previewQuery = createQuery ( {
347
- getText : ( ) => fileText ,
348
- fileName,
349
- version : - 1 ,
350
- } as vscode . TextDocument ) ;
351
-
352
- panelContext . push ( vscode . workspace . onDidChangeTextDocument ( e => {
353
- if ( e . document . fileName === fileName ) {
354
- const newPreviewQuery = createQuery ( e . document ) ;
355
- if ( newPreviewQuery !== previewQuery ) {
356
- const url = `http://localhost:${ port } /__preview${ newPreviewQuery } #${ e . document . fileName } ` ;
357
- panel . webview . postMessage ( { sender : 'volar' , command : 'updateUrl' , data : url } ) ;
358
-
359
- previewQuery = newPreviewQuery ;
360
- }
361
- }
388
+ panelContext . push ( vscode . workspace . onDidSaveTextDocument ( e => {
389
+ vscode . commands . executeCommand ( 'workbench.action.webview.reloadWebviewAction' ) ;
362
390
} ) ) ;
363
391
panelContext . push ( vscode . workspace . onDidChangeConfiguration ( ( ) => {
364
- updatePreviewPanel ( panel , fileName , previewQuery , port , mode ) ;
392
+ updatePreviewPanel ( panel , fileName , port , mode ) ;
365
393
} ) ) ;
366
394
367
- updatePreviewPanel ( panel , fileName , previewQuery , port , mode ) ;
395
+ updatePreviewPanel ( panel , fileName , port , mode ) ;
368
396
}
369
397
370
398
return port ;
@@ -475,59 +503,10 @@ export async function register(context: vscode.ExtensionContext) {
475
503
return configFile ;
476
504
}
477
505
478
- function createQuery ( document : vscode . TextDocument ) {
479
-
480
- const sfc = getSfc ( document ) ;
481
- let query = '' ;
482
- let fileName = document . fileName ;
483
-
484
- for ( const customBlock of sfc . descriptor . customBlocks ) {
485
- if ( customBlock . type === 'preview' ) {
486
- const previewTagStart = document . getText ( ) . substring ( 0 , customBlock . loc . start . offset ) . lastIndexOf ( '<preview' ) ;
487
- const previewTag = document . getText ( ) . substring ( previewTagStart , customBlock . loc . start . offset ) ;
488
- const previewGen = compile ( previewTag + '</preview>' ) . ast ;
489
- const props : Record < string , string > = { } ;
490
- for ( const previewNode of previewGen . children ) {
491
- if ( previewNode . type === NodeTypes . ELEMENT ) {
492
- for ( const prop of previewNode . props ) {
493
- if ( prop . type === NodeTypes . ATTRIBUTE ) {
494
- if ( prop . value ) {
495
- props [ prop . name ] = JSON . stringify ( prop . value . content ) ;
496
- }
497
- else {
498
- props [ prop . name ] = JSON . stringify ( true ) ;
499
- }
500
- }
501
- else if ( prop . type === NodeTypes . DIRECTIVE ) {
502
- if ( prop . arg ?. type === NodeTypes . SIMPLE_EXPRESSION && prop . exp ?. type == NodeTypes . SIMPLE_EXPRESSION ) {
503
- props [ prop . arg . content ] = prop . exp . content ;
504
- }
505
- }
506
- }
507
- }
508
- }
509
- const keys = Object . keys ( props ) ;
510
- for ( let i = 0 ; i < keys . length ; i ++ ) {
511
- query += i === 0 ? '?' : '&' ;
512
- const key = keys [ i ] ;
513
- const value = props [ key ] ;
514
- query += key ;
515
- query += '=' ;
516
- query += encodeURIComponent ( value ) ;
517
- }
518
- }
519
- else if ( customBlock . type === 'preview-target' && typeof customBlock . attrs . path === 'string' ) {
520
- fileName = path . resolve ( path . dirname ( fileName ) , customBlock . attrs . path ) ;
521
- }
522
- }
523
-
524
- return query ;
525
- }
526
-
527
- function updatePreviewPanel ( previewPanel : vscode . WebviewPanel , fileName : string , query : string , port : number , mode : 'vite' | 'nuxt' ) {
506
+ function updatePreviewPanel ( previewPanel : vscode . WebviewPanel , fileName : string , port : number , mode : 'vite' | 'nuxt' ) {
528
507
const bgPath = vscode . Uri . file ( path . join ( context . extensionPath , 'images' , 'preview-bg.png' ) ) ;
529
508
const bgSrc = previewPanel . webview . asWebviewUri ( bgPath ) ;
530
- const url = `http://localhost:${ port } /__preview${ query } #${ fileName } ` ;
509
+ const url = `http://localhost:${ port } /__preview#${ fileName } ` ;
531
510
previewPanel . title = 'Preview ' + path . basename ( fileName ) ;
532
511
previewPanel . webview . html = getWebviewContent ( url , { fileName, mode } , bgSrc . toString ( ) ) ;
533
512
}
0 commit comments