2016-08-05 19 views
27

Tôi đang cố gắng sử dụng gói web để biên dịch một chuỗi bộ nhớ của mã javascript hợp lệ. Tôi đang sử dụng bộ nhớ fs như được nêu ở đây: https://webpack.github.io/docs/node.js-api.html#compile-to-memory.Biên dịch Webpack trong bộ nhớ nhưng phân giải thành node_modules trên đĩa

Vì vậy, tôi đang dùng một chuỗi chứa javascript thô, viết nó vào bộ nhớ fs và sau đó gói web phân giải tới điểm nhập đó. Nhưng trình biên dịch không thành công trên câu lệnh require đầu tiên, có lẽ vì nó không thể nhìn vào fs thực cho node_modules.

Bất kỳ ý tưởng nào về cách tôi có thể thực hiện việc này?

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

Cách sử dụng

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

Lỗi này là

ModuleNotFoundError: Module not found: Error: Cannot resolve module underscore in /

Câu hỏi này chỉ ra rằng những người khác đã cố gắng điều tương tự: https://github.com/webpack/webpack/issues/1562. có một ý chính được tham chiếu tại số https://gist.github.com/DatenMetzgerX/2a96ebf287b4311f4c18 mà tôi tin là có ý định làm những gì tôi hy vọng đạt được, nhưng ở dạng hiện tại tôi không thấy như thế nào. Nó gán một thể hiện của MemoryFs cho tất cả các trình phân giải. Tôi đã thử gán module fs của nút, nhưng không có con xúc xắc.

Vì vậy, trong ngắn hạn, tôi đang cố gắng thiết lập một điểm vào một chuỗi bộ nhớ của javascript thô, nhưng vẫn yêu cầu và nhập khẩu các câu lệnh được giải quyết cho node_modules trên đĩa.

CẬP NHẬT

tôi đã có thể để có được những kết quả Tôi đang tìm nhưng nó không đẹp. Tôi về cơ bản sẽ ghi đè việc triển khai #stat và #readFile trong MemoryFS để kiểm tra hệ thống tệp thực nếu nó nhận được bất kỳ yêu cầu nào đối với tệp không tồn tại trong bộ nhớ. Tôi có thể làm sạch điều này một chút bằng cách phân lớp MemoryFS thay vì hoán đổi phương thức triển khai thực hiện trong thời gian chạy, nhưng ý tưởng sẽ vẫn như cũ.

giải pháp làm việc

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

Cách sử dụng

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 _. 

Nếu có không phải là một cách tốt hơn, sau đó tôi chắc chắn sẽ tóm lược này thành một lớp con của MemoryFS, nhưng tôi hy vọng có một cách lành mạnh hơn để thực hiện điều này với api của Webpack.

+2

Bạn có thể hiển thị mã hoàn thiện hơn, bao gồm cả 'báo cáo require' của bạn? – jonaz

+0

@jonaz Tôi đã cập nhật đoạn mã gốc và cũng đã thêm một phiên bản mới mà tôi đã có thể làm việc. Hy vọng đến với một cách tốt hơn mặc dù. – mike

+0

Bạn có thể nêu rõ thêm thông tin về yêu cầu xuất xứ không? Có vẻ như bạn muốn có một điểm vào động? –

Trả lời

1

Tôi đã tạo đoạn mã này chưa được kiểm tra. Tôi nghĩ rằng bạn muốn inputFS là một thực tế và fs đầu ra được trong bộ nhớ một. Mặt khác, bạn muốn tất cả các phụ thuộc của file.js được xây dựng riêng biệt. Vì vậy, tôi đã tìm ra plugin webpack.optimize.CommonsChunkPlugin có thể trợ giúp. Tôi mong đợi webpack để viết tất cả mọi thứ vào bộ nhớ. Tôi hy vọng nó hoạt động.

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

Bạn đang sử dụng MemoryFS, mà là một reimplementation JavaScript của một tính năng thường xử lý bởi hệ điều hành. Tôi tự hỏi, bạn có thể gắn một thư mục bằng cách sử dụng tmpfs ở cấp Hệ điều hành, sau đó sử dụng không? webpack sau đó sẽ không biết hoặc quan tâm rằng tệp đầu vào thực sự được lưu trữ trong bộ nhớ.

Giả sử rằng bạn đã gắn một hệ thống tập tin dựa trên bộ nhớ tại /media/bộ nhớ, mã cấu hình webpack có thể đơn giản như thế này:

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

Cách tiếp cận này cũng có một lợi ích ẩn: Nếu bạn muốn gỡ lỗi mã đầu vào, bạn chỉ cần gắn /media/memory với hệ thống tệp không dựa trên RAM và bạn có thể xem những gì đang được tạo.

Các vấn đề liên quan