@@ -2,11 +2,26 @@ import {fileURLToPath} from "node:url";
22import posixPath from "node:path/posix" ;
33import { promisify } from "node:util" ;
44import 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" ) ;
95import { 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;
1025
1126const 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 ) $ / ;
1227
@@ -21,40 +36,6 @@ const httpPattern = /^https?:\/\//i;
2136// Shared workerpool across all executions until the taskUtil cleanup is triggered
2237let pool ;
2338
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- }
5839
5940async function minifyInWorker ( options , taskUtil ) {
6041 return getPool ( taskUtil ) . exec ( "execMinification" , [ options ] ) ;
@@ -159,24 +140,12 @@ async function getSourceMapFromUrl({sourceMappingUrl, resourcePath, readFile}) {
159140 * Promise resolving with object of resource, dbgResource and sourceMap
160141 */
161142export 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} ) {
165145 if ( readSourceMappingUrl && ! fs ) {
166146 throw new Error ( `Option 'readSourceMappingUrl' requires parameter 'fs' to be provided` ) ;
167147 }
168148
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-
180149 return Promise . all ( resources . map ( async ( resource ) => {
181150 const resourcePath = resource . getPath ( ) ;
182151 const dbgPath = resourcePath . replace ( debugFileRegex , "-dbg$1" ) ;
@@ -248,7 +217,7 @@ export default async function({
248217 sourceMapJson . file = dbgFilename ;
249218
250219 // Then create a new resource
251- dbgSourceMapResource = new Resource ( {
220+ dbgSourceMapResource = resourceFactory . createResource ( {
252221 string : JSON . stringify ( sourceMapJson ) ,
253222 path : dbgPath + ".map"
254223 } ) ;
@@ -265,19 +234,39 @@ export default async function({
265234 }
266235 }
267236 }
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+ }
281270 } ) ) ;
282271}
283272
0 commit comments