欢迎光临
我们一直在努力

webpackloader生成虚拟文件的方案

此文已由作者张磊授权网易云社区发布。

使用 webpack 的时候,难免需要写一些 loader,接着就会遇到一个很纠结的问题。该 loader 会生成一个文件,一般这个文件的生成时机都是在 loader 处理所有的文件后。一般有两种处理方案。一种是写一个 plugin,监听对应的事件;一种是生成一个临时文件,将每次读到的内容都写在 临时文件 中。第一种在使用的时候也很麻烦,需要同时在 loader 和 plugin 加一下对应的逻辑。第二种,写入临时文件的这个过程很是让人纠结。很明显,两种方案对于有一定洁癖的人来说,都不优雅,那么就来寻找一种方案,既不需要写 plugin,又不需要写入 临时文件 中。

解决方案

在 github 上找到一个可用解决方案的 loader,这个 loader 看起来是关于虚拟文件生成的,使用很简单,指定名字,指定内容,生成一个虚拟文件,研究了一下,对解决问题很有帮助。关键代码如下:

// index.jsimport * as fsPatch from './fs-patch';// 省略...fsPatch.add( this.fs, {    path:    file,    content: src });// 省略...

这个文件传入 loader.fs,看起来是对 fs 打补丁,接着再来看 fs-patch.js

// fs-patch.jsimport path from 'path';const NS   = __filename; export function patch( fs ) {    if ( fs[ NS ] )        return;    const virtualFS = {         files: {},         add( options ) {            const file = path.resolve( options.path );             virtualFS.files[ file ] = {                 path:    file,                 content: options.content             };         }     };     fs[ NS ] = virtualFS;     createPatchFn( fs, 'readFile', function( orig, args, file, encoding, cb ) {        var rfile = path.resolve( file );        var vfile = virtualFS.files[ rfile ];        if ( vfile ) {            if ( typeof(encoding) === 'function' ) {                 cb       = encoding;                 encoding = null;             }            var content = vfile.content;            if ( encoding != null )                 content = content.toString( encoding );             cb( null, content )            return;         }        return orig.apply( this, args );     });     createPatchFn( fs, 'readFileSync', function( orig, args, file, encoding ) {        var rfile = path.resolve( file );        var vfile = virtualFS.files[ rfile ];        if ( vfile ) {            var content = vfile.content;            if ( encoding != null )                 content = content.toString( encoding );            return content;         }        return orig.apply( this, args );     });     createPatchFn( fs, 'stat', function( orig, args, p, cb ) {        var rp = path.resolve( p );        var vfile = virtualFS.files[ rp ];        if ( vfile ) {            var vstat = {                 dev: 8675309,                 nlink: 1,                 uid: 501,                 gid: 20,                 rdev: 0,                 blksize: 4096,                 ino: 44700000,                 mode: 33188,                 size: vfile.content.length,                  isFile() { return true; },                 isDirectory() { return false; },                 isBlockDevice() { return false; },                 isCharacterDevice() { return false; },                 isSymbolicLink() { return false; },                 isFIFO() { return false; },                 isSocket() { return false; },             };             cb( null, vstat );            return;         }        return orig.apply( this, args );     });     createPatchFn( fs, 'statSync', function( orig, args, p ) {        var rp = path.resolve( p );        var vfile = virtualFS.files[ rp ];        if ( vfile ) {            var vstat = {                 dev: 8675309,                 nlink: 1,                 uid: 501,                 gid: 20,                 rdev: 0,                 blksize: 4096,                 ino: 44700000,                 mode: 33188,                 size: vfile.content.length,                  isFile() { return true; },                 isDirectory() { return false; },                 isBlockDevice() { return false; },                 isCharacterDevice() { return false; },                 isSymbolicLink() { return false; },                 isFIFO() { return false; },                 isSocket() { return false; },             };            return vstat;         }        return orig.apply( this, args );     }); }; export function add( fs, options ) {     patch( fs );     fs[ NS ].add( options ); }function createPatchFn( obj, name, fn ) {    const origin  = obj[ name ];     obj[ name ] = function() {        const args = Array.prototype.slice.call( arguments );        return fn.apply( this, [origin, args].concat( args ) );     }; }

代码分析

可以看到 fs-patch.js 直接劫持了 loader.fs,重写了 fs 的一些方法,而重写的这些方法就是生成虚拟文件的关键。劫持后的 fs 在访问这些方法的时候,首先去从缓存中获取路径对应的内容,不存在则再从硬盘中读取。

优缺点

优点是不需要生成临时文件或者另写一个 plugin,缺点在文件比较大或者计算比较频繁,对机器的要求会比较高。

 

  • 海报
海报图正在生成中...
赞(0) 打赏
声明:
1、本博客不从事任何主机及服务器租赁业务,不参与任何交易,也绝非中介。博客内容仅记录博主个人感兴趣的服务器测评结果及一些服务器相关的优惠活动,信息均摘自网络或来自服务商主动提供;所以对本博客提及的内容不作直接、间接、法定、约定的保证,博客内容也不具备任何参考价值及引导作用,访问者需自行甄别。
2、访问本博客请务必遵守有关互联网的相关法律、规定与规则;不能利用本博客所提及的内容从事任何违法、违规操作;否则造成的一切后果由访问者自行承担。
3、未成年人及不能独立承担法律责任的个人及群体请勿访问本博客。
4、一旦您访问本博客,即表示您已经知晓并接受了以上声明通告。
文章名称:《webpackloader生成虚拟文件的方案》
文章链接:https://www.456zj.com/21037.html
本站资源仅供个人学习交流,请于下载后24小时内删除,不允许用于商业用途,否则法律问题自行承担。

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址