1/* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16const fs = require('fs') 17const path = require('path') 18const process = require('child_process') 19const qjsc = path.join(__dirname, '..', 'bin', 'qjsc') 20const checkWorksFile = require('./genAbc-plugin').checkWorksFile 21 22const forward = '(global.___mainEntry___ = function (globalObjects) {' + '\n' + 23 ' const define = globalObjects.define;' + '\n' + 24 ' const require = globalObjects.require;' + '\n' + 25 ' const bootstrap = globalObjects.bootstrap;' + '\n' + 26 ' const register = globalObjects.register;' + '\n' + 27 ' const render = globalObjects.render;' + '\n' + 28 ' const $app_define$ = globalObjects.$app_define$;' + '\n' + 29 ' const $app_bootstrap$ = globalObjects.$app_bootstrap$;' + '\n' + 30 ' const $app_require$ = globalObjects.$app_require$;' + '\n' + 31 ' const history = globalObjects.history;' + '\n' + 32 ' const Image = globalObjects.Image;' + '\n' + 33 ' const OffscreenCanvas = globalObjects.OffscreenCanvas;' + '\n' + 34 ' (function(global) {' + '\n' + 35 ' "use strict";' + '\n' 36const last = '\n' + '})(this.__appProto__);' + '\n' + '})' 37const firstFileEXT = '.jtc' 38const sencondFileEXT = '.c' 39const lastFileEXT = '.bin' 40let output 41let webpackPath 42let workerFile = null; 43 44class GenBinPlugin { 45 constructor(output_, webpackPath_, workerFile_) { 46 output = output_ 47 webpackPath = webpackPath_ 48 workerFile = workerFile_ 49 } 50 apply(compiler) { 51 if (!fs.existsSync(path.resolve(webpackPath, 'qjsc.exe')) && !fs.existsSync(path.resolve(webpackPath, 'qjsc'))) { 52 return 53 } 54 compiler.hooks.emit.tap('GenBinPlugin', (compilation) => { 55 const assets = compilation.assets 56 const keys = Object.keys(assets) 57 keys.forEach(key => { 58 // choice *.js 59 if (output && webpackPath && path.extname(key) === '.js') { 60 let newContent = assets[key].source() 61 if (checkWorksFile(key, workerFile)) { 62 newContent = forward + newContent + last 63 } 64 const keyPath = key.replace(/\.js$/, firstFileEXT) 65 writeFileSync(newContent, path.resolve(output, keyPath), key) 66 } 67 }) 68 }) 69 } 70} 71 72function writeFileSync(inputString, output, jsBundleFile) { 73 const parent = path.join(output, '..') 74 if (!(fs.existsSync(parent) && fs.statSync(parent).isDirectory())) { 75 mkDir(parent) 76 } 77 fs.writeFileSync(output, inputString) 78 if (fs.existsSync(output)){ 79 qjscFirst(output, output.replace(/\.jtc$/, sencondFileEXT)) 80 } else { 81 console.error('\u001b[31m', `Failed to convert file ${jsBundleFile} to bin. ${output} is lost`, '\u001b[39m') 82 } 83} 84 85function mkDir(path_) { 86 const parent = path.join(path_, '..') 87 if (!(fs.existsSync(parent) && !fs.statSync(parent).isFile())) { 88 mkDir(parent) 89 } 90 fs.mkdirSync(path_) 91} 92 93function qjscFirst(inputPath, outputPath) { 94 const cmd = `"${qjsc}" -o "${outputPath}" -N buf -c "${inputPath}"` 95 try { 96 process.execSync(cmd) 97 } catch (e) { 98 console.error('\u001b[31m', `Failed to convert file ${inputPath} to bin`, '\u001b[39m') 99 } 100 if (fs.existsSync(inputPath)) { 101 fs.unlinkSync(inputPath) 102 qjscSecond(outputPath) 103 } else { 104 console.error('\u001b[31m', `Failed to convert file ${inputPath} to bin. ${inputPath} is lost`, '\u001b[39m') 105 } 106} 107 108function qjscSecond(filePath) { 109 let data = fs.readFileSync(filePath, 'utf8') 110 data = data.substr(data.indexOf('{') + 1, data.indexOf('}') - data.indexOf('{') - 1).trim() 111 const lastFilePath = filePath.replace(/\.c$/, lastFileEXT) 112 const parent = path.join(lastFilePath, '..') 113 if (!(fs.existsSync(parent) && fs.statSync(parent).isDirectory())) { 114 mkDir(parent) 115 } 116 fs.writeFileSync(lastFilePath, toBuffer(data)) 117 if (fs.existsSync(filePath)) { 118 fs.unlinkSync(filePath) 119 } else { 120 console.error('\u001b[31m', `Failed to clean file ${filePath}.`, '\u001b[39m') 121 } 122} 123 124function toBuffer(str) { 125 const bytes = str.split(',') 126 const b = Buffer.alloc(bytes.length) 127 for (let i = 0; i < bytes.length; i++) { 128 b[i] = bytes[i] 129 } 130 return b 131} 132 133module.exports = GenBinPlugin 134