如何从回调函数中获取回调函数中的值

时间:2017-10-20 20:33:50

标签: javascript webpack callback webpack-2 urlloader

我正在为Pug文件编写一个Webpack加载器。它加载Pug文件中引用的所有依赖图像,使用file-loader将它们复制到适当的目录,并用生成的文件的URL替换Pug文件中的require()个调用。

我正在尝试添加功能以允许将数据URL插入到Pug文件中以代替文件URL。我现在正在使用this.loadModule()来执行file-loader

此函数将回调作为参数。传递给此回调的其中一个args包含url-loader(数据URL)的结果。所以,我需要这个写入应该输出的Pug文件。

问题是,整个加载程序在回调运行之前完成运行。因此,我对数据所做的任何事情都不会在最终文件中结束。我的程序的整体结构如下所示:

module.exports = function pugDepLoader(inputFile) {

/* Setting up various constants and variables. */

/* A while() loop that continually tests inputFile with a 
regex to find require() statements.  

It creates a copy of inputFile called outputFile, 
which it iterates over again and again, 
replacing require() statements with file paths 
one at a time.  

The call to this.loadModule() is within this while() loop. */

/* End of while() loop */

/* Return outputFile to Webpack, which is now a 
string with the Pug file, but with the 
require() statements replaced with 
file paths.  

This is meant to be fed to file-loader to 
get written out to disc. */

}

this.loadModule()的回调运行一次之前,最后的return语句将被重复调用,正如我在调试语句中发现的那样。我需要能够在返回之前将回调中提供的数据URL提取到outputFile,以便最终写入最终写入光盘的文件中。

完整的源代码如下:

module.exports = function pugDepLoader(inputFile) {

  const fs = require('fs');
  const path = require('path');
  const loaderUtils = require('loader-utils');

  var options = loaderUtils.getOptions(this);

  //This option is required. It specifies
  //the path to the root of the Pug file's
  //dependencies relative to the location
  //of the Pug files.
  var contextualRoot;

  if(!options || !options.hasOwnProperty('contextualRoot')) {
    throw new Error('You must specify a contextual root');
  }

  else {
    contextualRoot = options.contextualRoot;

    //Ensure there is a trailing slash.
    if(contextualRoot[contextualRoot.length-1] !== '/') {
      contextualRoot = contextualRoot + '/';
    }
  }

  //Determines whether paths should begin with
  //a leading slash. Useful for Express.js
  //compatibility.
  if(!options.hasOwnProperty('absolute')) {
    options.absolute = false;
  }

  //Set up regex to search for require() statements
  const reqRE = new RegExp(/require\(/, 'g');

  //outputFile will be returned containing the
  //appropriately processed Pug
  var outputFile = inputFile.slice();

  //We need to execute reqRE once to kick things
  //off, and we need to save it to a variable
  //because we need information from it.
  let regexResult = reqRE.exec(inputFile);

  //regexResult will be null when there
  //are no more matches to be found in
  //the file.
  while(regexResult != null) {

    //pathStartIndex is the beginning of
    //the path to the required file.
    //We add 1 to skip the opening
    //single quote.
    let pathStartIndex = reqRE.lastIndex+1;

    //We require the path to be wrapped in
    //single quotes, so that we can easily
    //be certain about where the require
    //statement ends.
    if(inputFile[reqRE.lastIndex] !== "'") {
      console.log('FATAL ERROR: File path must be wrapped in single quotes!');
      break;
    }

    //inputPath will hold the actual file path itself.
    let inputPath = inputFile.slice(pathStartIndex, inputFile.indexOf("'", pathStartIndex));

    //pathArray is used to split the
    //path so we can easily extract
    //the file name and path
    //separately.
    let pathArray = inputPath.split('/');

    //Just the file name, with extension.
    let fileName = pathArray.pop();

    //outputPath will define what path should be
    //written into the output Pug file.
    //The user may optionally specify a
    //custom output path.
    let outputPath;

    if(options.outputPath) {
      outputPath = options.outputPath;
    }

    else {
      outputPath = pathArray.join('/');
    }

    //Ensure a trailing slash.
    if(outputPath[outputPath.length-1] !== '/') {
      outputPath = (outputPath + '/');
    }

    //reqStart holds the index of the letter
    //"r" in require(), so that we can remove
    //the require() call and replace it
    //with the file path.
    let reqStart = inputFile.indexOf('require', regexResult.index);

    //reqStmt is the require() statement in
    //full. This will be used with replace()
    //to replace the require() call with a
    //file path in the output file.
    let reqStmt = inputFile.slice(reqStart, inputFile.indexOf('"', pathStartIndex));

    //The final file path, with file name.
    //This will be written into the output
    //Pug file in place of the require()
    //calls.
    let filePath = outputPath + fileName;

    if(options.absolute && filePath[0] !== '/') {
      if(filePath[0] === '.' && filePath[1] === '/') {
        filePath = filePath.slice(1);
      }
      else {
        filePath = '/' + filePath;
      }
    }

    else if(!options.absolute && filePath[0] === '/') {
      filePath = filePath.slice(1);
    }

  this.loadModule(contextualRoot + inputPath, (err, res, srcmap, module) => {
    if(err) {
      console.log(err);
    }
    if(new RegExp(/data:image/).test(res)) {
      filePath = res.slice(res.indexOf('data:image'), res.lastIndexOf('"'));
    }
  });

    //This takes care of require() calls
    //inside of url() CSS functions,
    //such as are used to declare
    //background images inline.

    //If the word "require" is
    //preceeded by a single quote,
    //it is within a url() function,
    //and so we add appropriate closure
    //for that function to the end of
    //the path.
    if(inputFile[reqStart-1] === "'") {
      filePath = filePath + "');";
    }
    //Write the output.
    outputFile = outputFile.replace(reqStmt, filePath);

    //Run the next iteration of the regex search.
    regexResult = reqRE.exec(inputFile);
  }
  //Return output as a string to Webpack.
  return outputFile;
}

0 个答案:

没有答案