有了它们就能更好的理解webpack了

最新内容,请在github阅读。同时,All issue and star welcomed!

1.获取webpack配置的输出配置

 compilation.outputOptions

其中该对象有如下内容:

 { path: ‘builds‘,
     filename: ‘bundle.js‘,
     publicPath: ‘builds/‘,
     chunkFilename: ‘[id].bundle.js‘,
     library: ‘‘,
     hotUpdateFunction: ‘webpackHotUpdate‘,
     jsonpFunction: ‘webpackJsonp‘,
     libraryTarget: ‘var‘,
     sourceMapFilename: ‘[file].map[query]‘,
     hotUpdateChunkFilename: ‘[id].[hash].hot-update.js‘,
     hotUpdateMainFilename: ‘[hash].hot-update.json‘,
     crossOriginLoading: false,
     hashFunction: ‘md5‘,
     hashDigest: ‘hex‘,
     hashDigestLength: 20,
     devtoolLineToLine: false,
     strictModuleExceptionHandling: false }

如果你需要更多的信息只能通过如下:

compilation.options
  {
   entry: ‘./src‘,
  output:
   { path: ‘builds‘,
     filename: ‘bundle.js‘,
     publicPath: ‘builds/‘,
     chunkFilename: ‘[id].bundle.js‘,
     library: ‘‘,
     hotUpdateFunction: ‘webpackHotUpdate‘,
     jsonpFunction: ‘webpackJsonp‘,
     libraryTarget: ‘var‘,
     sourceMapFilename: ‘[file].map[query]‘,
     hotUpdateChunkFilename: ‘[id].[hash].hot-update.js‘,
     hotUpdateMainFilename: ‘[hash].hot-update.json‘,
     crossOriginLoading: false,
     hashFunction: ‘md5‘,
     hashDigest: ‘hex‘,
     hashDigestLength: 20,
     devtoolLineToLine: false,
     strictModuleExceptionHandling: false },
  plugins:
   [ CommonsChunkPlugin {
       chunkNames: ‘vendor‘,
       filenameTemplate: ‘vendor.bundle.js‘,
       minChunks: 2,
       selectedChunks: undefined,
       async: undefined,
       minSize: undefined,
       ident: ‘C:\\Users\\Administrator\\Desktop\\webpack-chunkfilename\\node_mo
dules\\webpack\\lib\\optimize\\CommonsChunkPlugin.js0‘ },
     HtmlWebpackPlugin {
       options: [Object],
       childCompilerHash: ‘729d3caf962246f308dc6d5b1542a9ae‘,
       childCompilationOutputName: ‘index.html‘ } ],
  module:
   { loaders: [ [Object], [Object], [Object], [Object] ],
     unknownContextRequest: ‘.‘,
     unknownContextRegExp: false,
     unknownContextRecursive: true,
     unknownContextCritical: true,
     exprContextRequest: ‘.‘,
     exprContextRegExp: false,
     exprContextRecursive: true,
     exprContextCritical: true,
     wrappedContextRegExp: /.*/,
     wrappedContextRecursive: true,
     wrappedContextCritical: false,
     unsafeCache: true },
  bail: false,
  profile: false,
  context: ‘C:\\Users\\Administrator\\Desktop\\webpack-chunkfilename‘,
  devtool: false,
  cache: true,
  target: ‘web‘,

  node:
   { console: false,
     process: true,
     global: true,
     Buffer: true,
     setImmediate: true,
     __filename: ‘mock‘,
     __dirname: ‘mock‘ },
  performance: { maxAssetSize: 250000, maxEntrypointSize: 250000, hints: false }
,
  resolve:
   { unsafeCache: true,
     modules: [ ‘node_modules‘ ],
     extensions: [ ‘.js‘, ‘.json‘ ],
     aliasFields: [ ‘browser‘ ],
     mainFields: [ ‘browser‘, ‘module‘, ‘main‘ ] },
  resolveLoader:
   { unsafeCache: true,
     mainFields: [ ‘loader‘, ‘main‘ ],
     extensions: [ ‘.js‘, ‘.json‘ ] } }

注意我们其中关注的几点,node模块!

下面给出一个获取publicPath(输出配置)路径的例子:

 var webpackStatsJson = compilation.getStats().toJson();
  //获取compilation的所有的信息
  // Use the configured public path or build a relative path
  var publicPath = typeof compilation.options.output.publicPath !== ‘undefined‘
    // If a hard coded public path exists use it
    ? compilation.mainTemplate.getPublicPath({hash: webpackStatsJson.hash})
    // If no public path was set get a relative url path
    // 这个publicPath是可以使用hash的
    : path.relative(path.resolve(compilation.options.output.path, path.dirname(self.childCompilationOutputName)), compilation.options.output.path)
      .split(path.sep).join(‘/‘);
    //self.childCompilationOutputName得到的"index.html",dirname得到的是".",所以resolve结果为" C:\Users\Administrator\Desktop\webpack-chunkfilename\builds"
    if (publicPath.length && publicPath.substr(-1, 1) !== ‘/‘) {
      publicPath += ‘/‘;
    }
    //获取倒数第一个字符,添加一个"/"

很显然我们的publicPath是可以配置hash参数的,如果没有配置publicPath那么我们是相对于output.path目录来说的!

2.如何获取启动一个子compiler中的错误信息

if (childCompilation && childCompilation.errors && childCompilation.errors.length) {
        var errorDetails = childCompilation.errors.map(function (error) {
          return error.message + (error.error ? ‘:\n‘ + error.error : ‘‘);
        }).join(‘\n‘);
        reject(new Error(‘Child compilation failed:\n‘ + errorDetails));
        //如果报错,直接reject
      }

其实对于compiler对象,而不是childCompiler对象也是同样的道理

3.开启的child compiler如何对文件中的hash等进行替换得到最终文件名

   //‘assets-path‘钩子函数来完成文件名替
   var outputName = compilation.mainTemplate.applyPluginsWaterfall(‘asset-path‘, outputOptions.filename, {
          hash: childCompilation.hash,
          chunk: entries[0]
          //因为上面提供的是SingleEntryPlugin ·
        });

注意:此处调用的是compilation而不是childCompilation完成的!

4.如何加载本地文件系统的文件然后开启一个新的child c compiler

HtmlWebpackPlugin.prototype.getFullTemplatePath = function (template, context) {
  // If the template doesn‘t use a loader use the lodash template loader
  if (template.indexOf(‘!‘) === -1) {
    template = require.resolve(‘./lib/loader.js‘) + ‘!‘ + path.resolve(context, template);
    //对于我们的这个ejs文件,我们使用特定的loader加载
  }
  // Resolve template path
  return template.replace(
    /([!])([^/\\][^!?]+|[^/\\!?])($|\?[^!?\n]+$)/,
    function (match, prefix, filepath, postfix) {
      return prefix + path.resolve(filepath) + postfix;
    });
};
//通过上面的getFullTemplatePath得到通过loader加载文件后的完整的形式,最后传入到我们的SingleEntryPlugin中
  childCompiler.apply(
    new NodeTemplatePlugin(outputOptions),
    new NodeTargetPlugin(),
    new LibraryTemplatePlugin(‘HTML_WEBPACK_PLUGIN_RESULT‘, ‘var‘),
    new SingleEntryPlugin(this.context, template),
    //上面的通过loader加载的本地文件系统的内容传入到我们的SingleEntryPlugin中
    new LoaderTargetPlugin(‘node‘)
  );

所以上面的传入到中的内容大致如下(其中!后面表示要加载的文件,前面表示相应的loader):

C:\Users\Administrator\Desktop\webpack-chunkfilename\node_modules\html-webpack-plugin\lib\loader.js!C:\Users\Administrator\Desktop\w

ebpack-chunkfilename\node_modules\html-webpack-plugin\default_index.ejs

4.获取stats中所有的chunks

获取compilation所有的chunks:

compilation.getStats().toJson().chunks

chunks所有的内容如下:

[ { id: 0,//chunk id
    rendered: true,
    initial: false,//require.ensure产生,非initial
    entry: false,//非入口文件
    recorded: undefined,
    extraAsync: false,
    size: 296855,//chunk大小,比特
    names: [],//require.ensure不是通过webpack配置的,所以chunk的names是空
    files: [ ‘0.bundle.js‘ ],//该chunk产生的文件
    hash: ‘42fbfbea594ba593e76a‘,//chunk的hash
    parents: [ 2 ],//父级chunk
    origins: [ [Object] ] },
  { id: 1,
    rendered: true,
    initial: false,//require.ensure产生,非initial
    entry: false,//非入口文件
    recorded: undefined,
    extraAsync: false,
    size: 297181,//chunk大小,比特
    names: [],
    files: [ ‘1.bundle.js‘ ],//产生的文件
    hash: ‘456d05301e4adca16986‘,//chunk的hash
    parents: [ 2 ],
    origins: [ [Object] ] },
  { id: 2,
    rendered: true,
    initial: true,//commonchunkplugin产生或者入口文件产生
    entry: false,//非入口文件
    recorded: undefined,
    extraAsync: false,
    size: 687,//chunk大小,比特
    names: [ ‘main‘ ],
    files: [ ‘bundle.js‘ ],//产生的文件
    hash: ‘248029a0cfd99f46babc‘,//chunk的hash
    parents: [ 3 ],
    origins: [ [Object] ] },
  { id: 3,
    rendered: true,
    initial: true,//monchunkplugin产生或者入口文件产生
    entry: true,//commonchunkplugin把webpack执行环境抽取出来
    recorded: undefined,
    extraAsync: false,
    size: 0,//chunk大小,比特
    names: [ ‘vendor‘ ],
    files: [ ‘vendor.bundle.js‘ ],//产生的文件
    hash: ‘fbf76c7c330eaf0de943‘,//chunk的hash
    parents: [],
    origins: [] } ]

注意chunk的names是一个数组!

下面是给出的几个关于chunks的例子:

例1:html-webpack-plugin中就使用到了多个chunks属性,如names,initial等

//该chunk要被选中的条件是:有名称,不是懒加载,在includedChunks中但是不在excludedChunks中
HtmlWebpackPlugin.prototype.filterChunks = function (chunks, includedChunks, excludedChunks) {
  return chunks.filter(function (chunk) {
    var chunkName = chunk.names[0];
    // This chunk doesn‘t have a name. This script can‘t handled it.
    //通过require.ensure产生的chunk不会被保留,names是一个数组
    if (chunkName === undefined) {
      return false;
    }
    // Skip if the chunk should be lazy loaded
    //如果是require.ensure产生的chunk直接忽略
    if (!chunk.initial) {
      return false;
    }
    // Skip if the chunks should be filtered and the given chunk was not added explicity
    //这个chunk必须在includedchunks里面
    if (Array.isArray(includedChunks) && includedChunks.indexOf(chunkName) === -1) {
      return false;
    }
    // Skip if the chunks should be filtered and the given chunk was excluded explicity
    //这个chunk不能在excludedChunks中
    if (Array.isArray(excludedChunks) && excludedChunks.indexOf(chunkName) !== -1) {
      return false;
    }
    // Add otherwise
    return true;
  });
};

例2:通过id对chunks进行排序

/**
 * Sorts the chunks based on the chunk id.
 *
 * @param  {Array} chunks the list of chunks to sort
 * @return {Array} The sorted list of chunks
 * entry chunk在前,两个都是entry那么id大的在前
 */
module.exports.id = function (chunks) {
  return chunks.sort(function orderEntryLast (a, b) {
    if (a.entry !== b.entry) {
      return b.entry ? 1 : -1;
    } else {
      return b.id - a.id;
    }
  });
};

这样入口文件都会排列在前面,但是有一点就是这里的id较大的在前面,这和我们的occurenceOrderplugin完全是相反的,所以这里还是存在疑问的。

例3:通过chunk.parents(全部是parentId数组)来获取拓排序

/*
  Sorts dependencies between chunks by their "parents" attribute.
  This function sorts chunks based on their dependencies with each other.
  The parent relation between chunks as generated by Webpack for each chunk
  is used to define a directed (and hopefully acyclic) graph, which is then
  topologically sorted in order to retrieve the correct order in which
  chunks need to be embedded into HTML. A directed edge in this graph is
  describing a "is parent of" relationship from a chunk to another (distinct)
  chunk. Thus topological sorting orders chunks from bottom-layer chunks to
  highest level chunks that use the lower-level chunks.

  @param {Array} chunks an array of chunks as generated by the html-webpack-plugin.
  It is assumed that each entry contains at least the properties "id"
  (containing the chunk id) and "parents" (array containing the ids of the
  parent chunks).
  @return {Array} A topologically sorted version of the input chunks
  因为最上面的通过commonchunkplugin产生的chunk具有webpack的runtime,所以排列在前面
*/
module.exports.dependency = function (chunks) {
  if (!chunks) {
    return chunks;
  }
  // We build a map (chunk-id -> chunk) for faster access during graph building.
  // 通过chunk-id -> chunk这种Map结构更加容易绘制图
  var nodeMap = {};
  chunks.forEach(function (chunk) {
    nodeMap[chunk.id] = chunk;
  });
  // Next, we add an edge for each parent relationship into the graph
  var edges = [];
  chunks.forEach(function (chunk) {
    if (chunk.parents) {
      // Add an edge for each parent (parent -> child)
      chunk.parents.forEach(function (parentId) {
        // webpack2 chunk.parents are chunks instead of string id(s)
        var parentChunk = _.isObject(parentId) ? parentId : nodeMap[parentId];
        // If the parent chunk does not exist (e.g. because of an excluded chunk)
        // we ignore that parent
        if (parentChunk) {
          edges.push([parentChunk, chunk]);
        }
      });
    }
  });
  // We now perform a topological sorting on the input chunks and built edges
  return toposort.array(chunks, edges);
};

通过这种方式可以把各个chunk公有的模块排列在前面,从而提前加载,这是合理的!

5.获取stats中所有的assets

获取compilation所有的assets:

compilation.getStats().toJson().assets

assets内部结构如下:

 [ { name: ‘0.bundle.js‘,
    size: 299109,
    chunks: [ 0, 3 ],

    chunkNames: [],
    emitted: undefined,
    isOverSizeLimit: undefined },
  { name: ‘1.bundle.js‘,
    size: 299469,
    chunks: [ 1, 3 ],
    chunkNames: [],
    emitted: undefined,
    isOverSizeLimit: undefined },
  { name: ‘bundle.js‘,

    size: 968,

    chunks: [ 2, 3 ],

    chunkNames: [ ‘main‘ ],

    emitted: undefined,

    isOverSizeLimit: undefined },
  { name: ‘vendor.bundle.js‘,
    size: 5562,
    chunks: [ 3 ],
    chunkNames: [ ‘vendor‘ ],
    emitted: undefined,
    isOverSizeLimit: undefined }]

上次看到webpack-dev-server源码的时候看到了如何判断该assets是否变化的判断,其就是通过上面的emitted来判断的:

compiler.plugin("done", function(stats) {
    this._sendStats(this.sockets, stats.toJson(clientStats));
    //clientStats表示客户端stats要输出的内容过滤
    this._stats = stats;
  }.bind(this));
Server.prototype._sendStats = function(sockets, stats, force) {
  if(!force &&
    stats &&
    (!stats.errors || stats.errors.length === 0) &&
    stats.assets &&
    stats.assets.every(function(asset) {
      return !asset.emitted;
      //每一个asset都是没有emitted属性,表示没有发生变化。如果发生变化那么这个assets肯定有emitted属性。所以emitted属性表示是否又重新生成了一遍assets资源
    })
  )
    return this.sockWrite(sockets, "still-ok");
  this.sockWrite(sockets, "hash", stats.hash);
  //正常情况下首先发送hash,然后发送ok
  if(stats.errors.length > 0)
    this.sockWrite(sockets, "errors", stats.errors);
  else if(stats.warnings.length > 0)
    this.sockWrite(sockets, "warnings", stats.warnings);
  else
  //发送hash后再发送ok
    this.sockWrite(sockets, "ok");
}

6.获取stats中所有的modules

获取compilation所有的modules:

compilation.getStats().toJson().modules

modules内部结构如下:

 { id: 10,
   identifier: ‘C:\\Users\\Administrator\\Desktop\\webpack-chunkfilename\\node_
odules\\html-loader\\index.js!C:\\Users\\Administrator\\Desktop\\webpack-chunkf
lename\\src\\Components\\Header.html‘,
   name: ‘./src/Components/Header.html‘,//模块名称,已经转化为相对于根目录的路径
   index: 10,
   index2: 8,
   size: 62,
   cacheable: true,//缓存
   built: true,
   optional: false,
   prefetched: false,
   chunks: [ 0 ],//在那个chunk中出现
   assets: [],
   issuer: ‘C:\\Users\\Administrator\\Desktop\\webpack-chunkfilename\\node_modu
es\\eslint-loader\\index.js!C:\\Users\\Administrator\\Desktop\\webpack-chunkfil
name\\src\\Components\\Header.js‘,//是谁开始本模块的调用的,即模块调用发起者
   issuerId: 1,//发起者id
   issuerName: ‘./src/Components/Header.js‘,//发起者相对于根目录的路径
   profile: undefined,
   failed: false,
   errors: 0,
   warnings: 0,
   reasons: [ [Object] ],
   usedExports: [ ‘default‘ ],
   providedExports: null,
   depth: 2,
   source: ‘module.exports = "<header class=\\"header\\">{{text}}</header>";‘ }//source是模块内容

7.如何对输出的assets资源进行过滤

下面给出一个例子1:

 var assets = {
    // The public path
    publicPath: publicPath,
    // Will contain all js & css files by chunk
    chunks: {},
    // Will contain all js files
    js: [],
    // Will contain all css files
    css: [],
    // Will contain the html5 appcache manifest files if it exists
    //这里是application cache文件,这里不是文件内容是文件的名称。key就是文件名称
    manifest: Object.keys(compilation.assets).filter(function (assetFile) {
      return path.extname(assetFile) === ‘.appcache‘;
    })[0]
  };

例子2:过滤出所有的css文件

 var chunkFiles = [].concat(chunk.files).map(function (chunkFile) {
      return publicPath + chunkFile;
    });
    var css = chunkFiles.filter(function (chunkFile) {
      // Some chunks may contain content hash in their names, for ex. ‘main.css?1e7cac4e4d8b52fd5ccd2541146ef03f‘.
      // We must proper handle such cases, so we use regexp testing here
      return /.css($|\?)/.test(chunkFile);
    });

当然过滤出来的资源可能会要添加hash,我们看看如何处理:

/**
 * Appends a cache busting hash
 self.appendHash(assets.manifest, webpackStatsJson.hash);
 为文件名称后面添加一个hash值用于缓存,是在文件的路径上而不是内容
 */
 var webpackStatsJson = compilation.getStats().toJson();
 if (this.options.hash) {
    assets.manifest = self.appendHash(assets.manifest, webpackStatsJson.hash);
    assets.favicon = self.appendHash(assets.favicon, webpackStatsJson.hash);
  }
HtmlWebpackPlugin.prototype.appendHash = function (url, hash) {
  if (!url) {
    return url;
  }
  return url + (url.indexOf(‘?‘) === -1 ? ‘?‘ : ‘&‘) + hash;
};

8.如何对输出的资源路径进行特别的处理

HtmlWebpackPlugin.prototype.htmlWebpackPluginAssets = function (compilation, chunks) {
  var self = this;
  var webpackStatsJson = compilation.getStats().toJson();
  //获取compilation的所有的信息
  // Use the configured public path or build a relative path
  var publicPath = typeof compilation.options.output.publicPath !== ‘undefined‘
    // If a hard coded public path exists use it
    ? compilation.mainTemplate.getPublicPath({hash: webpackStatsJson.hash})
    // If no public path was set get a relative url path
    // 这个publicPath是可以使用hash的
    : path.relative(path.resolve(compilation.options.output.path, path.dirname(self.childCompilationOutputName)), compilation.options.output.path)
      .split(path.sep).join(‘/‘);
    //self.childCompilationOutputName得到的"index.html",dirname得到的是".",所以resolve结果为" C:\Users\Administrator\Desktop\webpack-chunkfilename\builds"
    if (publicPath.length && publicPath.substr(-1, 1) !== ‘/‘) {
      publicPath += ‘/‘;
    }
    //获取倒数第一个字符,添加一个"/"

  var assets = {
    // The public path
    publicPath: publicPath,
    // Will contain all js & css files by chunk
    chunks: {},
    // Will contain all js files
    js: [],
    // Will contain all css files
    css: [],
    // Will contain the html5 appcache manifest files if it exists
    //这里是application cache文件,这里不是文件内容是文件的名称
    manifest: Object.keys(compilation.assets).filter(function (assetFile) {
      return path.extname(assetFile) === ‘.appcache‘;
    })[0]
  };

  // Append a hash for cache busting(缓存清除)
  //hash: true | false if true then append a unique webpack compilation hash to all
  // included scripts and CSS files. This is useful for cache busting.
  if (this.options.hash) {
    assets.manifest = self.appendHash(assets.manifest, webpackStatsJson.hash);
    assets.favicon = self.appendHash(assets.favicon, webpackStatsJson.hash);
  }
  for (var i = 0; i < chunks.length; i++) {
    var chunk = chunks[i];
    var chunkName = chunk.names[0];
    //为每一个chunk都在上面的这个assets对象上添加一个对象,如assets.chunks[chunkName]={}
    assets.chunks[chunkName] = {};
    // Prepend the public path to all chunk files
    //chunk.files表示该chunk产生的所有的文件,不过是文件名称name而不是内容
    var chunkFiles = [].concat(chunk.files).map(function (chunkFile) {
      return publicPath + chunkFile;
    });

    // Append a hash for cache busting
    //为每一个文件加上了publicPath同时还要加上hash
    if (this.options.hash) {
      chunkFiles = chunkFiles.map(function (chunkFile) {
        return self.appendHash(chunkFile, webpackStatsJson.hash);
      });
    }

    // Webpack outputs an array for each chunk when using sourcemaps
    // But we need only the entry file
    //chunk.files[0]就是该chunk产生的入口文件
    var entry = chunkFiles[0];
    assets.chunks[chunkName].size = chunk.size;
    assets.chunks[chunkName].entry = entry;
    assets.chunks[chunkName].hash = chunk.hash;
    assets.js.push(entry);
    //为每一个该chunk产生的文件都在上面的assets对象上添加一个对象,key是chunkName
    //value为一个对象{chunkName:{size:100,entry:‘/qlin/‘,hash:‘chunk的hash‘}}
    // Gather all css files
    var css = chunkFiles.filter(function (chunkFile) {
      // Some chunks may contain content hash in their names, for ex. ‘main.css?1e7cac4e4d8b52fd5ccd2541146ef03f‘.
      // We must proper handle such cases, so we use regexp testing here
      return /.css($|\?)/.test(chunkFile);
    });
    assets.chunks[chunkName].css = css;
    //css属性就是我们的文件路径
    assets.css = assets.css.concat(css);
  }
  // Duplicate css assets can occur on occasion if more than one chunk
  // requires the same css.
  assets.css = _.uniq(assets.css);
  //如果多个chunk使用了同一个css那么会产生重复的css
  return assets;
};

上面的这个例子展示了如何如何为输出的资源做这些处理:添加publicPath以便html能够正常访问;为资源的文件名,即URL中添加编译的hash值。同时你要注意:

  var entry = chunkFiles[0];
    assets.chunks[chunkName].size = chunk.size;
    assets.chunks[chunkName].entry = entry;
    assets.chunks[chunkName].hash = chunk.hash;
    assets.js.push(entry);

之所以会如此处理是因为如果在webpack中配置了:

  devtool:‘cheap-source-map‘,

那么每一个chunk产生的files就是一个数组,如下:

[ ‘builds/vendor.bundle.js‘, ‘builds/vendor.bundle.js.map‘ ]
[ ‘builds/bundle.js‘, ‘builds/bundle.js.map‘ ]

所以我们只会保存第一个js文件而已!

9.如何判断是否要重新产生资源文件

 // If this is a hot update compilation, move on!
 // This solves a problem where an `index.html` file is generated for hot-update js files
 // It only happens in Webpack 2, where hot updates are emitted separately before the full bundle
  if (self.isHotUpdateCompilation(assets)) {
      return callback();
    }  // If the template and the assets did not change we don‘t have to emit the html
    //如果template和assets资源没有发生变化,我们不会重新产生html
    var assetJson = JSON.stringify(self.getAssetFiles(assets));
    //注意:这里包括了js,css,.appcache文件以及publicPath路径
    //isCompilationCached = compilationResult.hash && self.childCompilerHash === compilationResult.hash;
   //如果上次child compiler产生的hash和本次产生的hash(本次再次编译了一遍html)一致表示html没有变化
   //同时配置指定了可以读取html缓存,而且资源本身也没有发生变化,直接返回
    if (isCompilationCached && self.options.cache && assetJson === self.assetJson) {
      return callback();
    } else {
      self.assetJson = assetJson;
    }

HtmlWebpackPlugin.prototype.isHotUpdateCompilation = function (assets) {
  //如果每一个js的文件名,也就是入口文件都含有hot-update字段那么返回true
  return assets.js.length && assets.js.every(function (name) {
    return /\.hot-update\.js$/.test(name);
  });
};
HtmlWebpackPlugin.prototype.getAssetFiles = function (assets) {
  var files = _.uniq(Object.keys(assets).filter(function (assetType) {
    return assetType !== ‘chunks‘ && assets[assetType];
    //获取类型不是chunks的资源
  }).reduce(function (files, assetType) {
    return files.concat(assets[assetType]);
  }, []));
  files.sort();
  return files;
};

如果该html是为了达到热更新的效果,那么不用每次都重新产生html文件,这有点值得学习。同时,这里也展示了如何判断本次编译的资源和上次的资源有没有发生变化,其通过把JSON转化为字符串的方式来比较!注意:childCompilerHash表示加载了html后得到的hash值!

10.如何获取一次打包依赖的所有的文件并在所有文件中添加一个自己的文件

/*
 * Pushes the content of the given filename to the compilation assets
 */
HtmlWebpackPlugin.prototype.addFileToAssets = function (filename, compilation) {
  filename = path.resolve(compilation.compiler.context, filename);
  //获取文件的绝对路径,我们配置的是一个path
  //处理一个 promise 的 map 集合。只有有一个失败,所有的执行都结束,也就是说我们必须要同时获取到这个文件的大小和内容本身
  return Promise.props({
    size: fs.statAsync(filename),
    source: fs.readFileAsync(filename)
  })
  .catch(function () {
    return Promise.reject(new Error(‘HtmlWebpackPlugin: could not load file ‘ + filename));
  })
  .then(function (results) {
    var basename = path.basename(filename);
    //path.basename(‘/foo/bar/baz/asdf/quux.html‘)
     // Returns: ‘quux.html‘
     //获取文件名称
    compilation.fileDependencies.push(filename);
    //在compilation.fileDependencies中添加文件,filename是完整的文件路径
    compilation.assets[basename] = {
      source: function () {
        return results.source;
      },
      //source是文件的内容,通过fs.readFileAsync完成
      size: function () {
        return results.size.size;
        //size通过 fs.statAsync(filename)完成
      }
    };
    return basename;
  });
};

这里要学习的内容还是挺多的,首先把我们自己的文件添加到需要打包依赖文件集合中:

compilation.fileDependencies//在compilation.fileDependencies添加的必须是绝对路径

接下来就是修改compilation.assets对象:

compilation.assets[basename] = {
      source: function () {
        return results.source;
      },
      //source是文件的内容,通过fs.readFileAsync完成
      size: function () {
        return results.size.size;
        //size通过 fs.statAsync(filename)完成
      }
    };
    return basename;
  });

不过这里的key就是我们的文件名,而不再包含文件路径!最后一个就是题外话了,来源于我们的bluebird(Promise.prop方法):

var Promise = require(‘bluebird‘);
Promise.promisifyAll(fs);//所有fs对象的方法都promisify了,所以才有fs.statAsync(filename), fs.readFileAsync(filename),通过这两个方法就可以获取到我们的compilation.assets需要的source和size

参考资料:

webpack-dev-middleware源码分析

时间: 2024-11-08 19:07:44

有了它们就能更好的理解webpack了的相关文章

6个变态的C语言Hello World程序——更好的理解C

下面这个程序片段主要完成以下两件事情: 1)完成输出Hello World. 2)混乱C语言代码. #define _________ } #define ________ putchar #define _______ main #define _(a) ________(a); #define ______ _______(){ #define __ ______ _(0x48)_(0x65)_(0x6C)_(0x6C) #define ___ _(0x6F)_(0x2C)_(0x20)_(

java数据结构与算法之递归思维(让我们更通俗地理解递归)

[版权申明]转载请注明出处(请尊重原创,博主保留追究权) http://blog.csdn.net/javazejian/article/details/53452971 出自[zejian的博客] 关联文章: java数据结构与算法之顺序表与链表设计与实现分析 java数据结构与算法之双链表设计与实现 java数据结构与算法之改良顺序表与双链表类似ArrayList和LinkedList(带Iterator迭代器与fast-fail机制) java数据结构与算法之栈(Stack)设计与实现 j

6个变态的C语言Hello World程序——更好的理解C(2、3)

接上一篇文章,6个变态的C语言Hello World程序--更好的理解C,这篇文章给大家带来变态的Hello World程序2.3 hello2.c #include<stdio.h> main(){ int x=0,y[14],*z=&y;*(z++)=0x48;*(z++)=y[x++]+0x1D; *(z++)=y[x++]+0x07;*(z++)=y[x++]+0x00;*(z++)=y[x++]+0x03; *(z++)=y[x++]-0x43;*(z++)=y[x++]-0

用隐喻来更充分地理解软件开发

隐喻是启示而不是算法.因此它们往往有一点随意(sloppy). 隐喻把软件开发过程与其他你熟悉的活动联系在一起,帮助你更好地理解. 有些隐喻比其他一些隐喻更贴切. 通过把软件的构建过程比作是房屋的建设过程,我们可以发现,仔细的准备是必要的,而大型项目和小型项目之间也是有差异的. 通过把软件开发中的实践比作是智慧工具箱中的工具,我们又发现,每位程序员都有许多工具,但并不存在任何一个能适用于所有工作的工具,因地制宜地选择正确工具是成为能有效编程的程序员的关键. 不同的隐喻彼此并不排斥,应当使用对你最

《代码大全》阅读笔记-2-用隐喻来更充分地理解软件开发

隐喻的价值绝不应该被低估.隐喻的有点在于其预期的效果:能被所有的人理解.不必要的沟通和误解也因此大为降低,学习与教授更为快速.实际上,隐喻是对概念进行内在化和抽象的一种途径,它让人在更高的层面上思考问题,从而避免低层次的错误. 隐喻是启示而不是算法.因此他们往往有一点随意 隐喻把软件开发过程与其他你熟悉的活动联系在一起,帮助你更好地理解 有些隐喻比其他一些隐喻更贴切 通过把软件的构建过程比作是房屋的建设过程,我们可以发现,仔细的准备是必要的,而大型项目和小型项目之间也是有差异的 通过把软件开发中

使用IIS建立自己的网站、使用C#编写IIS模拟器,更好的理解Client和Server的relation

如何在IIS服务器上搭建自己的网站呢,今天带着这问题进行简单的实践一下,并且准备模拟一下IIS服务器工作方式,把这个工作方式搞清楚有利于发展. 1.首先应该进入控制面板=>程序=>添加或删除程序=>找到IIS 全部打钩. 2. 2.首先要自己建立一个网页.进行模拟. 3.然后在打开的IIS服务器,点击右键进行建立网页. 4.然后添加各种配置,如图: 5.填写必须的参数如图: 6.点击OK,点击浏览,如果端口是80端口.不会弹出你所希望看到的窗口. 7.所以我们要进行简单的调试. 8.点击

理清javascript中prototype、__proto__、Object、Function的关系,更好地理解原型继承

本文参考了http://www.blogjava.net/heavensay/archive/2013/10/20/405440.html这篇文章,对其内容作了个简单总结,形成了几条简单的结论,让读者更容易记住prototype.__proto__.Object.Function之间的关系. 结论1:Object.prototype只是一个普通对象,它是js原型链的最顶端. (typeof Object.prototype) === object;//true Object.prototype.

更博不能忘——webpack学习笔记

webpack是前端构建系统就像grunt和gulp(之前有学习过grunt所以也就大概明白webpack是个什么东西),所以说前端技术大部分还真是相通的,现在觉得当时多看的东西并不白费,虽然长时间不用会忘掉一丢丢,但是看过脑海中还是有印象的. webpack能够用作模块加载和打包类似Browserify,且能做更多.类似上诉模块管理工具都会有一个相应的配置文件,用于说明,你打包的文件,包装的模块等. webpack常用命令: webpack -p 压缩混淆脚本 webpack --watch

更好的理解java多线程

1.线程的创建 之前知道Java中一个多线程的创建方法是继承Thread类或者实现Runable接口,但是看不懂下面这种创建线程的方法 第一种 [java] view plain copy print? new Thread(new Runnable() { @Override public void run() { } } }).start();//这种方式中new Thread()是创建了一个线程,而new Runable()对象中是线程想要执行的代码,这样把想要执行的代码放到一个创建的对象