function getCompileFn(loaderContext, implementation, apiType) {
  if (typeof implementation.compileStringAsync !== "undefined") {
    if (apiType === "modern") {
      return (sassOptions) => {
        const { data, ...rest } = sassOptions;

        return implementation.compileStringAsync(data, rest);
      };
    }

    if (apiType === "modern-compiler") {
      return async (sassOptions) => {
        // eslint-disable-next-line no-underscore-dangle
        const webpackCompiler = loaderContext._compiler;
        const { data, ...rest } = sassOptions;

        // Some people can run the loader in a multi-threading way;
        // there is no webpack compiler object in such case.
        if (webpackCompiler) {
          if (!sassModernCompilers.has(webpackCompiler)) {
            // Create a long-running compiler process that can be reused
            // for compiling individual files.
            const compiler = await implementation.initAsyncCompiler();

            // Check again because awaiting the initialization function
            // introduces a race condition.
            if (!sassModernCompilers.has(webpackCompiler)) {
              sassModernCompilers.set(webpackCompiler, compiler);
              webpackCompiler.hooks.shutdown.tap("sass-loader", () => {
                compiler.dispose();
              });
            } else {
              compiler.dispose();
            }
          }

          return sassModernCompilers
            .get(webpackCompiler)
            .compileStringAsync(data, rest);
        }

        return implementation.compileStringAsync(data, rest);
      };
    }

    return (sassOptions) =>
      new Promise((resolve, reject) => {
        implementation.render(sassOptions, (error, result) => {
          if (error) {
            reject(error);

            return;
          }

          resolve(result);
        });
      });
  }

  if (apiType === "modern" || apiType === "modern-compiler") {
    throw new Error("Modern API is not supported for 'node-sass'");
  }

  // There is an issue with node-sass when async custom importers are used
  // See https://github.com/sass/node-sass/issues/857#issuecomment-93594360
  // We need to use a job queue to make sure that one thread is always available to the UV lib
  if (nodeSassJobQueue === null) {
    const threadPoolSize = Number(process.env.UV_THREADPOOL_SIZE || 4);
    // Only used for `node-sass`, so let's load it lazily
    // eslint-disable-next-line global-require
    const async = require("neo-async");

    nodeSassJobQueue = async.queue(
      implementation.render.bind(implementation),
      threadPoolSize - 1,
    );
  }

  return (sassOptions) =>
    new Promise((resolve, reject) => {
      nodeSassJobQueue.push.bind(nodeSassJobQueue)(
        sassOptions,
        (error, result) => {
          if (error) {
            reject(error);

            return;
          }

          resolve(result);
        },
      );
    });
}
Verifies that the implementation and version of Sass is supported by this loader.

@param {Object} loaderContext
@param {Object} implementation
@param {"legacy" | "modern" | "modern-compiler"} apiType
@returns {Function}