sortModules(compilation, chunk, modules, requestShortener) {
    let usedModules = this._sortedModulesCache.get(chunk);

    if (usedModules || !modules) {
      return /** @type {Set<CssModule>} */ (usedModules);
    }

    /** @type {CssModule[]} */
    const modulesList = [...modules];
    // Store dependencies for modules
    /** @type {Map<CssModule, Set<CssModule>>} */
    const moduleDependencies = new Map(
      modulesList.map((m) => [
        m,
        /** @type {Set<CssModule>} */
        (new Set()),
      ])
    );
    /** @type {Map<CssModule, Map<CssModule, Set<ChunkGroup>>>} */
    const moduleDependenciesReasons = new Map(
      modulesList.map((m) => [m, new Map()])
    );
    // Get ordered list of modules per chunk group
    // This loop also gathers dependencies from the ordered lists
    // Lists are in reverse order to allow to use Array.pop()
    /** @type {CssModule[][]} */
    const modulesByChunkGroup = Array.from(
      chunk.groupsIterable,
      (chunkGroup) => {
        const sortedModules = modulesList
          .map((module) => {
            return {
              module,
              index: chunkGroup.getModulePostOrderIndex(module),
            };
          })
          // eslint-disable-next-line no-undefined
          .filter((item) => item.index !== undefined)
          .sort(
            (a, b) =>
              /** @type {number} */ (b.index) - /** @type {number} */ (a.index)
          )
          .map((item) => item.module);

        for (let i = 0; i < sortedModules.length; i++) {
          const set = moduleDependencies.get(sortedModules[i]);

          const reasons =
            /** @type {Map<CssModule, Set<ChunkGroup>>} */
            (moduleDependenciesReasons.get(sortedModules[i]));

          for (let j = i + 1; j < sortedModules.length; j++) {
            const module = sortedModules[j];

            /** @type {Set<CssModule>} */
            (set).add(module);

            const reason =
              reasons.get(module) || /** @type {Set<ChunkGroup>} */ (new Set());

            reason.add(chunkGroup);

            reasons.set(module, reason);
          }
        }

        return sortedModules;
      }
    );

    // set with already included modules in correct order
    usedModules = new Set();

    /**
     * @param {CssModule} m
     * @returns {boolean}
     */
    const unusedModulesFilter = (m) =>
      !(/** @type {Set<CssModule>} */ (usedModules).has(m));

    while (usedModules.size < modulesList.length) {
      let success = false;
      let bestMatch;
      let bestMatchDeps;

      // get first module where dependencies are fulfilled
      for (const list of modulesByChunkGroup) {
        // skip and remove already added modules
        while (list.length > 0 && usedModules.has(list[list.length - 1])) {
          list.pop();
        }

        // skip empty lists
        if (list.length !== 0) {
          const module = list[list.length - 1];
          const deps = moduleDependencies.get(module);
          // determine dependencies that are not yet included
          const failedDeps = Array.from(
            /** @type {Set<CssModule>} */
            (deps)
          ).filter(unusedModulesFilter);

          // store best match for fallback behavior
          if (!bestMatchDeps || bestMatchDeps.length > failedDeps.length) {
            bestMatch = list;
            bestMatchDeps = failedDeps;
          }

          if (failedDeps.length === 0) {
            // use this module and remove it from list
            usedModules.add(/** @type {CssModule} */ (list.pop()));
            success = true;
            break;
          }
        }
      }

      if (!success) {
        // no module found => there is a conflict
        // use list with fewest failed deps
        // and emit a warning
        const fallbackModule = /** @type {CssModule[]} */ (bestMatch).pop();

        if (!this.options.ignoreOrder) {
          const reasons = moduleDependenciesReasons.get(
            /** @type {CssModule} */ (fallbackModule)
          );

          compilation.warnings.push(
            /** @type {WebpackError} */
            (
              new Error(
                [
                  `chunk ${chunk.name || chunk.id} [${pluginName}]`,
                  "Conflicting order. Following module has been added:",
                  ` * ${
                    /** @type {CssModule} */ (
                      fallbackModule
                    ).readableIdentifier(requestShortener)
                  }`,
                  "despite it was not able to fulfill desired ordering with these modules:",
                  .../** @type {CssModule[]} */ (bestMatchDeps).map((m) => {
                    const goodReasonsMap = moduleDependenciesReasons.get(m);
                    const goodReasons =
                      goodReasonsMap &&
                      goodReasonsMap.get(
                        /** @type {CssModule} */ (fallbackModule)
                      );
                    const failedChunkGroups = Array.from(
                      /** @type {Set<ChunkGroup>} */
                      (
                        /** @type {Map<CssModule, Set<ChunkGroup>>} */
                        (reasons).get(m)
                      ),
                      (cg) => cg.name
                    ).join(", ");
                    const goodChunkGroups =
                      goodReasons &&
                      Array.from(goodReasons, (cg) => cg.name).join(", ");
                    return [
                      ` * ${m.readableIdentifier(requestShortener)}`,
                      `   - couldn't fulfill desired order of chunk group(s) ${failedChunkGroups}`,
                      goodChunkGroups &&
                        `   - while fulfilling desired order of chunk group(s) ${goodChunkGroups}`,
                    ]
                      .filter(Boolean)
                      .join("\n");
                  }),
                ].join("\n")
              )
            )
          );
        }

        usedModules.add(/** @type {CssModule} */ (fallbackModule));
      }
    }

    this._sortedModulesCache.set(chunk, usedModules);

    return usedModules;
  }
@private
@param {Compilation} compilation
@param {Chunk} chunk
@param {CssModule[]} modules
@param {Compilation["requestShortener"]} requestShortener
@returns {Set<CssModule>}