有没有办法在 browserify 中使用 fs 同步功能?

Is there a way to use fs sync functions with browserify?

我已经尝试了 brfs 转换,但我收到以下错误消息:

08 03 2016 16:50:14.894:ERROR [framework.browserify]: bundle error
08 03 2016 16:50:14.894:ERROR [framework.browserify]: Error: tried to statically call { readFile: [Function: readFile], readFileSync: [Function: readFileSync], readdir: [Function: readdir], readdirSync: [Function: readdirSync] } as a function while parsing file
...
PhantomJS 1.9.8 (Windows 7 0.0.0) ERROR
  You need to include some adapter that implements __karma__.start method!

当我尝试在我的代码中使用 var fs = require("fs"); console.log(fs.readFileSync) 时。有没有办法在 browserify 中使用同步 fs 功能?

我想处理一些非 js 文件,这些文件由 karma 提供但未包含且未由 browserify 预处理。所以我需要的是 glob 和阅读。还有其他想法如何处理这些文件吗?理想的解决方案是使用 nodejs 来完成,但我不确定如何使用 karma 将数据从 nodejs 发送到浏览器。

我没能使 brfs 工作。我创建了一个简单的 fs shim,它支持以下功能:

  • existsSync(path) -> true/false
  • readdirSync(path) -> basename[]
  • statSync(path) -> {isDirectory}
  • readFileSync(path,"utf8") -> string

使用了path-browserify,所以在非browserify环境下使用需要更换require("path")依赖。请注意,此 fs shim 使用 window.__karma__.files 来构建目录和文件树,因此如果没有 Karma,它将无法工作。如果您能够从 browserify 收集文件路径,则可以使用相同的逻辑。我猜你需要为此编写一个 browserify 插件。

module.exports = (function () {

    var path = require("path");

    function absolutePath(relativePath) {
        return path.resolve(path.normalize(relativePath.split("\").join("/")));
    }

    var KarmaFileSystem = function () {
        this.registry = new KarmaPathRegistry();
        this.converter = new KarmaUriPathConverter("/base/", "/");
        this.reader = new KarmaFileReader(this.converter);

        var servedUris = Object.keys(window.__karma__.files);
        var servedFiles = this.converter.parseUris(servedUris);
        servedFiles.forEach(this.registry.addFile, this.registry);
    };
    KarmaFileSystem.prototype = {
        constructor: KarmaFileSystem,
        workingDirectory: "/",
        existsSync: function (path) {
            return this.registry.exists(path);
        },
        readdirSync: function (path) {
            return this.registry.getContent(path);
        },
        statSync: function (path) {
            return {
                isDirectory: function () {
                    return this.registry.isDirectory(path);
                }.bind(this)
            };
        },
        readFileSync: function (file, encoding) {
            if (encoding !== "utf8")
                throw new Error("This fs.readFileSync() shim does not support other than utf8 encoding.");
            if (!this.registry.isFile(file))
                throw new Error("File does not exist: " + file);
            return this.reader.readFile(file);
        }
    };

    var KarmaPathRegistry = function KarmaPathRegistry() {
        this.paths = {};
    };

    KarmaPathRegistry.prototype = {
        constructor: KarmaPathRegistry,
        addFile: function (file) {
            file = absolutePath(file);
            this.paths[file] = KarmaPathRegistry.TYPE_FILE;
            var parentDirectory = path.dirname(file);
            this.addDirectory(parentDirectory);
        },
        addDirectory: function (directory) {
            directory = absolutePath(directory);
            this.paths[directory] = KarmaPathRegistry.TYPE_DIRECTORY;
            var parentDirectory = path.dirname(directory);
            if (parentDirectory != directory)
                this.addDirectory(parentDirectory);
        },
        isFile: function (file) {
            file = absolutePath(file);
            return this.exists(file) && this.paths[file] === KarmaPathRegistry.TYPE_FILE;
        },
        isDirectory: function (directory) {
            directory = absolutePath(directory);
            return this.exists(directory) && this.paths[directory] === KarmaPathRegistry.TYPE_DIRECTORY;
        },
        exists: function (node) {
            node = absolutePath(node);
            return this.paths.hasOwnProperty(node);
        },
        getContent: function (directory) {
            if (!this.isDirectory(directory))
                throw new Error("Not a directory: " + directory);
            directory = absolutePath(directory);
            return Object.keys(this.paths).filter(function (node) {
                if (node === directory)
                    return false;
                var parentDirectory = path.dirname(node);
                return parentDirectory === directory;
            }, this).map(function (node) {
                return path.basename(node);
            });
        }
    };

    KarmaPathRegistry.TYPE_FILE = 0;
    KarmaPathRegistry.TYPE_DIRECTORY = 1;

    var KarmaUriPathConverter = function KarmaUriPathConverter(baseUri, workingDirectory) {
        this.workingDirectory = workingDirectory;
        this.workingDirectoryPattern = this.patternFromBase(workingDirectory);
        this.baseUri = baseUri;
        this.baseUriPattern = this.patternFromBase(baseUri);
    };

    KarmaUriPathConverter.prototype = {
        constructor: KarmaUriPathConverter,
        patternFromBase: function (string, flags) {
            var pattern = "^" + string.replace(/[-\/\^$*+?.()|[\]{}]/g, '\$&');
            return new RegExp(pattern, flags);
        },
        parseUris: function (uris) {
            return uris.filter(function (uri) {
                return this.baseUriPattern.test(uri)
            }, this).map(function (uri) {
                return uri.replace(this.baseUriPattern, this.workingDirectory);
            }, this);
        },
        buildUri: function (file) {
            file = absolutePath(file);
            if (!this.workingDirectoryPattern.test(file))
                throw new Error("Path is not in working directory: " + file);
            return file.replace(this.workingDirectoryPattern, this.baseUri);
        }
    };

    var KarmaFileReader = function KarmaFileReader(converter) {
        this.converter = converter;
    };

    KarmaFileReader.prototype = {
        constructor: KarmaFileReader,
        readFile: function (file) {
            var uri = this.converter.buildUri(file);
            var xhr = new XMLHttpRequest();
            xhr.open("get", uri, false);
            xhr.send();
            return xhr.responseText;
        }
    };

    return new KarmaFileSystem();
})();