Я пытаюсь использовать веб-пакет для компиляции строки в строке действительного кода javascript. Я использую память fs, как описано здесь: https://webpack.github.io/docs/node.js-api.html#compile-to-memory.
Итак, я беру строку, содержащую необработанный javascript, записывая это в память fs, а затем веб-пакет разрешает эту точку входа. Но компиляция терпит неудачу в первом требовании оператора, по-видимому, потому, что она не может смотреть в реальном fs для node_modules.
Любые идеи о том, как я могу это сделать?
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: модуль не найден: ошибка: невозможно разрешить модуль подчеркивание в /
Этот вопрос указывает, что другие пробовали одно и то же: https://github.com/webpack/webpack/issues/1562. есть ссылка на https://gist.github.com/DatenMetzgerX/2a96ebf287b4311f4c18, которая, как я полагаю, была предназначена для того, чтобы делать то, что я надеюсь сделать, но в этом текущем виде я не вижу, как это сделать. Он назначает экземпляр MemoryFs всем резольверам. Я попытался назначить модуль node fs, но не кубик.
Короче говоря, я пытаюсь установить точку входа в строку памяти необработанного javascript, но все еще есть запросы на импорт и импорт, разрешенные на node_modules на диске.
UPDATE
Мне удалось получить результат, который я ищу, но это не очень. Я в основном переопределяю реализацию #stat и #readFile в MemoryFS чтобы проверить реальную файловую систему, если он получает какой-либо запрос на файл, который не существует в памяти. Я мог бы немного почистить это путем подклассификации MemoryFS вместо замены методов реализации во время выполнения, но идея все равно будет такой же.
Рабочее решение
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.