• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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