Próbuję użyć pakietu internetowego do skompilowania łańcucha w pamięci z poprawnym kodem JavaScript. Używam pamięci fs, jak tutaj: https://webpack.github.io/docs/node.js-api.html#compile-to-memory.Kompilowanie pakietu Web Pack w pamięci, ale rozwiązywanie problemu dla node_modules na dysku
Tak więc biorę ciąg zawierający javascript, zapisując go w pamięci fs, a następnie pakiet internetowy rozwiązuje ten punkt wejścia. Ale kompilacja kończy się niepowodzeniem na pierwszym wymagającym oświadczeniu, prawdopodobnie dlatego, że nie jest w stanie zajrzeć do prawdziwego fs dla node_modules.
Jakieś pomysły, jak mogę to osiągnąć?
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;
}
Wykorzystanie
var code = "var _ = require('underscore'); console.log(_);";
var bundle = yield compile(code); //should be a bundle containing the underscore source.
Błąd znajduje
ModuleNotFoundError: Module not found: Error: Cannot resolve module underscore in /
To pytanie wskazuje, że inni próbowali to samo: https://github.com/webpack/webpack/issues/1562. istnieje sedno, o którym mowa w https://gist.github.com/DatenMetzgerX/2a96ebf287b4311f4c18, które moim zdaniem miało na celu zrobienie tego, co mam nadzieję osiągnąć, ale w jego obecnej formie nie widzę sposobu. Przypisuje instancję MemoryFs wszystkim programom rozpoznawania nazw. Próbowałem już przypisać moduł fs węzła, ale nie ma kości.
Krótko mówiąc, próbuję ustawić punkt wejścia na ciąg w pamięci surowego javascriptu, ale nadal mam instrukcje wymagające i importowane rozwiązane na node_modules na dysku.
UPDATE
byłem w stanie uzyskać wynik szukam, ale nie całkiem. Zasadniczo nadpisuję implementację #stat i #readFile w MemoryFS , aby sprawdzić prawdziwy system plików, jeśli otrzyma żądanie dla pliku, który nie istnieje w pamięci. Mogłem to trochę posprzątać, podklasując MemoryFS zamiast zamieniać implementacje metod w środowisku wykonawczym, ale pomysł byłby taki sam.
Roztwór roboczy
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;
}
Wykorzystanie
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 _.
Jeśli nie jest to lepszy sposób, to ja zdecydowanie hermetyzacji to pod podklasa MemoryFS, ale mam nadzieję, jest bardziej logiczny sposób na osiągnięcie tego przy pomocy api aplikacji Webpack.
można pokazać bardziej kompletny kod, łącznie swoimi 'require' stwierdzeniami? – jonaz
@jonaz Zaktualizowałem oryginalny fragment kodu i dodałem nową wersję, dzięki której mogłem pracować. Mając nadzieję, że wymyślę lepszy sposób. – mike
Czy możesz podać więcej informacji o wymaganiach dotyczących pochodzenia? Brzmi jak chcesz dynamicznego punktu wejścia? –