1
1
import { Action } from 'typings'
2
2
import * as path from 'path'
3
3
import * as vscode from 'vscode'
4
- import Channel from '../Channel'
4
+ import { JSDOM } from 'jsdom'
5
+ import Channel from '../channel'
5
6
6
7
const getNonce = ( ) : string => {
7
8
let text = ''
@@ -30,13 +31,14 @@ class ReactWebView {
30
31
private channel : Channel
31
32
32
33
public constructor ( { extensionPath, workspaceState} : ReactWebViewProps ) {
34
+ console . log ( `extPath ${ extensionPath } ` )
33
35
this . extensionPath = extensionPath
34
36
35
37
// Create and show a new webview panel
36
38
this . panel = this . createWebviewPanel ( vscode . ViewColumn . Two )
37
39
38
40
// Set the webview initial html content
39
- this . panel . webview . html = this . getHtmlForWebview ( )
41
+ this . getHtmlForWebview ( )
40
42
41
43
// Listen for when the panel is disposed
42
44
// This happens when the user closes the panel or when the panel is closed programmatically
@@ -65,15 +67,15 @@ class ReactWebView {
65
67
66
68
// prevents new panels from going on top of coderoad panel
67
69
vscode . window . onDidChangeActiveTextEditor ( ( textEditor ?: vscode . TextEditor ) => {
68
- console . log ( 'onDidChangeActiveTextEditor' )
69
- console . log ( textEditor )
70
+ // console.log('onDidChangeActiveTextEditor')
71
+ // console.log(textEditor)
70
72
if ( ! textEditor || textEditor . viewColumn !== vscode . ViewColumn . Two ) {
71
73
updateWindows ( )
72
74
}
73
75
} )
74
76
// // prevents moving coderoad panel on top of left panel
75
77
vscode . window . onDidChangeVisibleTextEditors ( ( textEditor : vscode . TextEditor [ ] ) => {
76
- console . log ( 'onDidChangeVisibleTextEditors' )
78
+ // console.log('onDidChangeVisibleTextEditors')
77
79
updateWindows ( )
78
80
} )
79
81
@@ -97,7 +99,7 @@ class ReactWebView {
97
99
Promise . all ( this . disposables . map ( ( x ) => x . dispose ( ) ) )
98
100
}
99
101
100
- private createWebviewPanel ( column : number ) : vscode . WebviewPanel {
102
+ private createWebviewPanel = ( column : number ) : vscode . WebviewPanel => {
101
103
const viewType = 'CodeRoad'
102
104
const title = 'CodeRoad'
103
105
const config = {
@@ -111,62 +113,64 @@ class ReactWebView {
111
113
return vscode . window . createWebviewPanel ( viewType , title , column , config )
112
114
}
113
115
114
- private getHtmlForWebview ( ) : string {
115
- const buildUri = vscode . Uri . file ( path . join ( this . extensionPath , 'build' ) ) . with ( { scheme : 'vscode-resource' } )
116
+ private getHtmlForWebview = async ( ) : Promise < void > => {
117
+
118
+ const dom = await JSDOM . fromFile ( './build/index.html' )
119
+
120
+ const { document} = dom . window
121
+
122
+ const base : HTMLBaseElement = document . createElement ( 'base' )
123
+ base . href = vscode . Uri . file ( path . join ( this . extensionPath , 'build' ) ) . with ( { scheme : 'vscode-resource' } ) . path
124
+ document . head . appendChild ( base )
116
125
117
126
const manifest = require ( path . join ( this . extensionPath , 'build' , 'asset-manifest.json' ) )
118
127
119
- const getSrc = ( manifestName : string ) : any => {
120
- const file = manifest . files [ manifestName ]
121
- const uriPath = vscode . Uri . file ( path . join ( this . extensionPath , 'build' , file ) )
122
- return uriPath . with ( { scheme : 'vscode-resource' } )
128
+ const nonces : string [ ] = [ ]
129
+
130
+ const scripts : HTMLScriptElement [ ] = Array . from ( document . getElementsByTagName ( 'script' ) )
131
+ for ( const script of scripts ) {
132
+ const nonce : string = getNonce ( )
133
+ nonces . push ( nonce )
134
+ script . nonce = nonce
135
+ const uriPath = vscode . Uri . file ( path . join ( this . extensionPath , 'build' , script . src ) )
136
+ uriPath . with ( { scheme : 'vscode-resource' } )
137
+ }
138
+
139
+ // add run-time script from webpack
140
+ const runTimeScript = document . createElement ( 'script' )
141
+ runTimeScript . src = manifest . files [ 'runtime-main.js' ]
142
+ runTimeScript . nonce = getNonce ( )
143
+ nonces . push ( runTimeScript . nonce )
144
+ vscode . Uri . file ( path . join ( this . extensionPath , 'build' , runTimeScript . src ) ) . with ( { scheme : 'vscode-resource' } )
145
+ document . body . appendChild ( runTimeScript )
146
+
147
+ const styles : HTMLLinkElement [ ] = Array . from ( document . getElementsByTagName ( 'link' ) )
148
+ for ( const style of styles ) {
149
+ if ( style . href ) {
150
+ const uriPath = vscode . Uri . file ( path . join ( this . extensionPath , 'build' , style . href ) )
151
+ uriPath . with ( { scheme : 'vscode-resource' } )
152
+ }
123
153
}
124
154
125
- const styles = [
126
- 'main.css' ,
127
- // get style chunk
128
- Object . keys ( manifest . files ) . find ( f => f . match ( / ^ s t a t i c \/ c s s \/ .+ \. c s s $ / ) ) || ''
129
- ] . map ( style => getSrc ( style ) )
130
-
131
- // map over scripts
132
- const scripts = [ {
133
- file : './webpackBuild.js' ,
134
- } , {
135
- manifest : 'runtime~main.js' ,
136
- } , {
137
- manifest : 'main.js' ,
138
- } , {
139
- // get js chunk
140
- manifest : Object . keys ( manifest . files ) . find ( f => f . match ( / ^ s t a t i c \/ j s \/ .+ \. j s $ / ) ) ,
141
- } ] . map ( script => ( {
142
- nonce : getNonce ( ) ,
143
- src : script . manifest ? getSrc ( script . manifest ) : script . file
144
- } ) )
145
-
146
- const indexHtml = `<!DOCTYPE html>
147
- <html lang='en'>
148
- <head>
149
- <meta charset='utf-8'>
150
- <meta name='viewport' content='width=device-width,initial-scale=1,shrink-to-fit=no'>
151
- <meta name='theme-color' content='#000000'>
152
- <meta http-equiv='Content-Security-Policy' content="font-src vscode-resource://*; img-src vscode-resource: https:; script-src ${ scripts . map ( script => `'nonce-${ script . nonce } '` ) . join ( ' ' ) } ; style-src vscode-resource: 'unsafe-inline' http: https: data:;">
153
- <title>React App</title>
154
-
155
- <link rel='manifest' href='./manifest.json' />
156
- <link rel='stylesheet' href='https://unpkg.com/@alifd/next/dist/next.css' />
157
- ${ styles . map ( styleUri => `<link rel='stylesheet' type='text/css' href='${ styleUri } '>` ) . join ( '\n' ) }
158
-
159
- <base href='${ buildUri } /'>
160
- </head>
161
-
162
- <body>
163
- <noscript>You need to enable JavaScript to run this app.</noscript>
164
- <div id='root' style='background-color:white; padding: 1rem;'>Loading...</div>
165
- ${ scripts . map ( s => `<script nonce='${ s . nonce } ' src='${ s . src } '></script>` ) . join ( '\n' ) }
166
- </body>
167
- </html>`
168
-
169
- return indexHtml
155
+
156
+ // content security policy
157
+ const cspMeta : HTMLMetaElement = document . createElement ( 'meta' )
158
+ cspMeta . httpEquiv = 'Content-Security-Policy'
159
+ cspMeta . content = [
160
+ `default-src 'none';` ,
161
+ 'font-src vscode-resource://*;' ,
162
+ 'img-src vscode-resource: https:;' ,
163
+ `script-src ${ nonces . map ( nonce => `'nonce-${ nonce } '` ) . join ( ' ' ) } ;` ,
164
+ `style-src 'unsafe-inline' vscode-resource: http: https: data:;`
165
+ ] . join ( ' ' )
166
+ document . head . appendChild ( cspMeta )
167
+
168
+
169
+ const html = dom . serialize ( )
170
+
171
+ console . log ( html )
172
+
173
+ this . panel . webview . html = html
170
174
}
171
175
172
176
}
0 commit comments