@@ -16,7 +16,8 @@ import {
16
16
grants ,
17
17
regexpScripts ,
18
18
regexpStyles ,
19
- styleTemplate
19
+ styleTemplate ,
20
+ vitePluginName
20
21
} from './constants.js'
21
22
import css from './css.js'
22
23
import { defineGrants , removeDuplicates , transform } from './helpers.js'
@@ -27,181 +28,189 @@ export type { UserscriptPluginConfig }
27
28
export default function UserscriptPlugin (
28
29
config : UserscriptPluginConfig
29
30
) : PluginOption {
30
- let pluginConfig : ResolvedConfig
31
- let isBuildWatch : boolean
32
- let socketConnection : connection | null = null
33
-
34
- const workdir = dirname ( fileURLToPath ( import . meta. url ) )
35
- const logger = createLogger ( 'info' , {
36
- prefix : '[vite-userscript-plugin]' ,
37
- allowClearScreen : true
38
- } )
39
-
40
- const httpServer = createServer ( ( req , res ) => {
41
- return serveHandler ( req , res , {
42
- public : pluginConfig . build . outDir
31
+ try {
32
+ let pluginConfig : ResolvedConfig
33
+ let isBuildWatch : boolean
34
+ let socketConnection : connection | null = null
35
+
36
+ const workdir = dirname ( fileURLToPath ( import . meta. url ) )
37
+ const logger = createLogger ( 'info' , {
38
+ prefix : `[${ vitePluginName } ]` ,
39
+ allowClearScreen : true
43
40
} )
44
- } )
45
-
46
- const WebSocketServer = server
47
- const ws = new WebSocketServer ( { httpServer } )
48
- ws . on ( 'request' , ( request ) => {
49
- socketConnection = request . accept ( null , request . origin )
50
- } )
51
-
52
- return {
53
- name : 'vite-userscript-plugin' ,
54
- apply : 'build' ,
55
- config ( ) {
56
- return userConfig ( config )
57
- } ,
58
- async configResolved ( userConfig ) {
59
- pluginConfig = userConfig
60
- isBuildWatch = ( userConfig . build . watch ?? false ) as boolean
61
- config . entry = resolve ( userConfig . root , config . entry )
62
- config . header . name = sanitize ( config . header . name )
63
-
64
- Array . from ( [
65
- 'match' ,
66
- 'require' ,
67
- 'include' ,
68
- 'exclude' ,
69
- 'resource' ,
70
- 'connect'
71
- ] ) . forEach ( ( key ) => {
72
- const value = config . header [ key ]
73
- config . header [ key ] = removeDuplicates ( value )
41
+
42
+ const httpServer = createServer ( ( req , res ) => {
43
+ return serveHandler ( req , res , {
44
+ public : pluginConfig . build . outDir
74
45
} )
46
+ } )
75
47
76
- config . server = {
77
- port : await getPort ( ) ,
78
- open : false ,
79
- ...config . server
80
- }
81
- } ,
82
- async transform ( src : string , path : string ) {
83
- let code = src
48
+ const WebSocketServer = server
49
+ const ws = new WebSocketServer ( { httpServer } )
50
+ ws . on ( 'request' , ( request ) => {
51
+ socketConnection = request . accept ( null , request . origin )
52
+ } )
84
53
85
- if ( regexpStyles . test ( path ) ) {
86
- code = await css . add ( src , path )
87
- }
54
+ return {
55
+ name : vitePluginName ,
56
+ apply : 'build' ,
57
+ config ( ) {
58
+ return userConfig ( config )
59
+ } ,
60
+ async configResolved ( userConfig ) {
61
+ pluginConfig = userConfig
62
+ isBuildWatch = ( userConfig . build . watch ?? false ) as boolean
63
+ config . entry = resolve ( userConfig . root , config . entry )
64
+ config . header . name = sanitize ( config . header . name )
65
+
66
+ Array . from ( [
67
+ 'match' ,
68
+ 'require' ,
69
+ 'include' ,
70
+ 'exclude' ,
71
+ 'resource' ,
72
+ 'connect'
73
+ ] ) . forEach ( ( key ) => {
74
+ const value = config . header [ key ]
75
+ config . header [ key ] = removeDuplicates ( value )
76
+ } )
88
77
89
- if ( path . includes ( config . entry ) ) {
90
- code = src + styleTemplate
91
- }
78
+ config . server = {
79
+ port : await getPort ( ) ,
80
+ open : false ,
81
+ ...config . server
82
+ }
83
+ } ,
84
+ async transform ( src : string , path : string ) {
85
+ let code = src
92
86
93
- return {
94
- code,
95
- map : null
96
- }
97
- } ,
98
- generateBundle ( _ , bundle ) {
99
- for ( const [ _ , file ] of Object . entries ( bundle ) ) {
100
- const modules = Object . keys (
101
- ( file as unknown as { modules : string [ ] } ) . modules
102
- )
103
-
104
- const styleModules = modules . filter ( ( module ) =>
105
- regexpStyles . test ( module )
106
- )
107
-
108
- if ( styleModules . length ) {
109
- css . merge ( styleModules )
87
+ if ( regexpStyles . test ( path ) ) {
88
+ code = await css . add ( src , path )
110
89
}
111
- }
112
- } ,
113
- async writeBundle ( _ , bundle ) {
114
- const { open, port } = config . server !
115
- const userFilename = `${ config . header . name } .user.js`
116
- const proxyFilename = `${ config . header . name } .proxy.user.js`
117
- const metaFilename = `${ config . header . name } .meta.js`
118
-
119
- for ( const [ fileName ] of Object . entries ( bundle ) ) {
120
- if ( regexpScripts . test ( fileName ) ) {
121
- const rootDir = pluginConfig . root
122
- const outDir = pluginConfig . build . outDir
123
-
124
- const outPath = resolve ( rootDir , outDir , fileName )
125
- const userFilePath = resolve ( rootDir , outDir , userFilename )
126
- const proxyFilePath = resolve ( rootDir , outDir , proxyFilename )
127
- const metaFilePath = resolve ( rootDir , outDir , metaFilename )
128
- const wsPath = resolve ( workdir , `ws-${ config . header . name } .js` )
129
-
130
- try {
131
- let source = readFileSync ( outPath , 'utf8' )
132
- source = source . replace ( styleTemplate , `${ css . inject ( ) } ` )
133
- source = await transform ( {
134
- file : source ,
135
- name : fileName ,
136
- loader : 'js'
137
- } )
138
-
139
- config . header . grant = removeDuplicates (
140
- isBuildWatch
141
- ? grants
142
- : [ ...defineGrants ( source ) , ...( config . header . grant ?? [ ] ) ]
143
- )
144
90
145
- if ( isBuildWatch ) {
146
- const wsFile = readFileSync ( resolve ( workdir , 'ws.js' ) , 'utf8' )
91
+ if ( path . includes ( config . entry ) ) {
92
+ code = src + styleTemplate
93
+ }
94
+
95
+ return {
96
+ code,
97
+ map : null
98
+ }
99
+ } ,
100
+ generateBundle ( _ , bundle ) {
101
+ for ( const outputChunk of Object . values ( bundle ) ) {
102
+ if ( outputChunk . type === 'asset' ) {
103
+ continue
104
+ }
105
+
106
+ // prettier-ignore
107
+ const styleModules = Object
108
+ . keys ( outputChunk . modules )
109
+ . filter ( ( module ) => regexpStyles . test ( module ) )
147
110
148
- const wsScript = await transform ( {
149
- file : wsFile . replace ( '__WS__' , `ws://localhost:${ port } ` ) ,
150
- name : wsPath ,
111
+ if ( styleModules . length ) {
112
+ css . merge ( styleModules )
113
+ }
114
+ }
115
+ } ,
116
+ async writeBundle ( _ , bundle ) {
117
+ const { open, port } = config . server !
118
+ const userFilename = `${ config . header . name } .user.js`
119
+ const proxyFilename = `${ config . header . name } .proxy.user.js`
120
+ const metaFilename = `${ config . header . name } .meta.js`
121
+
122
+ for ( const [ fileName ] of Object . entries ( bundle ) ) {
123
+ if ( regexpScripts . test ( fileName ) ) {
124
+ const rootDir = pluginConfig . root
125
+ const outDir = pluginConfig . build . outDir
126
+
127
+ const outPath = resolve ( rootDir , outDir , fileName )
128
+ const userFilePath = resolve ( rootDir , outDir , userFilename )
129
+ const proxyFilePath = resolve ( rootDir , outDir , proxyFilename )
130
+ const metaFilePath = resolve ( rootDir , outDir , metaFilename )
131
+ const wsPath = resolve ( workdir , `ws-${ config . header . name } .js` )
132
+
133
+ try {
134
+ let source = readFileSync ( outPath , 'utf8' )
135
+ source = source . replace ( styleTemplate , `${ css . inject ( ) } ` )
136
+ source = await transform ( {
137
+ file : source ,
138
+ name : fileName ,
151
139
loader : 'js'
152
140
} )
153
141
154
- writeFileSync ( wsPath , wsScript )
155
- writeFileSync (
156
- proxyFilePath ,
157
- new Banner ( {
158
- ...config . header ,
159
- require : [
160
- ...config . header . require ! ,
161
- 'file://' + wsPath ,
162
- 'file://' + outPath
163
- ]
164
- } ) . generate ( )
142
+ config . header . grant = removeDuplicates (
143
+ isBuildWatch
144
+ ? grants
145
+ : [ ...defineGrants ( source ) , ...( config . header . grant ?? [ ] ) ]
165
146
)
166
- }
167
147
168
- const banner = new Banner ( config . header ) . generate ( )
169
- writeFileSync ( outPath , source )
170
- writeFileSync ( metaFilePath , banner )
171
- writeFileSync ( userFilePath , `${ banner } \n\n${ source } ` )
172
- } catch ( err ) {
173
- console . log ( err )
148
+ if ( isBuildWatch ) {
149
+ const wsFile = readFileSync ( resolve ( workdir , 'ws.js' ) , 'utf8' )
150
+
151
+ const wsScript = await transform ( {
152
+ file : wsFile . replace ( '__WS__' , `ws://localhost:${ port } ` ) ,
153
+ name : wsPath ,
154
+ loader : 'js'
155
+ } )
156
+
157
+ writeFileSync ( wsPath , wsScript )
158
+ writeFileSync (
159
+ proxyFilePath ,
160
+ new Banner ( {
161
+ ...config . header ,
162
+ require : [
163
+ ...config . header . require ! ,
164
+ 'file://' + wsPath ,
165
+ 'file://' + outPath
166
+ ]
167
+ } ) . generate ( )
168
+ )
169
+ }
170
+
171
+ const banner = new Banner ( config . header ) . generate ( )
172
+ writeFileSync ( outPath , source )
173
+ writeFileSync ( metaFilePath , banner )
174
+ writeFileSync ( userFilePath , `${ banner } \n\n${ source } ` )
175
+ } catch ( err ) {
176
+ console . log ( err )
177
+ }
174
178
}
175
179
}
176
- }
177
180
178
- if ( isBuildWatch && ! httpServer . listening ) {
179
- const link = `http://localhost:${ port } `
180
- httpServer . listen ( port , ( ) => {
181
- logger . clearScreen ( 'info' )
182
- logger . info ( colors . blue ( `Running at: ${ colors . gray ( link ) } ` ) )
183
- } )
181
+ if ( isBuildWatch && ! httpServer . listening ) {
182
+ const link = `http://localhost:${ port } `
183
+ httpServer . listen ( port , ( ) => {
184
+ logger . clearScreen ( 'info' )
185
+ logger . info ( colors . blue ( `Running at: ${ colors . gray ( link ) } ` ) )
186
+ } )
184
187
185
- if ( open ) {
186
- await openLink ( `${ link } /${ proxyFilename } ` )
188
+ if ( open ) {
189
+ await openLink ( `${ link } /${ proxyFilename } ` )
190
+ }
191
+ } else if ( ! isBuildWatch ) {
192
+ httpServer . close ( )
193
+ process . exit ( 0 )
187
194
}
188
- } else if ( ! isBuildWatch ) {
189
- httpServer . close ( )
190
- process . exit ( 0 )
191
- }
192
- } ,
193
- buildEnd ( ) {
194
- if ( isBuildWatch ) {
195
- logger . clearScreen ( 'info' )
196
-
197
- if ( socketConnection ) {
198
- socketConnection . sendUTF (
199
- JSON . stringify ( {
200
- message : 'reload'
201
- } )
202
- )
195
+ } ,
196
+ buildEnd ( ) {
197
+ if ( isBuildWatch ) {
198
+ logger . clearScreen ( 'info' )
199
+
200
+ if ( socketConnection ) {
201
+ socketConnection . sendUTF (
202
+ JSON . stringify ( {
203
+ message : 'reload'
204
+ } )
205
+ )
206
+ }
203
207
}
204
208
}
205
209
}
210
+ } catch ( err ) {
211
+ console . error ( err )
212
+ return {
213
+ name : vitePluginName
214
+ }
206
215
}
207
216
}
0 commit comments