@@ -178,11 +178,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
178178 return findLast ( Array . from ( this . activeInstances ) , ( instance ) => instance . view ?. visible === true )
179179 }
180180
181- resolveWebviewView (
182- webviewView : vscode . WebviewView | vscode . WebviewPanel ,
183- //context: vscode.WebviewViewResolveContext<unknown>, used to recreate a deallocated webview, but we don't need this since we use retainContextWhenHidden
184- //token: vscode.CancellationToken
185- ) : void | Thenable < void > {
181+ async resolveWebviewView ( webviewView : vscode . WebviewView | vscode . WebviewPanel ) {
186182 this . outputChannel . appendLine ( "Resolving webview view" )
187183 this . view = webviewView
188184
@@ -191,7 +187,11 @@ export class ClineProvider implements vscode.WebviewViewProvider {
191187 enableScripts : true ,
192188 localResourceRoots : [ this . context . extensionUri ] ,
193189 }
194- webviewView . webview . html = this . getHtmlContent ( webviewView . webview )
190+
191+ webviewView . webview . html =
192+ this . context . extensionMode === vscode . ExtensionMode . Development
193+ ? await this . getHMRHtmlContent ( webviewView . webview )
194+ : this . getHtmlContent ( webviewView . webview )
195195
196196 // Sets up an event listener to listen for messages passed from the webview view context
197197 // and executes code based on the message that is received
@@ -342,9 +342,9 @@ export class ClineProvider implements vscode.WebviewViewProvider {
342342 // then convert it to a uri we can use in the webview.
343343
344344 // The CSS file from the React build output
345- const stylesUri = getUri ( webview , this . context . extensionUri , [ "webview-ui" , "build" , "static " , "css" , "main .css"] )
345+ const stylesUri = getUri ( webview , this . context . extensionUri , [ "webview-ui" , "build" , "assets " , "index .css" ] )
346346 // The JS file from the React build output
347- const scriptUri = getUri ( webview , this . context . extensionUri , [ "webview-ui" , "build" , "static " , "js" , "main .js"] )
347+ const scriptUri = getUri ( webview , this . context . extensionUri , [ "webview-ui" , "build" , "assets " , "index .js" ] )
348348
349349 // The codicon font from the React build output
350350 // https://github.com/microsoft/vscode-extension-samples/blob/main/webview-codicons-sample/src/extension.ts
@@ -389,18 +389,92 @@ export class ClineProvider implements vscode.WebviewViewProvider {
389389 <meta name="theme-color" content="#000000">
390390 <meta http-equiv="Content-Security-Policy" content="default-src 'none'; font-src ${ webview . cspSource } ; style-src ${ webview . cspSource } 'unsafe-inline'; img-src ${ webview . cspSource } https: data:; script-src 'nonce-${ nonce } ';">
391391 <link rel="stylesheet" type="text/css" href="${ stylesUri } ">
392- <link href="${ codiconsUri } " rel="stylesheet" />
392+ <link href="${ codiconsUri } " rel="stylesheet" />
393393 <title>Cline</title>
394394 </head>
395395 <body>
396396 <noscript>You need to enable JavaScript to run this app.</noscript>
397397 <div id="root"></div>
398- <script nonce="${ nonce } " src="${ scriptUri } "></script>
398+ <script type="module" nonce="${ nonce } " src="${ scriptUri } "></script>
399399 </body>
400400 </html>
401401 `
402402 }
403403
404+ /**
405+ * Connects to the local Vite dev server to allow HMR, with fallback to the bundled assets
406+ *
407+ * @param webview A reference to the extension webview
408+ * @returns A template string literal containing the HTML that should be
409+ * rendered within the webview panel
410+ */
411+ private async getHMRHtmlContent ( webview : vscode . Webview ) : Promise < string > {
412+ const localPort = 25463
413+ const localServerUrl = `localhost:${ localPort } `
414+
415+ // Check if local dev server is running.
416+ try {
417+ await axios . get ( `http://${ localServerUrl } ` )
418+ } catch ( error ) {
419+ vscode . window . showErrorMessage (
420+ "Cline: Local webview dev server is not running, HMR will not work. Please run 'npm run dev:webview' before launching the extension to enable HMR. Using bundled assets." ,
421+ )
422+
423+ return this . getHtmlContent ( webview )
424+ }
425+
426+ const nonce = getNonce ( )
427+ const stylesUri = getUri ( webview , this . context . extensionUri , [ "webview-ui" , "build" , "assets" , "index.css" ] )
428+ const codiconsUri = getUri ( webview , this . context . extensionUri , [
429+ "node_modules" ,
430+ "@vscode" ,
431+ "codicons" ,
432+ "dist" ,
433+ "codicon.css" ,
434+ ] )
435+
436+ const scriptEntrypoint = "src/main.tsx"
437+ const scriptUri = `http://${ localServerUrl } /${ scriptEntrypoint } `
438+
439+ const reactRefresh = /*html*/ `
440+ <script nonce="${ nonce } " type="module">
441+ import RefreshRuntime from "http://${ localServerUrl } /@react-refresh"
442+ RefreshRuntime.injectIntoGlobalHook(window)
443+ window.$RefreshReg$ = () => {}
444+ window.$RefreshSig$ = () => (type) => type
445+ window.__vite_plugin_react_preamble_installed__ = true
446+ </script>
447+ `
448+
449+ const csp = [
450+ "default-src 'none'" ,
451+ `font-src ${ webview . cspSource } ` ,
452+ `style-src ${ webview . cspSource } 'unsafe-inline' https://* http://${ localServerUrl } http://0.0.0.0:${ localPort } ` ,
453+ `img-src ${ webview . cspSource } https: data:` ,
454+ `script-src 'unsafe-eval' https://* http://${ localServerUrl } http://0.0.0.0:${ localPort } 'nonce-${ nonce } '` ,
455+ `connect-src https://* ws://${ localServerUrl } ws://0.0.0.0:${ localPort } http://${ localServerUrl } http://0.0.0.0:${ localPort } ` ,
456+ ]
457+
458+ return /*html*/ `
459+ <!DOCTYPE html>
460+ <html lang="en">
461+ <head>
462+ <meta charset="utf-8">
463+ <meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">
464+ <meta http-equiv="Content-Security-Policy" content="${ csp . join ( "; " ) } ">
465+ <link rel="stylesheet" type="text/css" href="${ stylesUri } ">
466+ <link href="${ codiconsUri } " rel="stylesheet" />
467+ <title>Roo Code</title>
468+ </head>
469+ <body>
470+ <div id="root"></div>
471+ ${ reactRefresh }
472+ <script type="module" src="${ scriptUri } "></script>
473+ </body>
474+ </html>
475+ `
476+ }
477+
404478 /**
405479 * Sets up an event listener to listen for messages passed from the webview context and
406480 * executes code based on the message that is received.
0 commit comments