zoukankan      html  css  js  c++  java
  • webpack loader 生成虚拟文件的方案

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

    欢迎访问网易云社区,了解更多网易技术产品运营经验。

    前言

    使用 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,缺点在文件比较大或者计算比较频繁,对机器的要求会比较高。


    免费体验云安全(易盾)内容安全、验证码等服务

    更多网易技术、产品、运营经验分享请点击

     



    相关文章:
    【推荐】 什么是高防服务器?

  • 相关阅读:
    centos7配置vsftpd
    vsftpd上传文件出现553 Could not create file错误解决方法
    mysql表引擎myisam改为innodb
    python字符串
    linux虚拟机设置本地yum源
    python3读取excel数据
    expect远程登录服务器并执行命令
    sed中支持变量的处理方法
    test
    test
  • 原文地址:https://www.cnblogs.com/163yun/p/9914213.html
Copyright © 2011-2022 走看看