2016-08-05 13 views
27

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.

+2

można pokazać bardziej kompletny kod, łącznie swoimi 'require' stwierdzeniami? – jonaz

+0

@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

+0

Czy możesz podać więcej informacji o wymaganiach dotyczących pochodzenia? Brzmi jak chcesz dynamicznego punktu wejścia? –

Odpowiedz

1

Utworzyłem ten fragment nieprzetestowany. Myślę, że chcesz, aby inputFS był rzeczywisty, a wyjście fs miało być w pamięci. Z drugiej strony chcesz, aby wszystkie zależności pliku file.js były konstruowane osobno. Do tego doszedłem do wniosku, że wtyczka webpack.optimize.CommonsChunkPlugin może pomóc. Oczekuję, że webpack zapisze wszystko w pamięci. Mam nadzieję, że to działa.

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; 
} 
0

Używasz MemoryFS, co jest reimplementacja JavaScript z funkcji normalnie obsługiwane przez system operacyjny. Zastanawiam się, czy można zamontować katalog przy użyciu tmpfs na poziomie systemu operacyjnego, a następnie użyć? pakiet Webpack nie wiedziałby, czy plik wejściowy jest rzeczywiście przechowywany w pamięci.

Zakładając, że masz zamontowany system plików pamięci oparte na /media/pamięci, kod konfiguracyjny WebPack może być tak proste, jak to:

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

Takie podejście ma również ukryte korzyści: Jeśli chcesz debugować kod wejściowy, wystarczy zamontować /media/memory z systemem plików bez obsługi pamięci RAM, aby zobaczyć, co jest generowane.

Powiązane problemy