import fs from 'fs'; import { minify_sync } from 'terser'; import * as path from 'path'; class Minifier { static MinifyList = [ 'CDClientLib', 'websocket', 'modules', 'page', 'App.js' ]; static combine() { const getAllJSFiles = (dirPath, fileList = []) => { const files = fs.readdirSync(dirPath); files.forEach(file => { const filePath = path.join(dirPath, file); if (fs.statSync(filePath).isDirectory()) { getAllJSFiles(filePath, fileList); } else if (filePath.endsWith('.js')) { fileList.push(filePath); } }); return fileList; }; const mergeFilesWithComments = (fileList) => { let mergedContent = ''; for (let i = 0; i < fileList.length; i++) { mergedContent += `\n\n/*! >>> ${fileList[i]} */\n\n`; const filePath = fileList[i]; const fileContent = fs.readFileSync(filePath, 'utf8'); mergedContent += fileContent; } return mergedContent; } const allJSFiles = this.MinifyList.reduce((accumulator, currentPath) => { currentPath = path.join('./build/static/', currentPath); if (fs.statSync(currentPath).isDirectory()) { return accumulator.concat(getAllJSFiles(currentPath)); } else if (currentPath.endsWith('.js')) { return accumulator.concat(currentPath); } return accumulator; }, []); const mergedContent = mergeFilesWithComments(allJSFiles); fs.writeFileSync('./build/static/merged_statics.js', mergedContent, { encoding: 'utf8' }); } static uglify() { const mangleProperties = { properties: { reserved: [ '$', // jQuery // >>> CodeMirror 'CodeMirror', 'cmLineCount', 'cmEachLine', 'cmRefresh', 'cmSetValue', 'scrollIntoView', 'markText', 'getSearchCursor', 'cmFirstLine', 'setSelection', 'cmGetValue', 'replaceRange', 'setCursor', 'cmGetLine', 'cmFocus', 'lineNo', 'onClassLinkClick', 'onPropertyClick', 'line', // <<< CodeMirror // >>> Server data 'Class', 'isAdmin', 'isEditor', 'Login', 'ClassList', 'ClassSource', 'RepoNames', 'Z8Locales', 'Comments', 'LastUpdateTime', 'StatisticsUser', 'comment', 'timestamp', 'nearestParent', 'nearestParentRoot', 'type', 'value', 'key', 'inherited', 'overridden', 'dynamic', 'author', // <<< Server data // >>> WebSocket 'onopen', 'onclose', 'onerror', 'onmessage', 'send' // <<< WebSocket ], keep_quoted: true }, toplevel: true } const uglified = minify_sync(fs.readFileSync('./build/static/merged_statics.js', 'utf8').toString(), { mangle: mangleProperties }); const uglifiedCode = uglified.code.replace(/\/\*\!\s>>>\s(.+)\s\*\/([^\s])/g, '/*! >>> $1 */\n$2'); const uglifiedCodeStrings = uglifiedCode.split('\n'); let fPath = ''; let fContents = {}; for(const str of uglifiedCodeStrings) { const fnMatch = str.match(/\/\*\!\s>>>\s(.+)\s\*\//); if(fnMatch) { fPath = `./${fnMatch[1]}`; fContents[fPath] = ''; } else { fContents[fPath] += str + '\n'; } } for(const file of Object.keys(fContents)) { fs.writeFileSync(file, fContents[file], { encoding: 'utf8' }); } } static clean() { fs.rmSync('./build/static/merged_statics.js'); } static run() { Minifier.combine(); Minifier.uglify(); Minifier.clean(); } } Minifier.run();