"use strict";var _WeakMap = require("@babel/runtime-corejs2/core-js/weak-map");var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");var _Object$getOwnPropertyDescriptor = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptor");var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");_Object$defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _stringify = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/json/stringify"));var _from = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/array/from"));var _assign = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/assign"));var _entries = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/entries"));var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));



var _path = _interopRequireDefault(require("path"));
var _index = require("../../cli-shared-utils/index.js");
var paths = _interopRequireWildcard(require("../lib/paths.js"));
var _manifest = require("../lib/manifest.js");
var _glob = _interopRequireDefault(require("glob"));
var _chalk = _interopRequireDefault(require("chalk"));function _getRequireWildcardCache(e) {if ("function" != typeof _WeakMap) return null;var r = new _WeakMap(),t = new _WeakMap();return (_getRequireWildcardCache = function (e) {return e ? t : r;})(e);}function _interopRequireWildcard(e, r) {if (!r && e && e.__esModule) return e;if (null === e || "object" != typeof e && "function" != typeof e) return { default: e };var t = _getRequireWildcardCache(r);if (t && t.has(e)) return t.get(e);var n = { __proto__: null },a = _Object$defineProperty && _Object$getOwnPropertyDescriptor;for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) {var i = a ? _Object$getOwnPropertyDescriptor(e, u) : null;i && (i.get || i.set) ? _Object$defineProperty(n, u, i) : n[u] = e[u];}return n.default = e, t && t.set(e, n), n;} /**
 * 打出带 main.js 入口的游戏包，适配联盟引擎
 */ /**
 * 将webpack引用的js资源保存到webpack_use_moudle.json文件中，动态编译js时在webpack的webpackEmptyContext中可能会用到
 * @param {*} modules
 */
function saveWebpackUseModules(chunkGraph, modules, unUsedFile) {
  try {
    const modulePathMap = {};
    unUsedFile.forEach((file) => {
      try {
        modulePathMap[file.replace(/\\/g, '/')] = -1;
      } catch (err) {
        (0, _index.error)(err);
      }
    });
    // 遍历所有模块，生成模块 ID 和路径的映射
    modules.forEach((module) => {
      try {
        const id = chunkGraph.getModuleId(module);
        if (id != null) {
          const ss = module.resource;
          if (ss && ss.indexOf(paths.SRC) !== -1) {
            const arr = _path.default.relative(paths.SRC, ss).replace(/\\/g, '/');
            modulePathMap[arr] = chunkGraph.getModuleId(module);
          }
        }
      } catch (err) {
      }
    });
    const webpackUseModule = _path.default.join(paths.BUILD, 'webpack_use_moudle.json');
    if (!_index.fs.existsSync(webpackUseModule)) {
      (0, _index.info)(`webpackUseModule 保存到 ${webpackUseModule}`);
      _index.fs.writeFileSync(webpackUseModule, (0, _stringify.default)(modulePathMap), 'utf8');
    }
  } catch (err) {
    (0, _index.error)(err);
  }
}

/**
 * 将webpack未引用的js文件copy到build目录下参与打包，动态编译js时在webpack的webpackEmptyContext中可能会用到
 * @param {*} fileDependencies
 * @returns
 */
function copyUnUsedFiles(fileDependencies) {
  try {
    // 过滤掉workers配置文件
    const workersPath = (0, _manifest.getWorkersPath)();

    // 获取webpack使用的js模块
    const usedModules = (0, _from.default)(fileDependencies).
    filter((file) => file.indexOf(paths.SRC) !== -1 && (workersPath === '' || file.indexOf(workersPath) === -1)).
    reduce((obj, item) => (0, _assign.default)(obj, { [item]: true }), {});
    const normalizedUsedModules = Object.fromEntries(
      (0, _entries.default)(usedModules).map(([key, value]) => [
      _path.default.normalize(key),
      value]
      )
    );
    // 获取src下所有的js文件
    const files = _glob.default.sync('**/*.js', { ignore: ['node_modules/**'], cwd: paths.SRC, absolute: true });
    // 过滤src下未使用的js文件
    const unUsedFiles = files.filter((file) => !normalizedUsedModules[_path.default.normalize(file)]);

    const allFiles = unUsedFiles.reduce(
      (array, item) => array.concat(item),
      []
    );
    if (!allFiles.length) {
      return [];
    }

    // 将所有未使用的js文件copy到build目录下
    (0, _index.info)(_chalk.default.green('*** Unused Plugin ***'));
    (0, _index.info)(`${allFiles.length} unused source files found.`);
    const unUsedFile = [];
    allFiles.forEach((file) => {
      if (!file.includes('@babel/runtime') && _index.fs.existsSync(file) && !_index.fs.statSync(file).isDirectory()) {
        const relative = _path.default.relative(paths.SRC, file);
        const destFile = _path.default.resolve(paths.BUILD, relative);
        if (!_index.fs.existsSync(destFile)) {
          (0, _index.info)(`unused JS File ${relative} copy to Build dir.`);
          // 默认情况下，如果 dest 已经存在，则覆盖它。
          const destDir = _path.default.dirname(destFile);
          if (!_index.fs.existsSync(destDir)) {
            _index.fs.mkdirSync(destDir, { recursive: true });
          }

          _index.fs.copyFileSync(file, destFile);
          unUsedFile.push(relative);
        }
      }
    });
    // 将未引用的文件缓存下来，webpack完成打包时使用
    paths.unUsedFiles = unUsedFile;
    return unUsedFile;
  } catch (err) {}
}

function retryCopyFileSync(src, dest, maxRetries = 3) {
  let attempts = 0;
  while (attempts < maxRetries) {
    let isCopySuccess = false;
    try {
      // 自动创建目标目录并复制文件
      _index.fs.copySync(src, dest, { overwrite: true });
      (0, _index.info)(`[成功] 文件已复制至: ${dest}`);
      isCopySuccess = true;
    } catch (e) {
      (0, _index.error)(`[错误] 复制失败: ${e.message}`);
      isCopySuccess = false;
    }

    // 如果复制失败，尝试重试
    if (isCopySuccess) {
      return true;
    }
    attempts++;
    (0, _index.info)(`[重试] 第 ${attempts} 次尝试...`);
  }
  (0, _index.error)(`[终止] 重试 ${maxRetries} 次后仍失败`);
  return false;
}

class ZipMainPlugin {
  constructor(options) {
    this.options = options;
  }

  apply(compiler) {
    const pluginName = 'ZipMainPlugin';
    const { singlePackage, alliance, subpackages } = this.options;

    compiler.hooks.afterEmit.tapPromise(pluginName, (compilation) => {
      return new _promise.default((resolve) => {
        // 将webpack未引入的js文件 copy到build目录下
        const unUsedFile = copyUnUsedFiles(compilation.fileDependencies);

        // 将webpack的映射信息保存下来
        saveWebpackUseModules(compilation.chunkGraph, compilation.modules, unUsedFile);

        // 如果是打原整包
        if (singlePackage) {
          // 联盟适配转换代码
          let needTransferAlliance = true;
          const allianceAdapterJS = 'alliance_adapter';
          const gameContent = _index.fs.readFileSync(_path.default.resolve(paths.BUILD, './game.js'), {
            encoding: 'utf-8'
          });
          if (gameContent.includes(allianceAdapterJS)) {
            needTransferAlliance = false;
            if (alliance) {
              (0, _index.info)('game.js 包含联盟 alliance_adapter.js 转换代码，不进行二次转换...');
            }
          }
          if (needTransferAlliance) {
            (0, _index.info)('开始写入联盟适配代码...');
            // 生成 main.js文件，引入 game.js，作为适配联盟api的入口
            if (_index.fs.existsSync(_path.default.resolve(paths.BUILD, './main.js'))) {
              (0, _index.info)('main.js为入口文件，不允许作为业务文件引入进来，如果游戏有报错，请修改文件名，重新打包');
              const content = _index.fs.readFileSync(_path.default.resolve(paths.BUILD, './main.js'), {
                encoding: 'utf-8'
              });

              // 判断build是否包含适配文件
              const allianceJs = _path.default.resolve(paths.BUILD, './alliance_adapter.js');
              if (!_index.fs.existsSync(allianceJs)) {
                const allianceJs = _path.default.join(__dirname, '../alliance_adapter/alliance_adapter.js');
                retryCopyFileSync(allianceJs, _path.default.resolve(paths.BUILD, './alliance_adapter.js'));
              }

              // 判断main.js是否已引入适配js
              if (!content.includes(allianceAdapterJS)) {
                // 重新写入vivo_alliance_adapter
                const allianceAdapterContent = 'require(\'alliance_adapter.js\');\n';
                _index.fs.outputFileSync(_path.default.resolve(paths.BUILD, './main.js'), allianceAdapterContent + content, 'utf8');
              }
            } else {
              const allianceJs = _path.default.join(__dirname, '../alliance_adapter/alliance_adapter.js');
              retryCopyFileSync(allianceJs, _path.default.resolve(paths.BUILD, './alliance_adapter.js'));
              _index.fs.outputFileSync(_path.default.resolve(paths.BUILD, './main.js'), 'require(\'alliance_adapter.js\');\nrequire("game.js");', 'utf8');
            }
          } else {
            // 生成 main.js文件，引入 game.js，作为适配联盟api的入口
            if (_index.fs.existsSync(_path.default.resolve(paths.BUILD, './main.js'))) {
              (0, _index.info)('main.js为入口文件，不允许作为业务文件引入进来，如果游戏有报错，请修改文件名，重新打包');
            } else {
              _index.fs.outputFileSync(_path.default.resolve(paths.BUILD, './main.js'), 'require("game.js");', 'utf8');
            }
          }

          resolve();
        } else {
          // 如果是打分包，检查是目录的分包，增加main.js，引入 game.js
          subpackages.forEach(({ root }) => {
            const ext = _path.default.extname(root);
            if (ext === '') {
              // 如果是联盟，则为了兼容荣耀分包，将分包内的game.js copy到main.js，防止require引用失败
              if (alliance) {
                try {
                  if (_index.fs.existsSync(_path.default.resolve(paths.BUILD, root, './game.js'))) {
                    _index.fs.renameSync(_path.default.resolve(paths.BUILD, root, './game.js'), _path.default.resolve(paths.BUILD, root, './main.js'));
                  }
                  if (_index.fs.existsSync(_path.default.resolve(paths.BUILD, root, './game.js.map'))) {
                    _index.fs.renameSync(_path.default.resolve(paths.BUILD, root, './game.js.map'), _path.default.resolve(paths.BUILD, root, './main.js.map'));
                  }
                } catch (err) {
                  console.error(err);
                }
              } else {
                // 如果是目录
                // 生成 main.js文件，引入 game.js，作为分包适配联盟api的入口
                if (_index.fs.existsSync(_path.default.resolve(paths.BUILD, root, './main.js'))) {
                  // console.warn('main.js为入口文件，不允许作为业务文件引入进来，如果游戏有报错，请修改文件名，重新打包')
                  (0, _index.info)(root + '/main.js为入口文件，不允许作为业务文件引入进来，如果游戏有报错，请修改文件名，重新打包');
                  // throw new Error('main.js为子包入口文件，不允许作为业务文件引入，请修改文件名，重新打包')
                } else {
                  _index.fs.outputFileSync(_path.default.resolve(paths.BUILD, root, './main.js'), 'require("./game.js");', 'utf8');
                }
              }
            }
          });
          resolve();
        }
      });
    });
  }
}var _default = exports.default =

ZipMainPlugin;