@@ -2,11 +2,26 @@ import {fileURLToPath} from "node:url";
2
2
import posixPath from "node:path/posix" ;
3
3
import { promisify } from "node:util" ;
4
4
import os from "node:os" ;
5
- import workerpool from "workerpool" ;
6
- import Resource from "@ui5/fs/Resource" ;
7
- import { getLogger } from "@ui5/logger" ;
8
- const log = getLogger ( "builder:processors:minifier" ) ;
9
5
import { setTimeout as setTimeoutPromise } from "node:timers/promises" ;
6
+ import { minify } from "terser" ;
7
+
8
+ /**
9
+ * @private
10
+ * @module @ui 5/builder/tasks/minifyWorker
11
+ */
12
+
13
+ /**
14
+ * Preserve comments which contain:
15
+ * <ul>
16
+ * <li>copyright notice</li>
17
+ * <li>license terms</li>
18
+ * <li>"@ui5-bundle"</li>
19
+ * <li>"@ui5-bundle-raw-include"</li>
20
+ * </ul>
21
+ *
22
+ * @type {RegExp }
23
+ */
24
+ const copyrightCommentsAndBundleCommentPattern = / c o p y r i g h t | \( c \) (?: [ 0 - 9 ] + | \s + [ 0 - 9 A - Z a - z ] ) | r e l e a s e d u n d e r | l i c e n s e | \u00a9 | ^ @ u i 5 - b u n d l e - r a w - i n c l u d e | ^ @ u i 5 - b u n d l e / i;
10
25
11
26
const debugFileRegex = / ( (?: \. v i e w | \. f r a g m e n t | \. c o n t r o l l e r | \. d e s i g n t i m e | \. s u p p o r t ) ? \. j s ) $ / ;
12
27
@@ -21,40 +36,6 @@ const httpPattern = /^https?:\/\//i;
21
36
// Shared workerpool across all executions until the taskUtil cleanup is triggered
22
37
let pool ;
23
38
24
- function getPool ( taskUtil ) {
25
- if ( ! pool ) {
26
- log . verbose ( `Creating workerpool with up to ${ maxWorkers } workers (available CPU cores: ${ osCpus } )` ) ;
27
- const workerPath = fileURLToPath ( new URL ( "./minifierWorker.js" , import . meta. url ) ) ;
28
- pool = workerpool . pool ( workerPath , {
29
- workerType : "auto" ,
30
- maxWorkers
31
- } ) ;
32
- taskUtil . registerCleanupTask ( ( force ) => {
33
- const attemptPoolTermination = async ( ) => {
34
- log . verbose ( `Attempt to terminate the workerpool...` ) ;
35
-
36
- if ( ! pool ) {
37
- return ;
38
- }
39
-
40
- // There are many stats that could be used, but these ones seem the most
41
- // convenient. When all the (available) workers are idle, then it's safe to terminate.
42
- let { idleWorkers, totalWorkers} = pool . stats ( ) ;
43
- while ( idleWorkers !== totalWorkers && ! force ) {
44
- await setTimeoutPromise ( 100 ) ; // Wait a bit workers to finish and try again
45
- ( { idleWorkers, totalWorkers} = pool . stats ( ) ) ;
46
- }
47
-
48
- const poolToBeTerminated = pool ;
49
- pool = null ;
50
- return poolToBeTerminated . terminate ( force ) ;
51
- } ;
52
-
53
- return attemptPoolTermination ( ) ;
54
- } ) ;
55
- }
56
- return pool ;
57
- }
58
39
59
40
async function minifyInWorker ( options , taskUtil ) {
60
41
return getPool ( taskUtil ) . exec ( "execMinification" , [ options ] ) ;
@@ -159,24 +140,12 @@ async function getSourceMapFromUrl({sourceMappingUrl, resourcePath, readFile}) {
159
140
* Promise resolving with object of resource, dbgResource and sourceMap
160
141
*/
161
142
export default async function ( {
162
- resources, fs, taskUtil, options : { readSourceMappingUrl = false , addSourceMappingUrl = true , useWorkers = false
163
- } = { } } ) {
164
- let minify ;
143
+ resources, fs, options : { readSourceMappingUrl = false , addSourceMappingUrl = true , useWorkers = false
144
+ } = { } , log, resourceFactory} ) {
165
145
if ( readSourceMappingUrl && ! fs ) {
166
146
throw new Error ( `Option 'readSourceMappingUrl' requires parameter 'fs' to be provided` ) ;
167
147
}
168
148
169
- if ( useWorkers ) {
170
- if ( ! taskUtil ) {
171
- // TaskUtil is required for worker support
172
- throw new Error ( `Minifier: Option 'useWorkers' requires a taskUtil instance to be provided` ) ;
173
- }
174
- minify = minifyInWorker ;
175
- } else {
176
- // Do not use workerpool
177
- minify = ( await import ( "./minifierWorker.js" ) ) . default ;
178
- }
179
-
180
149
return Promise . all ( resources . map ( async ( resource ) => {
181
150
const resourcePath = resource . getPath ( ) ;
182
151
const dbgPath = resourcePath . replace ( debugFileRegex , "-dbg$1" ) ;
@@ -248,7 +217,7 @@ export default async function({
248
217
sourceMapJson . file = dbgFilename ;
249
218
250
219
// Then create a new resource
251
- dbgSourceMapResource = new Resource ( {
220
+ dbgSourceMapResource = resourceFactory . createResource ( {
252
221
string : JSON . stringify ( sourceMapJson ) ,
253
222
path : dbgPath + ".map"
254
223
} ) ;
@@ -265,19 +234,39 @@ export default async function({
265
234
}
266
235
}
267
236
}
268
-
269
- const result = await minify ( {
270
- filename,
271
- dbgFilename,
272
- code,
273
- sourceMapOptions
274
- } , taskUtil ) ;
275
- resource . setString ( result . code ) ;
276
- const sourceMapResource = new Resource ( {
277
- path : resource . getPath ( ) + ".map" ,
278
- string : result . map
279
- } ) ;
280
- return { resource, dbgResource, sourceMapResource, dbgSourceMapResource} ;
237
+ try {
238
+ const result = await minify ( {
239
+ // Use debug-name since this will be referenced in the source map "sources"
240
+ [ dbgFilename ] : code
241
+ } , {
242
+ output : {
243
+ comments : copyrightCommentsAndBundleCommentPattern ,
244
+ wrap_func_args : false
245
+ } ,
246
+ compress : false ,
247
+ mangle : {
248
+ reserved : [
249
+ "jQuery" ,
250
+ "jquery" ,
251
+ "sap" ,
252
+ ]
253
+ } ,
254
+ sourceMap : sourceMapOptions
255
+ } ) ;
256
+ resource . setString ( result . code ) ;
257
+ const sourceMapResource = resourceFactory . createResource ( {
258
+ path : resource . getPath ( ) + ".map" ,
259
+ string : result . map
260
+ } ) ;
261
+ return { resource, dbgResource, sourceMapResource, dbgSourceMapResource} ;
262
+ } catch ( err ) {
263
+ // Note: err.filename contains the debug-name
264
+ throw new Error (
265
+ `Minification failed with error: ${ err . message } in file ${ filename } ` +
266
+ `(line ${ err . line } , col ${ err . col } , pos ${ err . pos } )` , {
267
+ cause : err
268
+ } ) ;
269
+ }
281
270
} ) ) ;
282
271
}
283
272
0 commit comments