在内存中编译Webpack,但parsing为磁盘上的node_modules

我正在尝试使用networking包编译一个有效的javascript代码的内存string。 我在这里使用内存fs: https : //webpack.github.io/docs/node.js-api.html#compile-to-memory 。

所以我采取了一个string包含原始的JavaScript,将其写入内存FS,然后networking包parsing到该入口点。 但编译在第一个require语句上失败,大概是因为它无法查看node_modules的实际fs。

任何想法我怎么能做到这一点?

import webpack from 'webpack'; import MemoryFS from 'memory-fs'; import thenify from 'thenify'; function* compile(code) { const fs = new MemoryFS(); fs.writeFileSync('/file.js', code); const compiler = webpack({ entry: { file: '/file.js' }, output: { path: '/build', filename: '[name].js' }, module: { loaders: [ { test: /\.json$/, loader: 'json' } ], } }); compiler.run = thenify(compiler.run); compiler.inputFileSystem = fs; compiler.resolvers.normal.fileSystem = fs; //this is needed for memfs compiler.outputFileSystem = fs; const stats = yield compiler.run(); //retrieve the output of the compilation const res = stats.compilation.assets['file.js'].source(); return res; } 

用法

 var code = "var _ = require('underscore'); console.log(_);"; var bundle = yield compile(code); //should be a bundle containing the underscore source. 

错误是

ModuleNotFoundError:找不到模块:错误:无法parsing模块下划线/

这个问题表明其他人也尝试过同样的事情: https : //github.com/webpack/webpack/issues/1562 。 有一个引用https://gist.github.com/DatenMetzgerX/2a96ebf287b4311f4c18 ,我相信是打算做我想做的事情,但在目前的forms,我不知道如何。 它将MemoryFs的一个实例分配给所有的parsing器。 我试过分配节点的FS模块,但没有骰子。

所以总之,我试图设置一个入口点的内存string的原始JavaScript,但仍然有要求和导入语句parsing到磁盘上的node_modules。

UPDATE

我已经能够得到我正在寻找的结果,但它不漂亮。 我基本上覆盖MemoryFS中的#stat和#readFile的实现来检查真正的文件系统,如果它得到任何内存中不存在的文件的请求。 我可以通过子类化MemoryFS而不是在运行时交换方法实现来清除这个问题,但是这个想法仍然是一样的。

工作解决scheme

 import webpack from 'webpack'; import JsonLoader from 'json-loader'; import MemoryFS from 'memory-fs'; import UglifyJS from "uglify-js"; import thenify from 'thenify'; import path from 'path'; import fs from 'fs'; import root from 'app-root-path'; /* * Provide webpack with an instance of MemoryFS for * in-memory compilation. We're currently overriding * #stat and #readFile. Webpack will ask MemoryFS for the * entry file, which it will find successfully. However, * all dependencies are on the real filesystem, so any require * or import statements will fail. When that happens, our wrapper * functions will then check fs for the requested file. */ const memFs = new MemoryFS(); const statOrig = memFs.stat.bind(memFs); const readFileOrig = memFs.readFile.bind(memFs); memFs.stat = function (_path, cb) { statOrig(_path, function(err, result) { if (err) { return fs.stat(_path, cb); } else { return cb(err, result); } }); }; memFs.readFile = function (path, cb) { readFileOrig(path, function (err, result) { if (err) { return fs.readFile(path, cb); } else { return cb(err, result); } }); }; export default function* compile(code) { // Setup webpack //create a directory structure in MemoryFS that matches //the real filesystem const rootDir = root.toString(); //write code snippet to memoryfs const outputName = `file.js`; const entry = path.join(rootDir, outputName); const rootExists = memFs.existsSync(rootDir); if (!rootExists) { memFs.mkdirpSync(rootDir); } memFs.writeFileSync(entry, code); //point webpack to memoryfs for the entry file const compiler = webpack({ entry: entry, output: { filename: outputName }, module: { loaders: [ { test: /\.json$/, loader: 'json' } ] } }); compiler.run = thenify(compiler.run); //direct webpack to use memoryfs for file input compiler.inputFileSystem = memFs; compiler.resolvers.normal.fileSystem = memFs; //direct webpack to output to memoryfs rather than to disk compiler.outputFileSystem = memFs; const stats = yield compiler.run(); //remove entry from memory. we're done with it memFs.unlinkSync(entry); const errors = stats.compilation.errors; if (errors && errors.length > 0) { //if there are errors, throw the first one throw errors[0]; } //retrieve the output of the compilation const res = stats.compilation.assets[outputName].source(); return res; } 

用法

 var code = "var _ = require('underscore'); console.log(_);"; var bundle = yield compile(code); //is a valid js bundle containing the underscore source and a log statement logging _. 

如果没有更好的方法,那么我肯定会把它封装到MemoryFS的一个子类中,但是我希望用Webpack的api来实现这一点更为合理。

我已经创build了这个片段未经testing。 我想你想要inputFS是真实的,输出fs是在内存之一。 另一方面,你想要分开构造file.js的所有依赖关系。 为此,我想到了webpack.optimize.CommonsChunkPlugin插件可以提供帮助。 我期望webpack将所有内容写入内存。 我希望它的作品。

 import webpack from 'webpack'; import MemoryFS from 'memory-fs'; import thenify from 'thenify'; import realFS from 'fs'; function* compile(code) { const fs = new MemoryFS(); const compiler = webpack({ entry: { file: '/file.js', vendor: [ 'underscore', 'other-package-name' ] }, output: { path: '/build', filename: '[name].js' }, module: { loaders: [ { test: /\.json$/, loader: 'json' } ], }, plugins: [ new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js') ] }); compiler.run = thenify(compiler.run); compiler.inputFileSystem = realFS; compiler.resolvers.normal.fileSystem = fs; //this is needed for memfs compiler.outputFileSystem = fs; const stats = yield compiler.run(); //retrieve the output of the compilation const res = stats.compilation.assets['file.js'].source(); return res; } 

您正在使用MemoryFS ,这是通常由操作系统处理的function的JavaScript重新实现。 我想知道,你可以在操作系统级别使用tmpfs挂载一个目录,然后使用它吗? 然后webpack将不知道或在意input文件实际上存储在内存中。

假设你已经在/ media / memory上挂载了一个基于内存的文件系统, webpack的configuration代码可以这么简单:

 resolve: { root: ['/media/memory', ...other paths...], }, output: { path: '/wherever/you/want/the/output/files' } } 

这种方法也有一个隐藏的好处:如果你想debugginginput代码,你只需要在非基于RAM的文件系统上挂载/ media / memory ,你就可以看到正在生成的东西。

unionfs / memfs / linkfs的组合应该有所帮助,而不是内存-fs。